2013年6月7日星期五

【转】 MySQL Index详解

①MySQL Index

一、SHOW INDEX会返回以下字段

1、Table 表的名称。

2、 Non_unique 如果索引不能包括重复词,则为0,如果可以则为1。

3、 Key_name 索引的名称

4、 Seq_in_index 索引中的列序列号,从1开始。

5、 Column_name 列名称。

6、 Collation 列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类)。

7、Cardinality 索引中唯一值的数目的估计值。通过运行ANALYZE TABLE或myisamchk -a可以更新。基数根据被存储为整数的统计数据来计数,所以即使对于小型表,该值也没有必要是精确的。基数越大,当进行联合时,MySQL使用该索引的机 会就越大。

8、Sub_part 如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL。

9、 Packed 指示关键字如何被压缩。如果没有被压缩,则为NULL。

10、 Null 如果列含有NULL,则含有YES。如果没有,则该列含有NO。

11、 Index_type 用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)。

12、 Comment 多种评注,您可以使用db_name.tbl_name作为tbl_name FROM db_name语法的另一种形式。这两个语句是等价的:

mysql>SHOW INDEX FROM mytable FROM mydb;

mysql>SHOW INDEX FROM mydb.mytable;

二、使用 CREATE INDEX 创建索引

如果要为已存在的表创建索引,就需要使用 CREATE INDEX 命令或 ALTER TABLE 来创建索引。

CREATEINDEX idxtitle ON tablename (title)

这条命令将创建与 CREATE TABLE 命令相同的索引。

三、使用 ALTER TABLE 创建索引

ALTER TABLE tablename ADD INDEX idxtitle (title)

四、查看和删除索引

我们可以使用以下命令来查看已存在的索引:

SHOW INDEX FROM tablename

DROP INDEX indexname ON tablename

DROP INDEX 将删除 tablename 表上的 indexname 索引,indexname 就是我们创建表时指定的索引名。

########################################

createtable c(id char(20) not null primary key,`index` char(10));

问题1.如果我忘记把id设为主键现在该怎么办?输入什么命令?

ALTER TABLE record 

ADD PRIMARY KEY (id); 

例如:ALTER TABLE `abc` ADD PRIMARY KEY(`a`); 

问题2.如果我想把id设为主键,同时想把name改为not null,且改为varchar(10),能不能用一句命令完成问题2?

ALTER TABLE record

ADD PRIMARY KEY (id),

CHANGEname varchar(10) not null;

########################################

索引 mysql index

        索引是一种数据结构,可以是B-tree, R-tree, 或者 hash 结构。其中R-tree 常用于查询比较接近的数据;B-trees适合用于查找某范围内的数据,可以很快的从当前数据找到下条数据;hash结构则适用于随机访问的场合,查找每 条数据的时间几乎相同。显然,若要查找某个时间段的数据,用B-tree结构要比hash结构快好多。  

       优化查询的有效方法是为经常查询的字段建立索引,如无索引查询数据时,会遍历整张表(多么恐怖啊);若有了索引查找会容易很多。当进行 UPDATE, DELETE, 以及 INSERT 操作时,mysql会自动更新索引信息。

1.创建和删除索引( Creating and dropping indexes )

创建:

[xhtml] view plaincopy
  1. mysql> USE sakila;  
  2. Database changed  
  3. mysql> CREATE INDEX idx_actor_first_name ON actor (first_name);  
  4. 或者  
  5. mysql> ALTER TABLE actor ADD INDEX idx_actor_first_name (first_name);  

PS:当用 create index 创建索引时,必须指定索引的名字,否则mysql会报错;
  用 ALTER TABLE 创建索引时,可以不指定索引名字,若不指定mysql会自动生成索引名字
  
建立索引时,若不想用存储引擎的默认索引类型,可以指定索引的类型:

  1. mysql> ALTER TABLE temp_index  
  2.  ADD INDEX (first_name),  
  3.  ADD INDEX lname (last_name) USING BTREE  

删除:

  1. DROP INDEX indexname ON tblname  
  2. mysql> DROP INDEX idx_actor_fname ON actor;  
  3. mysql> ALTER TABLE actor DROP INDEX idx_actor_fname;  

2.索引类型

BTREE    适合连续读取数据
RTREE    适合根据一条数据找附近的数据
HASH      适合随机读取数据
FULLTEXT    
SPATIAL

 查看某个表中存在的索引类型

  1. mysql> SELECT INDEX_NAME,INDEX_TYPE  
  2. -> FROM INFORMATION_SCHEMA.STATISTICS  
  3. -> WHERE TABLE_NAME=’temp_index’;  
  4. +------------+------------+  
  5. | INDEX_NAME | INDEX_TYPE |  
  6. +------------+------------+  
  7. | first_name | HASH       |  
  8. | lname      | BTREE      |  
  9. +------------+------------+  

3.索引冗余

如果两个或者多个索引包含了相同的索引信息,那么就存在索引冗余。

不同类型的索引有不同的索引冗余判断:
(1) SPATIAL 索引
SPATIAL 只能是一个简单索引,不能说复合索引;存在冗余的情况是同一个字段有两个索引。
(2) FULLTEXT 索引
若一个FULLTEXT索引是另一个索引的子集(不考虑字段顺序),则存在冗余。
例如: 表中包含如下两个索引 
■ (field1)
■ (field1, field2)
(3) HASH 索引
若一个索引在不考虑字段顺序的情况下,索引字段相同,则存在冗余。
例如:表中包含如下两个索引 
■ (field1, field2, field3)
■ (field1, field3, field2)
(4) BTREE 索引
若一个索引是另一个索引的子集(考虑字段顺序),则存在冗余。
例如:表中包含如下两个索引 
■ (field2)
■ (field2, field1)

PS:若两个或多个索引有相同的索引字段和字段顺序,但是有不同的索引类型,这样的索引是不冗余的。因为每种索引类型有自己的索引值。

######################################

深入MySQL数据库的索引 

摘要:本文介绍索引的类型,已经如何创建索引做了介绍,其中涉及三个比较重要的SQL语句――ALTER TABLE、CREATE/DROP INDEX和CREATE TABLE,注意它们的用法。

索引是加速表内容访问的主要手段,特别对涉及多个表的连接的查询更是如此。这是数据库优化中的一个重要内容,我们要了解为什么需要索引,索引如何工作以及怎样利用它们来优化查询。本节中,我们将介绍索引的特点,以及创建和删除索引的语法。 

索引的特点

所有的MySQL列类型能被索引。在相关的列上的使用索引是改进SELECT操作性能的最好方法。

一个表最多可有16个索引。最大索引长度是256个字节,尽管这可以在编译MySQL时被改变。

对于CHAR和 VARCHAR列,你可以索引列的前缀。这更快并且比索引整个列需要较少的磁盘空间。对于BLOB和TEXT列,你必须索引列的前缀,你不能索引列的全部。

MySQL能在多个列上创建索引。一个索引可以由最多15个列组成。(在CHAR和VARCHAR列上,你也可以使用列的前缀作为一个索引的部分)。

虽然随着 MySQL 的进一步开发创建索引的约束将会越来越少,但现在还是存在一些约束的。下面的表根据索引的特性,给出了 ISAM 表和 MyISAM 表之间的差别:

表2-1 通道信息特征字对照表索引的特点 ISAM 表 MyISAM 表

NULL 值

BLOB 和 TEXT 列

每个表中的索引数

每个索引中的列数

最大索引行尺寸

不允许

不能索引

16

16

256 字节 允许

只能索引列的前缀

32

16

500 字节

从此表中可以看到,对于 ISAM 表来说,其索引列必须定义为 NOT NULL,并且不能对 BLOB 和 TEXT 列进行索引。MyISAM 表类型去掉了这些限制,而且减缓了其他的一些限制。两种表类型的索引特性的差异表明,根据所使用的 MySQL 版本的不同,有可能对某些列不能进行索引。例如,如果使用3.23 版以前的版本,则不能对包含 NULL 值的列进行索引。

索引有如下的几种情况:

INDEX索引:通常意义的索引,某些情况下KEY是它的一个同义词。索引的列可以包括重复的值。

UNIQUE索引:唯一索引,保证了列不包含重复的值,对于多列唯一索引,它保证值的组合不重复。

PRIMARY KEY索引:也UNIQUE索引非常类似。事实上,PRIMARYKEY索引仅是一个具有PRIMARY名称的UNIQUE索引。这表示一个表只能包含一个PRIMARY KEY。 

用Alter Table语句创建与删除索引

为了给现有的表增加一个索引,可使用 ALTER TABLE 或CREATE INDEX 语句。ALTER TABLE 最常用,因为可用它来创建普通索引、UNIQUE 索引或 PRIMARY KEY 索引,如:

ALTER TABLE tbl_name ADD INDEX index_name  (column_list)

ALTER TABLE tbl_name ADD UNIQUE index_name  (column_list)

ALTER TABLE tbl_name ADD PRIMARY KEY index_name  (column_list)

其中 tbl_name 是要增加索引的表名,而 column_list 指出对哪些列进行索引。一个(col1,col2,...)形式的列表创造一个多列索引。索引值有给定列的值串联而成。如果索引由不止一列组成,各列名之 间用逗号分隔。索引名 index_name 是可选的,因此可以不写它,MySQL 将根据第一个索引列赋给它一个名称。ALTER TABLE 允许在单个语句中指定多个表的更改,因此可以在同时创建多个索引。

同样,也可以用ALTER TABLE语句删除列的索引:

ALTER TABLE tbl_name DROP INDEX index_name

ALTER TABLE tbl_name DROP PRIMARY KEY

注意上面第一条语句可以用来删除各种类型的索引,而第三条语句只在删除 PRIMARY KEY 索引时使用;在此情形中,不需要索引名,因为一个表只可能具有一个这样的索引。如果没有明确地创建作为 PRIMARY KEY 的索引,但该表具有一个或多个 UNIQUE 索引,则 MySQL 将删除这些 UNIQUE 索引中的第一个。

如果从表中删除了列,则索引可能会受到影响。如果所删除的列为索引的组成部分,则该列也会从索引中删除。如果组成索引的所有列都被删除,则整个索引将被删除。

例如,对于上面所使用的student为例,你可能想为之创建这样的索引,以加速表的检索速度:

mysql> ALTER TABLE student

-> ADD PRIMARY KEY(id),

-> ADD INDEXmark(english,Chinese,history);

这个例子,既包括PRIMARY索引,也包括多列索引。记住,使用 PRIMARY索引的列,必须是一个具有NOT NULL属性的列,如果你愿意查看创建的索引的情况,可以使用SHOW INDEX语句:

mysql> SHOW INDEX FROM student;

其结果为:

+---------+------------+----------+--------------+-------------+-

| Table  | Non_unique | Key_name | Seq_in_index | Column_name |

+---------+------------+----------+--------------+-------------+-

| student |          0 | PRIMARY  |           1 | id          |

| student |          1 | mark     |            1 | english     |

| student |          1 | mark     |            2 | chinese     |

| student |          1 | mark     |            3 | history     |

+---------+------------+----------+--------------+-------------+-

由于列数太多,上表并没有包括所有的输出,读者可以试着自己查看。

再使用ALTER TABLE语句删除索引,删除索引需要知道索引的名字,你可以通过SHOW INDEX语句得到:

mysql> ALTER TABLE student DROP PRIMARYKEY,

   -> DROP INDEX mark;

再产看表中的索引,其语句和输出为:

mysql> SHOW INDEX FROM student;

Empty set (0.01 sec) 

用CREATE\DROP INDEX创建索引

还可以用CREATE INDEX语句来创建索引.CREATE INDEX 是在 MySQL 3.23版中引入的,但如果使用3.23 版以前的版本,可利用 ALTER TABLE 语句创建索引(MySQL 通常在内部将 CREATE INDEX 映射到 ALTER TABLE)。该语句创建索引的语法如下:

CREATE UNIQUE INDEX index_name ON tbl_name(column_list)

CREATE INDEX index_name ON tbl_name(column_list) tbl_name、index_name 和 column_list 具有与 ALTER TABLE 语句中相同的含义。这里索引名不可选。很明显,CREATE INDEX 可对表增加普通索引或 UNIQUE 索引,不能用 CREATE INDEX 语句创建 PRIMARY KEY 索引。

可利用 DROP INDEX语句来删除索引。类似于 CREATE INDEX 语句,DROP INDEX 通常在内部作为一条 ALTER TABLE 语句处理,并且DROP INDEX是在 MySQL 3.22 中引入的。

删除索引语句的语法如下:

DROP INDEX index_name ON tbl_name

还是上一节的例子,由于CREATE INDEX不能创建PRIMARY索引,所以这里我们只创建一个多列索引:

mysql> CREATE INDEX mark ONstudent(english,chinese,history);

同样的检查student表,可知:

mysql> SHOW INDEX FROM student;

+---------+------------+----------+--------------+-------------+

| Table  | Non_unique | Key_name | Seq_in_index | Column_name |

+---------+------------+----------+--------------+-------------+

| student |          1 | mark     |           1 | english     |

| student |          1 | mark     |            2 | chinese     |

| student |          1 | mark     |            3 | history     |

+---------+------------+----------+--------------+-------------+

然后使用下面的语句删除索引:

mysql> DROP INDEX mark ON student;

在创建表时指定索引

要想在发布 CREATE TABLE 语句时为新表创建索引,所使用的语法类似于 ALTER TABLE 语句的语法,但是应该在您定义表列的语句部分指定索引创建子句,如下所示:

  1. CREATE TABLE tbl_name  
  2. (  
  3. …  
  4. INDEX index_name (column_list),  
  5. KEY index_name (column_list),  
  6. UNIQUE index_name (column_list),  
  7. PRIMARY KEY index_name (column_list),  
  8. …  
  9. )  

与ALTER TABLE 一样,索引名对于 INDEX 和 UNIQUE 都是可选的,如果未给出,MySQL 将为其选一个。另外,这里KEY时INDEX的一个别名,具有相同的意义。

有一种特殊情形:可在列定义之后增加 PRIMARY KEY 创建一个单列的PRIMARY KEY 索引,如下所示:

  1. CREATE TABLE tbl_name  
  2. (  
  3.   iINT NOT NULL PRIMARY KEY  
  4. )  

该语句等价于以下的语句:

  1. CREATE TABLE tbl_name  
  2. (  
  3.   iINT NOT NULL,  
  4.  PRIMARY KEY (i)  
  5. )  

前面所有表创建样例都对索引列指定了 NOT NULL。如果是 ISAM 表,这是必须的,因为不能对可能包含 NULL 值的列进行索引。如果是 MyISAM 表,索引列可以为 NULL,只要该索引不是 PRIMARY KEY 索引即可。

在CREATE TBALE语句中可以某个串列的前缀进行索引(列值的最左边 n 个字符)。

如果对某个串列的前缀进行索引,应用 column_list 说明符表示该列的语法为 col_name(n) 而不用col_name。例如,下面第一条语句创建了一个具有两个 CHAR 列的表和一个由这两列组成的索引。第二条语句类似,但只对每个列的前缀进行索引:

  1. CREATE TABLE tbl_name  
  2. (  
  3. name CHAR(30),  
  4. address CHAR(60),  
  5. INDEX (name,address)  
  6. )  
  1. CREATE TABLE tbl_name  
  2. (  
  3. name CHAR(30),  
  4. address CHAR(60),  
  5. INDEX (name(10),address(20))  
  6. )  

你可以检查所创建表的索引:

mysql> SHOW INDEX FROM tbl_name;

+----------+------------+----------+--------------+-------------+-

| Table   | Non_unique | Key_name | Seq_in_index | Column_name |

+----------+------------+----------+--------------+-------------+-

| tbl_name |          1 | name     |            1 | name        |

| tbl_name |          1 | name     |            2 | address     |

+----------+------------+----------+--------------+-------------+-

在某些情况下,可能会发现必须对列的前缀进行索引。例如,索引行的长度有一个最大上限,因此,如果索引列的长度超过了这个上限,那么就可能需要利用前缀进行索引。在 MyISAM 表索引中,对 BLOB 或 TEXT 列也需要前缀索引。

对一个列的前缀进行索引限制了以后对该列的更改;不能在不删除该索引并使用较短前缀的情况下,将该列缩短为一个长度小于索引所用前缀的长度的列。 

总结

本节对索引的类型,已经如何创建索引做了介绍,其中涉及三个比较重要的SQL语句――ALTER TABLE、CREATE/DROP INDEX和CREATE TABLE,注意它们的用法。

索引最重要的功能是,通过使用索引加速表的检索,有关这方面的知识,将在第十章数据库优化中介绍。 

思考题

1、建立一个如下所述的表:

data:FLOAT列,使用随机函数填充数据

birth:DATETIME列,填充当前时间。

然后,请录入几条数据。最后计算data列的平均值、总和、极值,并且按照data列降序排序检索值。

2、分别使用标准SQL模式和扩展正规表达式模式匹配,匹配上面创建的表,假设你创建表的当前日期为2001-01-01,用模式匹配检索出birth列包含该日期的值。(实际上,上面的表中记录都是同一日期录入的,因此实际将返回全部记录。)

3、为前几章使用的数据表创建索引:

student:为id段创建一个PRIMARY索引,为english、chinese和history创建一个多列索引。

pet:为name和owner段创建一个多类索引。

4、删除为pet表创建的索引。

##################################################

MySQL Index的使用

以下是理论知识备忘:

一、什么是索引?
   索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个 表的所有记录,直至找到符合要求的记录。表里面的记录数量越多,这个操作的代价就越高。如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记 录即可迅速得到目标记录所在的位置。如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍。
  
  假设我们创建了一个名为people的表:
  
  CREATE TABLE people ( peopleid SMALLINT NOT NULL, name CHAR(50) NOT NULL );
  
  然后,我们完全随机把1000个不同name值插入到people表。下图显示了people表所在数据文件的一小部分:
  
  可以看到,在数据文件中name列没有任何明确的次序。如果我们创建了name列的索引,MySQL将在索引中排序name列:
  
   对于索引中的每一项,MySQL在内部为它保存一个数据文件中实际记录所在位置的“指针”。因此,如果我们要查找name等于“Mike”记录的 peopleid(SQL命令为“SELECT peopleid FROM people WHERE name='Mike';”),MySQL能够在name的索引中查找“Mike”值,然后直接转到数据文件中相应的行,准确地返回该行的 peopleid(999)。在这个过程中,MySQL只需处理一个行就可以返回结果。如果没有“name”列的索引,MySQL要扫描数据文件中的所有 记录,即1000个记录!显然,需要MySQL处理的记录数量越少,则它完成任务的速度就越快。
  
  二、索引的类型
  MySQL提供多种索引类型供选择:
  
  普通索引
  这是最基本的索引类型,而且它没有唯一性之类的限制。普通索引可以通过以下几种方式创建:
  创建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表);
  修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表);
  创建表的时候指定索引,例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) );
  
  唯一性索引
  这种索引和前面的“普通索引”基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一。唯一性索引可以用以下几种方式创建:
  创建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表);
  修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表);
  创建表的时候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表) );
  
  主键
   主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”。如果你曾经用过AUTO_INCREMENT类型的列,你可能已经熟悉主键之类的概念了。主键一般在创建表的时候指定,例如“CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); ”。但是,我们也可以通过修改表的方式加入主键,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每个表只能有一个主键。
  
  全文索引
   MySQL从3.23.23版开始支持全文索引和全文检索。在MySQL中,全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者 TEXT类型的列上创建。它可以通过CREATE TABLE命令创建,也可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集,通过ALTER TABLE(或者CREATE INDEX)命令创建全文索引要比把记录插入带有全文索引的空表更快。本文下面的讨论不再涉及全文索引,要了解更多信息,请参见MySQL documentation。
  
  三、单列索引与多列索引
  索引可以是单列索引,也可以是多列索引。下面我们通过具体的例子来说明这两种索引的区别。假设有这样一个people表:
  
   CREATE TABLE people ( peopleid SMALLINT NOT NULL AUTO_INCREMENT, firstname CHAR(50) NOT NULL, lastname CHAR(50) NOT NULL, age SMALLINT NOT NULL, townid SMALLINT NOT NULL, PRIMARY KEY (peopleid) );
  
  下面是我们插入到这个people表的数据:
  
  这个数据片段中有四个名字为“Mikes”的人(其中两个姓Sullivans,两个姓McConnells),有两个年龄为17岁的人,还有一个名字与众不同的Joe Smith。
  
   这个表的主要用途是根据指定的用户姓、名以及年龄返回相应的peopleid。例如,我们可能需要查找姓名为Mike Sullivan、年龄17岁用户的peopleid(SQL命令为SELECT peopleid FROM people WHERE firstname='Mike' AND lastname='Sullivan' AND age=17;)。由于我们不想让MySQL每次执行查询就去扫描整个表,这里需要考虑运用索引。
  
   首先,我们可以考虑在单个列上创建索引,比如firstname、lastname或者age列。如果我们创建firstname列的索引(ALTER TABLE people ADD INDEX firstname (firstname);),MySQL将通过这个索引迅速把搜索范围限制到那些firstname='Mike'的记录,然后再在这个“中间结果集”上 进行其他条件的搜索:它首先排除那些lastname不等于“Sullivan”的记录,然后排除那些age不等于17的记录。当记录满足所有搜索条件之 后,MySQL就返回最终的搜索结果。
  
   由于建立了firstname列的索引,与执行表的完全扫描相比,MySQL的效率提高了很多,但我们要求MySQL扫描的记录数量仍旧远远超过了实际 所需要的。虽然我们可以删除firstname列上的索引,再创建lastname或者 age列的索引,但总地看来,不论在哪个列上创建索引搜索效率仍旧相似。
  
  为了提高搜索效率,我们需要考虑运用多列索引。如果为firstname、lastname和age这三个列创建一个多列索引,MySQL只需一次检索就能够找出正确的结果!下面是创建这个多列索引的SQL命令:
  
  ALTER TABLE people ADD INDEX fname_lname_age (firstname,lastname,age);
  
  由于索引文件以B-树格式保存,MySQL能够立即转到合适的firstname,然后再转到合适的lastname,最后转到合适的age。在没有扫描数据文件任何一个记录的情况下,MySQL就正确地找出了搜索的目标记录!
  
   那么,如果在firstname、lastname、age这三个列上分别创建单列索引,效果是否和创建一个firstname、lastname、 age的多列索引一样呢?答案是否定的,两者完全不同。当我们执行查询的时候,MySQL只能使用一个索引。如果你有三个单列的索引,MySQL会试图选 择一个限制最严格的索引。但是,即使是限制最严格的单列索引,它的限制能力也肯定远远低于firstname、lastname、age这三个列上的多列 索引。
  
  四、最左前缀
   多列索引还有另外一个优点,它通过称为最左前缀(Leftmost Prefixing)的概念体现出来。继续考虑前面的例子,现在我们有一个firstname、lastname、age列上的多列索引,我们称这个索引 为fname_lname_age。当搜索条件是以下各种列的组合时,MySQL将使用fname_lname_age索引:
  
  firstname,lastname,age
  firstname,lastname
  firstname
  从另一方面理解,它相当于我们创建了(firstname,lastname,age)、(firstname,lastname)以及(firstname)这些列组合上的索引。下面这些查询都能够使用这个fname_lname_age索引:
  
   SELECT peopleid FROM people WHERE firstname='Mike' AND lastname='Sullivan' AND age='17'; SELECT peopleid FROM people WHERE firstname='Mike' AND lastname='Sullivan'; SELECT peopleid FROM people WHERE firstname='Mike'; The following queries cannot use the index at all: SELECT peopleid FROM people WHERE lastname='Sullivan'; SELECT peopleid FROM people WHERE age='17'; SELECT peopleid FROM people WHERE lastname='Sullivan' AND age='17';
  
  五、选择索引列
  在性能优化过程中,选择在哪些列上创建索引是最重要的步骤之一。可以考虑使用索引的主要有两种类型的列:在WHERE子句中出现的列,在join子句中出现的列。请看下面这个查询:
  
  SELECT age ## 不使用索引
  FROM people WHERE firstname='Mike' ## 考虑使用索引
  AND lastname='Sullivan' ## 考虑使用索引
  
  这个查询与前面的查询略有不同,但仍属于简单查询。由于age是在SELECT部分被引用,MySQL不会用它来限制列选择操作。因此,对于这个查询来说,创建age列的索引没有什么必要。下面是一个更复杂的例子:
  
  SELECT people.age, ##不使用索引
  town.name ##不使用索引
  FROM people LEFT JOIN town ON
  people.townid=town.townid ##考虑使用索引
  WHERE firstname='Mike' ##考虑使用索引
  AND lastname='Sullivan' ##考虑使用索引
  
  与前面的例子一样,由于firstname和lastname出现在WHERE子句中,因此这两个列仍旧有创建索引的必要。除此之外,由于town表的townid列出现在join子句中,因此我们需要考虑创建该列的索引。
  
   那么,我们是否可以简单地认为应该索引WHERE子句和join子句中出现的每一个列呢?差不多如此,但并不完全。我们还必须考虑到对列进行比较的操作 符类型。MySQL只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE。可以 在LIKE操作中使用索引的情形是指另一个操作数不是以通配符(%或者_)开头的情形。例如,“SELECT peopleid FROM peopleWHERE firstname LIKE 'Mich%';”这个查询将使用索引,但“SELECT peopleid FROM people WHERE firstname LIKE '%ike';”这个查询不会使用索引。
  
  六、分析索引效率

  现在我们已经知道了一些如何选择索引列的知识,但还无法判断哪一个最有效。MySQL提供了一个内建的SQL命令帮助

一、 MySQL建表,字段需设置为非空,需设置字段默认值。

二、 MySQL建表,字段需NULL时,需设置字段默认值,默认值不为NULL。

三、 MySQL建表,如果字段等价于外键,应在该字段加索引。

四、 MySQL建表,不同表之间的相同属性值的字段,列类型,类型长度,是否非空,是否默认值,需保持一致,否则无法正确使用索引进行关联对比。

五、 MySQL使用时,一条SQL语句只能使用一个表的一个索引。所有的字段类型都可以索引,多列索引的属性最多15个。

六、 如果可以在多个索引中进行选择,MySQL通常使用找到最少行的索引,索引唯一值最高的索引。

七、 建立索引index(part1,part2,part3),相当于建立了 index(part1),index(part1,part2)和index(part1,part2,part3)三个索引。

八、 MySQL针对like语法必须如下格式才使用索引:

SELECT * FROM t1 WHERE key_col LIKE 'ab%' ;

九、 SELECT COUNT(*) 语法在没有where条件的语句中执行效率没有SELECT COUNT(col_name)快,但是在有where条件的语句中执行效率要快。

十、 在where条件中多个and的条件中,必须都是一个多列索引的key_part属性而且必须包含key_part1。各自单一索引的话,只使用遍历最少行的那个索引。

十一、 在where条件中多个or的条件中,每一个条件,都必须是一个有效索引。

十二、 ORDER BY 后面的条件必须是同一索引的属性,排序顺序必须一致(比如都是升序或都是降序)。

十三、 所有GROUP BY列引用同一索引的属性,并且索引必须是按顺序保存其关键字的。

十四、 JOIN 索引,所有匹配ON和where的字段应建立合适的索引。

十五、 对智能的扫描全表使用FORCE INDEX告知MySQL,使用索引效率更高。

十六、 定期ANALYZE TABLE tbl_name为扫描的表更新关键字分布 。

十七、 定期使用慢日志检查语句,执行explain,分析可能改进的索引。

十八、 条件允许的话,设置较大的key_buffer_size和query_cache_size的值(全局参数),和sort_buffer_size的值(session变量,建议不要超过4M)。


摘自:http://blog.csdn.net/tianmo2010/article/details/7930482

【转】mysql in 子查询 效率慢 优化

现在的CMS系统、博客系统、BBS等都喜欢使用标签tag作交叉链接,因此我也尝鲜用了下。但用了后发现我想查询某个tag的文章列表时速度很慢,达到5秒之久!百思不解(后来终于解决),我的表结构是下面这样的,文章只有690篇。

文章表article(id,title,content)
标签表tag(tid,tag_name)
标签文章中间表article_tag(id,tag_id,article_id)
其中有个标签的tid是135,我帮查询标签tid是135的文章列表
用以下语句时发现速度好慢,我文章才690篇
select id,title from article where id in(
select article_id from article_tag where tag_id=135
)
其中这条速度很快:select article_id from article_tag where tag_id=135
查询结果是五篇文章,id为428,429,430,431,432
我用写死的方式用下面sql来查文章也很快
select id,title from article where id in(
428,429,430,431,432
)
我在SqlServer中好像不会这样慢,不知MySQL怎样写好点,也想不出慢在哪里。

后来我找到了解决方法:

select id,title from article where id in(
select article_id from (select article_id from article_tag where tag_id=135) as tbt
)

 

 

其它解决方法:(举例)

mysql> select * from abc_number_prop where number_id in (select number_id from abc_number_phone where phone = '82306839');

为了节省篇幅,省略了输出内容,下同。

67 rows in set (12.00 sec)


只有67行数据返回,却花了12秒,而系统中可能同时会有很多这样的查询,系统肯定扛不住。用desc看一下(注:explain也可)


mysql> desc select * from abc_number_prop where number_id in (select number_id from abc_number_phone where phone = '82306839');
+----+--------------------+------------------+--------+-----------------+-------+---------+------------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+------------------+--------+-----------------+-------+---------+------------+---------+--------------------------+
| 1 | PRIMARY | abc_number_prop | ALL | NULL | NULL | NULL | NULL | 2679838 | Using where |
| 2 | DEPENDENT SUBQUERY | abc_number_phone | eq_ref | phone,number_id | phone | 70 | const,func | 1 | Using where; Using index |
+----+--------------------+------------------+--------+-----------------+-------+---------+------------+---------+--------------------------+
2 rows in set (0.00 sec)


从上面的信息可以看出,在执行此查询时会扫描两百多万行,难道是没有创建索引吗,看一下


mysql>show index from abc_number_phone;
+------------------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| abc_number_phone | 0 | PRIMARY | 1 | number_phone_id | A | 36879 | NULL | NULL | | BTREE | | |
| abc_number_phone | 0 | phone | 1 | phone | A | 36879 | NULL | NULL | | BTREE | | |
| abc_number_phone | 0 | phone | 2 | number_id | A | 36879 | NULL | NULL | | BTREE | | |
| abc_number_phone | 1 | number_id | 1 | number_id | A | 36879 | NULL | NULL | | BTREE | | |

| abc_number_phone | 1 | created_by | 1 | created_by | A | 36879 | NULL | NULL | | BTREE | | |
| abc_number_phone | 1 | modified_by | 1 | modified_by | A | 36879 | NULL | NULL | YES | BTREE | | |
+------------------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
6 rows in set (0.06 sec)

mysql>show index from abc_number_prop;
+-----------------+------------+-------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------+------------+-------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| abc_number_prop | 0 | PRIMARY | 1 | number_prop_id | A | 311268 | NULL | NULL | | BTREE | | |
| abc_number_prop | 1 | number_id | 1 | number_id | A | 311268 | NULL | NULL | | BTREE | | |

| abc_number_prop | 1 | created_by | 1 | created_by | A | 311268 | NULL | NULL | | BTREE | | |
| abc_number_prop | 1 | modified_by | 1 | modified_by | A | 311268 | NULL | NULL | YES | BTREE | | |
+-----------------+------------+-------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.15 sec)


从上面的输出可以看出,这两张表在number_id字段上创建了索引的。


看看子查询本身有没有问题。

mysql> desc select number_id from abc_number_phone where phone = '82306839';
+----+-------------+------------------+------+---------------+-------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+------+---------------+-------+---------+-------+------+--------------------------+
| 1 | SIMPLE | abc_number_phone | ref | phone | phone | 66 | const | 6 | Using where; Using index |
+----+-------------+------------------+------+---------------+-------+---------+-------+------+--------------------------+
1 row in set (0.00 sec)


没有问题,只需要扫描几行数据,索引起作用了。查询出来看看

mysql> select number_id from abc_number_phone where phone = '82306839';
+-----------+
| number_id |
+-----------+
| 8585 |
| 10720 |
| 148644 |
| 151307 |
| 170691 |
| 221897 |
+-----------+
6 rows in set (0.00 sec)


直接把子查询得到的数据放到上面的查询中

mysql> select * from abc_number_prop where number_id in (8585, 10720, 148644, 151307, 170691, 221897);

67 rows in set (0.03 sec)


速度也快,看来MySQL在处理子查询的时候是不够好。我在MySQL 5.1.42 和 MySQL 5.5.19 都进行了尝试,都有这个问题。


搜索了一下网络,发现很多人都遇到过这个问题:

参考资料1:使用连接(JOIN)来代替子查询(Sub-Queries) mysql优化系列记录
http://blog.csdn.net/hongsejiaozhu/article/details/1876181
参考资料2:网站开发日记(14)-MYSQL子查询和嵌套查询优化
http://dodomail.iteye.com/blog/250199

根据网上这些资料的建议,改用join来试试。

修改前:select * from abc_number_prop where number_id in (select number_id from abc_number_phone where phone = '82306839');

修改后:select a.* from abc_number_prop a inner join abc_number_phone b on a.number_id = b.number_id where phone = '82306839';


mysql> select a.* from abc_number_prop a inner join abc_number_phone b on a.number_id = b.number_id where phone = '82306839';

67 rows in set (0.00 sec)


效果不错,查询所用时间几乎为0。看一下MySQL是怎么执行这个查询的


mysql>desc select a.* from abc_number_prop a inner join abc_number_phone b on a.number_id = b.number_id where phone = '82306839';
+----+-------------+-------+------+-----------------+-----------+---------+-----------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------+-----------+---------+-----------------+------+--------------------------+
| 1 | SIMPLE | b | ref | phone,number_id | phone | 66 | const | 6 | Using where; Using index |
| 1 | SIMPLE | a | ref | number_id | number_id | 4 | eap.b.number_id | 3 | |
+----+-------------+-------+------+-----------------+-----------+---------+-----------------+------+--------------------------+
2 rows in set (0.00 sec)


小结:当子查询速度慢时,可用JOIN来改写一下该查询来进行优化。


网上也有文章说,使用JOIN语句的查询不一定总比使用子查询的语句快。

参考资料3:改变了对Mysql子查询的看法
http://hi.baidu.com/yzx110/blog/item/e694f536f92075360b55a92b.html

 

 

mysql手册也提到过,具体的原文在mysql文档的这个章节:

I.3. Restrictions on Subqueries

13.2.8. Subquery Syntax

摘抄:

1)关于使用IN的子查询:

Subquery optimization for IN is not as effective as for the = operator or for IN(value_list) constructs.

A typical case for poor IN subquery performance is when the subquery returns a small number of rows but the outer query returns a large number of rows to be compared to the subquery result.

The problem is that, for a statement that uses an IN subquery, the optimizer rewrites it as a correlated subquery. Consider the following statement that uses an uncorrelated subquery:

SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);

The optimizer rewrites the statement to a correlated subquery:

SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);

If the inner and outer queries return M and N rows, respectively, the execution time becomes on the order of O(M×N), rather than O(M+N) as it would be for an uncorrelated subquery.

An implication is that an IN subquery can be much slower than a query written using an IN(value_list) construct that lists the same values that the subquery would return.

2)关于把子查询转换成join的:

The optimizer is more mature for joins than for subqueries, so in many cases a statement that uses a subquery can be executed more efficiently if you rewrite it as a join.

An exception occurs for the case where an IN subquery can be rewritten as a SELECT DISTINCT join. Example:

SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE condition);

That statement can be rewritten as follows:

SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND condition;

But in this case, the join requires an extra DISTINCT operation and is not more efficient than the subquery


摘自:http://www.cnblogs.com/xh831213/archive/2012/05/09/2491272.html

【转】MySQL的mysqldump工具的基本用法

导出要用到MySQL的mysqldump工具,基本用法是:   
shell> mysqldump [OPTIONS] database [tables]   
如果你不给定任何表,整个数据库将被导出。   
通过执行mysqldump --help,你能得到你mysqldump的版本支持的选项表。   
注意,如果你运行mysqldump没有--quick或--opt选项,mysqldump将在导出结果前装载整个结果集到内存中,如果你正在导出一个大的数据库,这将可能是一个问题。   
mysqldump支持下列选项:   
--add-locks   
在每个表导出之前增加LOCK TABLES并且之后UNLOCK TABLE。(为了使得更快地插入到MySQL)。   
--add-drop-table   
在每个create语句之前增加一个drop table。   
--allow-keywords   
允许创建是关键词的列名字。这由表名前缀于每个列名做到。   
-c, --complete-insert   
使用完整的insert语句(用列名字)。   
-C, --compress   
如果客户和服务器均支持压缩,压缩两者间所有的信息。   
--delayed   
用INSERT DELAYED命令插入行。   
-e, --extended-insert   
使用全新多行INSERT语法。(给出更紧缩并且更快的插入语句)   
-#, --debug[=option_string]   
跟踪程序的使用(为了调试)。   
--help   
显示一条帮助消息并且退出。   
--fields-terminated-by=...   
    
--fields-enclosed-by=...   
    
--fields-optionally-enclosed-by=...   
    
--fields-escaped-by=...   
    
--fields-terminated-by=...   
这些选择与-T选择一起使用,并且有相应的LOAD DATA INFILE子句相同的含义。   
LOAD DATA INFILE语法。   
-F, --flush-logs   
在开始导出前,洗掉在MySQL服务器中的日志文件。   
-f, --force,   
即使我们在一个表导出期间得到一个SQL错误,继续。   
-h, --host=..   
从命名的主机上的MySQL服务器导出数据。缺省主机是localhost。   
-l, --lock-tables.   
为开始导出锁定所有表。   
-t, --no-create-info   
不写入表创建信息(CREATE TABLE语句)   
-d, --no-data   
不写入表的任何行信息。如果你只想得到一个表的结构的导出,这是很有用的!   
--opt   
同--quick --add-drop-table --add-locks --extended-insert --lock-tables。   
应该给你为读入一个MySQL服务器的尽可能最快的导出。   
-pyour_pass, --password[=your_pass]   
与服务器连接时使用的口令。如果你不指定“=your_pass”部分,mysqldump需要来自终端的口令。   
-P port_num, --port=port_num   
与一台主机连接时使用的TCP/IP端口号。(这用于连接到localhost以外的主机,因为它使用 Unix套接字。)   
-q, --quick   
不缓冲查询,直接导出至stdout;使用mysql_use_result()做它。   
-S /path/to/socket, --socket=/path/to/socket   
与localhost连接时(它是缺省主机)使用的套接字文件。   
-T, --tab=path-to-some-directory   
对 于每个给定的表,创建一个table_name.sql文件,它包含SQL CREATE 命令,和一个table_name.txt文件,它包含数 据。 注意:这只有在mysqldump运行在mysqld守护进程运行的同一台机器上的时候才工作。.txt文件的格式根据--fields-xxx和 --lines--xxx选项来定。   
-u user_name, --user=user_name   
与服务器连接时,MySQL使用的用户名。缺省值是你的Unix登录名。   
-O var=option, --set-variable var=option设置一个变量的值。可能的变量被列在下面。   
-v, --verbose   
冗长模式。打印出程序所做的更多的信息。   
-V, --version   
打印版本信息并且退出。   
-w, --where='where-condition'   
只导出被选择了的记录;注意引号是强制的!   
"--where=user='jimf'" "-wuserid>1" "-wuserid<1"  
最常见的mysqldump使用可能制作整个数据库的一个备份:  
mysqldump --opt database > backup-file.sql   
但是它对用来自于一个数据库的信息充实另外一个MySQL数据库也是有用的:   
mysqldump --opt database | mysql --host=remote-host -C database   
由于mysqldump导出的是完整的SQL语句,所以用mysql客户程序很容易就能把数据导入了:   
shell> mysqladmin create target_db_name   
shell> mysql target_db_name < backup-file.sql  
就是  
shell> mysql 库名 < 文件名 
================================
几个常用用例:
1.导出整个数据库
 mysqldump -u 用户名 -p 数据库名 > 导出的文件名    
 mysqldump -u wcnc -p smgp_apps_wcnc > wcnc.sql
2.导出一个表
 mysqldump -u 用户名 -p 数据库名 表名> 导出的文件名
 mysqldump -u wcnc -p smgp_apps_wcnc users> wcnc_users.sql
3.导出一个数据库结构
  mysqldump -u wcnc -p -d --add-drop-table smgp_apps_wcnc >d:\wcnc_db.sql
 -d 没有数据 --add-drop-table 在每个create语句之前增加一个drop table 
4.导入数据库
  常用source 命令
  进入mysql数据库控制台,
  如mysql -u root -p 
  
  mysql>use 数据库
  然后使用source命令,后面参数为脚本文件(如这里用到的.sql)
  mysql>source d:\wcnc_db.sql

摘自:http://www.blogjava.net/Alpha/archive/2007/08/10/135694.html

2013年5月31日星期五

【转】php之call_user_func_array的简易用法

今天在群里面,有个叫lewis的在问call_user_func_array的用法,因为之前一直没有用过,也不能说什么,于是看一下手册,发现是这么写的:

call_user_func_array

(PHP 4 >= 4.0.4, PHP 5)

call_user_func_array --  Call a user function given with an array of parameters

Description

mixed call_user_func_array ( callback function, array param_arr )

Call a user defined function given by function, with the parameters in param_arr.
然后还有一个例子:


<?php
function debug($var, $val
{
    
echo "***DEBUGGING\nVARIABLE: $var\nVALUE:";
    
if (is_array($val|| is_object($val|| is_resource($val)) {
        
print_r($val);
    } 
else {
        
echo "\n$val\n";
    }
    
echo "***\n";
}

$c = mysql_connect();
$host = $_SERVER["SERVER_NAME"];

call_user_func_array('debug', array("host", $host));
call_user_func_array('debug', array("c", $c));
call_user_func_array('debug', array("_POST", $_POST));
?> 
相信看了例子之后应该有点明白了吧?
我自己是这么理解这个函数的,如果说的不对,还望各位高手不要耻笑:
     该函数真正的用法有点类似于函数重载,因为他的第一个参数是字符型的,也就是函数的名称,第二个参数是数组,我们可以当成该函数的各个参数,而事实上也就是这么用的,如果你看过我的前一篇文章:PHP的伪重载 ,或许你能够理解,正是因为这个函数的存在,我发现函数重载也可以这样运用:
 1    /**
 2     * 例子写完后,本来认为完事了,结果遇到有人问call_user_func_array(),看了一下手册
 3     * 原来,我上面的那个test函数还可以精简成如下的例子,
 4     */
 5    function otest1 ($a)
 6    {
 7        echo'一个参数' );
 8    }
 9
10    function otest2 ( $a, $b)
11    {
12        echo'二个参数' );
13    }
14
15    function otest3 ( $a ,$b,$c)
16    {
17        echo'三个啦' );
18    }
19
20    function otest ()
21    {
22        $args = func_get_args();
23        $num = func_num_args();
24        call_user_func_array'otest'.$num, $args  );
25    }
26
27    otest(1,2);
28
看到不?而我最初的写法,在PHP的伪重载一文中有所提及,仅作参考。。。。

这些只是call_user_func_array的简易用法,在PHP4下测试过,而手册中还有一些将第一个参数当成数组来传入的例子,我在PHP4下是没有办法运行的,也许PHP5可以吧,但我不用PHP5的,也没有办法解释什么。谢谢各位

摘自:http://www.cnitblog.com/neatstudio/archive/2006/07/21/13990.html

【转】func_get_args的使用

func_get_args是获取方法中参数的数组,返回的是一个数组,与func_num_args搭配使用;
func_num_args一般写在方法中,用于计数;
使用方法如下:
function foo($a='gg',$b='kk'){
 
   $numargs = func_num_args();
     echo "Number of arguments: $numargs<br />\n";
     if ($numargs >= 2) {
         echo "Second argument is: " . func_get_arg(1) . "<br />\n";
     }
    $arg_list = func_get_args();
     for ($i = 0; $i < $numargs; $i++) {
         echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
     }
}

foo(1, 2);=》输出内容为:
Number of arguments: 2
Second argument is: 2
Argument 0 is: 1
Argument 1 is: 2

摘自:http://blog.sina.com.cn/s/blog_816cdc2301014rvt.html

2013年5月27日星期一

【转】mysql 创建索引、修改索引、删除索引的命令

创建和删除索引
索引的创建可以在CREATE TABLE语句中进行,也可以单独用CREATE INDEX或ALTER TABLE来给表增加索引。删除索引可以利用ALTER TABLE或DROP INDEX语句来实现。

(1)使用ALTER TABLE语句创建索引。
语法如下:

  1. alter table table_name add index index_name (column_list) ; 
  2. alter table table_name add unique (column_list) ; 
  3. alter table table_name add primary key (column_list) ; 

其中包括普通索引、UNIQUE索引和PRIMARY KEY索引3种创建索引的格式,table_name是要增加索引的表名,column_list指出对哪些列进行索引,多列时各列之间用逗号分隔。索引 名index_name可选,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTER TABLE允许在单个语句中更改多个表,因此可以同时创建多个索引。
创建索引的示例如下:

  1. mysql> use tpsc 
  2. Database changed 
  3. mysql> alter table tpsc add index shili (tpmc ) ; 
  4. Query OK, 2 rows affected (0.08 sec) 
  5. Records: 2 Duplicates: 0 Warnings: 0 

(2)使用CREATE INDEX语句对表增加索引。
能够增加普通索引和UNIQUE索引两种。其格式如下:

  1. create index index_name on table_name (column_list) ; 
  2. create unique index index_name on table_name (column_list) ; 

说明:table_name、index_name和column_list具有与ALTER TABLE语句中相同的含义,索引名不可选。另外,不能用CREATE INDEX语句创建PRIMARY KEY索引。

(3)删除索引。
删除索引可以使用ALTER TABLE或DROP INDEX语句来实现。DROP INDEX可以在ALTER TABLE内部作为一条语句处理,其格式如下:

  1. drop index index_name on table_name ; 
  2. alter table table_name drop index index_name ; 
  3. alter table table_name drop primary key ; 

其中,在前面的两条语句中,都删除了table_name中的索引index_name。而在最后一条语句中,只在删除PRIMARY KEY索引中使用,因为一个表只可能有一个PRIMARY KEY索引,因此不需要指定索引名。如果没有创建PRIMARY KEY索引,但表具有一个或多个UNIQUE索引,则MySQL将删除第一个UNIQUE索引。
如果从表中删除某列,则索引会受影响。对于多列组合的索引,如果删除其中的某列,则该列也会从索引中删除。如果删除组成索引的所有列,则整个索引将被删除。
删除索引的操作,如下面的代码:

  1. mysql> drop index shili on tpsc ; 
  2. Query OK, 2 rows affected (0.08 sec) 
  3. Records: 2 Duplicates: 0 Warnings: 0 

该语句删除了前面创建的名称为“shili”的索引。

摘自:http://www.beijibear.com/index.php?aid=544

【转】mysql 中alter语句中change和modify的区别

以下摘自mysql5手册 


您可以使用CHANGE old_col_namecolumn_definition子句对列进行重命名。重命名时,需给定旧的和新的列名称和列当前的类型。例如:要把一个INTEGER列的名称从a变更到b,您需要如下操作:

・                mysql> ALTER TABLE t1 CHANGE a b INTEGER;

如果您想要更改列的类型而不是名称, CHANGE语法仍然要求旧的和新的列名称,即使旧的和新的列名称是一样的。例如:

mysql> ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;

您也可以使用MODIFY来改变列的类型,此时不需要重命名:

mysql> ALTER TABLE t1 MODIFY b BIGINT NOT NULL;




mysql alter 语句用法,添加、修改、删除字段等


//主键549830479

   alter table tabelname add new_field_id int(5) unsigned default 0 not null auto_increment ,add primary key (new_field_id);
//增加一个新列549830479

   alter table t2 add d timestamp;
alter table infos add ex tinyint not null default '0';
//删除列549830479

   alter table t2 drop column c;
//重命名列549830479

   alter table t1 change a b integer;

//改变列的类型549830479

   alter table t1 change b b bigint not null;
alter table infos change list list tinyint not null default '0';

//重命名表549830479

   alter table t1 rename t2;
加索引549830479

   mysql> alter table tablename change depno depno int(5) not null;
mysql> alter table tablename add index 索引名 (字段名1[,字段名2 …]);
mysql> alter table tablename add index emp_name (name);
加主关键字的索引549830479

mysql> alter table tablename add primary key(id);
加唯一限制条件的索引549830479

  mysql> alter table tablename add unique emp_name2(cardnumber);
删除某个索引549830479

   mysql>alter table tablename drop index emp_name;
修改表:549830479

增加字段:549830479

   mysql> ALTER TABLE table_name ADD field_name field_type;
修改原字段名称及类型:549830479

   mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
删除字段:549830479

   mysql> ALTER TABLE table_name DROP field_name;

删除主键: alter table Employees drop primary key;

摘自:http://hi.baidu.com/software_one/item/3da0360ba7a32ce6ff240de1