为MYSQL数据库建立索引

风清扬斈 12年前 (2008-03-02) 信息科技 3415 0

就象许多的PHP开发者一样,在刚开始建立动态网站的时候,我都是使用相对简单的数据结构。PHP在连接数据库方面的确实是十分方便(译者注:有些人认为PHP在连接不同数据库时没有一个统一的接口,不太方便,其实这可以通过一些扩展库来做到这一点),你无需看大量的设计文档就可以建立和使用数据库,这也是PHP获得成功的主要原因之一。 

  前些时候,一位颇高级的程序员居然问我什么叫做索引,令我感到十分的惊奇,我想这绝不会是沧海一粟,因为有成千上万的开发者(可能大部分是使用MySQL的)都没有受过有关数据库的正规培训,尽管他们都为客户做过一些开发,但却对如何为数据库建立适当的索引所知较少,因此我起了写一篇相关文章的念头。

  最普通的情况,是为出现在where子句的字段建一个索引。为方便讲述,我们先建立一个如下的表。

  CREATE TABLE mytable (
     id serial primary key,
     category_id int not null default 0,
     user_id int not null default 0,
     adddate int not null default 0
  );

  很简单吧,不过对于要说明这个问题,已经足够了。如果你在查询时常用类似以下的语句:

   SELECT * FROM mytable WHERE category_id=1; 

  最直接的应对之道,是为category_id建立一个简单的索引:

   CREATE INDEX mytable_categoryid 
     ON mytable (category_id);

  OK,搞定?先别高兴,如果你有不止一个选择条件呢?例如:

   SELECT * FROM mytable WHERE category_id=1 AND user_id=2;

  你的第一反应可能是,再给user_id建立一个索引。不好,这不是一个最佳的方法。你可以建立多重的索引。

  CREATE INDEX mytable_categoryid_userid ON mytable (category_id,user_id);

  注意到我在命名时的习惯了吗?我使用"表名_字段1名_字段2名"的方式。你很快就会知道我为什么这样做了。

  现在你已经为适当的字段建立了索引,不过,还是有点不放心吧,你可能会问,数据库会真正用到这些索引吗?测试一下就OK,对于大多数的数据库来说,这是很容易的,只要使用EXPLAIN命令:

  EXPLAIN

   SELECT * FROM mytable 
    WHERE category_id=1 AND user_id=2;

   This is what Postgres 7.1 returns (exactly as I expected) 

   NOTICE: QUERY PLAN:

   Index Scan using mytable_categoryid_userid on 
     mytable (cost=0.00..2.02 rows=1 width=16)

  EXPLAIN

以上是postgres的数据,可以看到该数据库在查询的时候使用了一个索引(一个好开始),而且它使用的是我创建的第二个索引。看到我上面命名的好处了吧,你马上知道它使用适当的索引了。
接着,来个稍微复杂一点的,如果有个ORDER BY字句呢?不管你信不信,大多数的数据库在使用order by的时候,都将会从索引中受益。

   SELECT * FROM mytable 
    WHERE category_id=1 AND user_id=2
     ORDER BY adddate DESC;

有点迷惑了吧?很简单,就象为where字句中的字段建立一个索引一样,也为ORDER BY的字句中的字段建立一个索引:

   CREATE INDEX mytable_categoryid_userid_adddate
     ON mytable (category_id,user_id,adddate);

   注意: "mytable_categoryid_userid_adddate" 将会被截短为

   "mytable_categoryid_userid_addda"

   CREATE

   EXPLAIN SELECT * FROM mytable
    WHERE category_id=1 AND user_id=2
     ORDER BY adddate DESC;

   NOTICE: QUERY PLAN:

   Sort (cost=2.03..2.03 rows=1 width=16)
    -> Index Scan using mytable_categoryid_userid_addda 
       on mytable (cost=0.00..2.02 rows=1 width=16)

   EXPLAIN

  看看EXPLAIN的输出,好象有点恐怖啊,数据库多做了一个我们没有要求的排序,这下知道性能如何受损了吧,看来我们对于数据库的自身运作是有点过于乐观了,那么,给数据库多一点提示吧。

  为了跳过排序这一步,我们并不需要其它另外的索引,只要将查询语句稍微改一下。这里用的是postgres,我们将给该数据库一个额外的提示--在ORDER BY语句中,加入where语句中的字段。这只是一个技术上的处理,并不是必须的,因为实际上在另外两个字段上,并不会有任何的排序操作,不过如果加入,postgres将会知道哪些是它应该做的。

   EXPLAIN SELECT * FROM mytable 
    WHERE category_id=1 AND user_id=2
     ORDER BY category_id DESC,user_id DESC,adddate DESC;

   NOTICE: QUERY PLAN:

   Index Scan Backward using 
    mytable_categoryid_userid_addda on mytable 
     (cost=0.00..2.02 rows=1 width=16)

   EXPLAIN

现在使用我们料想的索引了,而且它还挺聪明,知道可以从索引后面开始读,从而避免了任何的排序。

以上说得细了一点,不过如果你的数据库非常巨大,并且每日的页面请求达上百万算,我想你会获益良多的。不过,如果你要做更为复杂的查询呢,例如将多张表结合起来查询,特别是where限制字句中的字段是来自不止一个表格时,应该怎样处理呢?我通常都尽量避免这种做法,因为这样数据库要将各个表中的东西都结合起来,然后再排除那些不合适的行,搞不好开销会很大。

  如果不能避免,你应该查看每张要结合起来的表,并且使用以上的策略来建立索引,然后再用EXPLAIN命令验证一下是否使用了你料想中的索引。如果是的话,就OK。不是的话,你可能要建立临时的表来将他们结合在一起,并且使用适当的索引。

  要注意的是,建立太多的索引将会影响更新和插入的速度,因为它需要同样更新每个索引文件。对于一个经常需要更新和插入的表格,就没有必要为一个很少使用的where字句单独建立索引了,对于比较小的表,排序的开销不会很大,也没有必要建立另外的索引。

  以上介绍的只是一些十分基本的东西,其实里面的学问也不少,单凭EXPLAIN我们是不能判定该方法是否就是最优化的,每个数据库都有自己的一些优化器,虽然可能还不太完善,但是它们都会在查询时对比过哪种方式较快,在某些情况下,建立索引的话也未必会快,例如索引放在一个不连续的存储空间时,这会增加读磁盘的负担,因此,哪个是最优,应该通过实际的使用环境来检验。

  在刚开始的时候,如果表不大,没有必要作索引,我的意见是在需要的时候才作索引,也可用一些命令来优化表,例如MySQL可用"OPTIMIZE TABLE"。

  综上所述,在如何为数据库建立恰当的索引方面,你应该有一些基本的概念了。
早上帮朋友一台服务器解决了 Mysql cpu 占用 100% 的问题,稍整理如下,希望对各位有所帮助。 

    朋友主机(Windows 2003 + IIS + PHP + MYSQL )近来 MySQL 服务进程 (mysqld-nt.exe) CPU 占用率总为 100% 高居不下。此主机有10个左右的 database, 分别给十个网站调用。据朋友测试,导致 mysqld-nt.exe cpu 占用奇高的是网站A,一旦在 IIS 中将此网站停止服务,CPU 占用就降下来了。一启用,则马上上升。 

    MYSQL CPU 占用 100% 的解决过程 

    今天早上仔细检查了一下。目前此网站的七日平均日 IP 为2000,PageView 为 3万左右。网站A 用的 database 目前有39个表,记录数 60.1万条,占空间 45MB。按这个数据,MySQL 不可能占用这么高的资源。 

    于是在服务器上运行命令,将 mysql 当前的环境变量输出到文件 output.txt: 
d:webmysql> mysqld.exe --help >output.txt
    发现 tmp_table_size 的值是默认的 32M,于是修改 My.ini, 将 tmp_table_size 赋值到 200M:
d:webmysql> notepad c:windowsmy.ini
[mysqld]
tmp_table_size=200M
    然后重启 MySQL 服务。CPU 占用有轻微下降,以前的CPU 占用波形图是 100% 一根直线,现在则在 97%~100%之间起伏。这表明调整 tmp_table_size 参数对 MYSQL 性能提升有改善作用。但问题还没有完全解决。 

    于是进入 mysql 的 shell 命令行,调用 show processlist, 查看当前 mysql 使用频繁的 sql 语句: 
mysql> show processlist; 

    反复调用此命令(每秒刷两次),发现网站 A 的两个 SQL 语句经常在 process list 中出现,其语法如下: 
SELECT t1.pid, t2.userid, t3.count, t1.date
FROM _mydata AS t1
LEFT JOIN _myuser AS t3 ON t1.userid=t3.userid
LEFT JOIN _mydata_body AS t2 ON t1.pid=t3.pid
ORDER BY t1.pid
LIMIT 0,15


    调用 show columns 检查这三个表的结构 : 
mysql> show columns from _myuser;
mysql> show columns from _mydata;
mysql> show columns from _mydata_body;


    终于发现了问题所在:_mydata 表,只根据 pid 建立了一个 primary key,但并没有为 userid 建立索引。而在这个 SQL 语句的第一个 LEFT JOIN ON 子句中: 
LEFT JOIN _myuser AS t3 ON t1.userid=t3.userid


    _mydata 的 userid 被参与了条件比较运算。于是我为给 _mydata 表根据字段 userid 建立了一个索引: 
mysql> ALTER TABLE `_mydata` ADD INDEX ( `userid` )


    建立此索引之后,CPU 马上降到了 80% 左右。看到找到了问题所在,于是检查另一个反复出现在 show processlist 中的 sql 语句: 
SELECT COUNT(*)
FROM _mydata AS t1, _mydata_key AS t2
WHERE t1.pid=t2.pid and t2.keywords = ’孔雀’


    经检查 _mydata_key 表的结构,发现它只为 pid 建了了 primary key, 没有为 keywords 建立 index。_mydata_key 目前有 33 万条记录,在没有索引的情况下对33万条记录进行文本检索匹配,不耗费大量的 cpu 时间才怪。看来就是针对这个表的检索出问题了。于是同样为 _mydata_key 表根据字段 keywords 加上索引: 
mysql> ALTER TABLE `_mydata_key` ADD INDEX ( `keywords` )


    建立此索引之后,CPU立刻降了下来,在 50%~70%之间震荡。 

    再次调用 show prosslist,网站A 的sql 调用就很少出现在结果列表中了。但发现此主机运行了几个 Discuz 的论坛程序, Discuz论坛的好几个表也存在着这个问题。于是顺手一并解决,cpu占用再次降下来了。 

    至此,问题解决。  
 1. 增加 tmp_table_size 值。mysql 的配置文件中,tmp_table_size 的默认大小是 32M。如果一张临时表超出该大小,MySQL产生一个 The table tbl_name is full 形式的错误,如果你做很多高级 GROUP BY 查询,增加 tmp_table_size 值。 这是 mysql 官方关于此选项的解释: 

    tmp_table_size 
    This variable determines the maximum size for a temporary table in memory. If the table becomes too large, a MYISAM table is created on disk. Try to avoid temporary tables by optimizing the queries where possible, but where this is not possible, try to ensure temporary tables are always stored in memory. Watching the processlist for queries with temporary tables that take too long to resolve can give you an early warning that tmp_table_size needs to be upped. Be aware that memory is also allocated per-thread. An example where upping this worked for more was a server where I upped this from 32MB (the default) to 64MB with immediate effect. The quicker resolution of queries resulted in less threads being active at any one time, with all-round benefits for the server, and available memory. 

    2. 对 WHERE, JOIN, MAX(), MIN(), ORDER BY 等子句中的条件判断中用到的字段,应该根据其建立索引 INDEX。 

    索引被用来快速找出在一个列上用一特定值的行。没有索引,MySQL不得不首先以第一条记录开始并然后读完整个表直到它找出相关的行。表越大,花费时间越多。如果表对于查询的列有一个索引,MySQL能快速到达一个位置去搜寻到数据文件的中间,没有必要考虑所有数据。如果一个表有1000行,这比顺序读取至少快100倍。所有的MySQL索引(PRIMARY、UNIQUE和INDEX)在B树中存储。 

    根据 mysql 的开发文档: 

    索引 index 用于: 

    o 快速找出匹配一个WHERE子句的行 
    o 当执行联结(JOIN)时,从其他表检索行。 
    o 对特定的索引列找出MAX()或MIN()值 
    o 如果排序或分组在一个可用键的最左面前缀上进行(例如,ORDER BY key_part_1,key_part_2),排序或分组一个表。如果所有键值部分跟随DESC,键以倒序被读取。 
    o 在一些情况中,一个查询能被优化来检索值,不用咨询数据文件。如果对某些表的所有使用的列是数字型的并且构成某些键的最左面前缀,为了更快,值可以从索引树被检索出来。 

    假定你发出下列SELECT语句: 

mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2; 

    如果一个多列索引存在于col1和col2上,适当的行可以直接被取出。如果分开的单行列索引存在于col1和col2上,优化器试图通过决定哪个索引将找到更少的行并来找出更具限制性的索引并且使用该索引取行。 

    开发人员做 SQL 数据表设计的时候,一定要通盘考虑清楚。

 索引

  索引用来快速地寻找那些具有特定值的记录,所有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 people WHERE firstname LIKE ’Mich%’;”这个查询将运用索引,但“SELECT peopleid FROM people WHERE firstname LIKE ’%ike’;”这个查询不会运用索引。

  剖析索引效力

  现在我们已经知道了一些如何选择索引列的知识,但还无法确定哪一个最有效。MySQL供应了一个内建的SQL命令资助我们完成这个责任,这就是EXPLAIN命令。EXPLAIN命令的一般语法是:EXPLAIN 。你可以在MySQL文档找到有关该命令的更多阐明。下面是一个例子:

  EXPLAIN SELECT peopleid FROM people WHERE firstname=’Mike’ AND lastname=’Sullivan’ AND age=’17’;

  这个命令将返回下面这种剖析结果:

table type possible_keys key  key_len ref  rows Extra 
people ref fname_lname_age fname_lname_age 102 const,const,const 1 Where used 


  下面我们就来看看这个EXPLAIN剖析结果的含义。

  table:这是表的名字。

  type:连接操作的类型。下面是MySQL文档关于ref连接类型的阐明:

  “对于每一种与另一个表中记录的组合,MySQL将从当前的表读取所有带有匹配索引值的记录。如果连接操作只运用键的最左前缀,或者如果键不是UNIQUE或PRIMARY KEY类型(换句话说,如果连接操作不能根据键值选择出唯一行),则MySQL运用ref连接类型。如果连接操作所用的键只匹配少量的记录,则ref是一种好的连接类型。”

  在本例中,由于索引不是UNIQUE类型,ref是我们能够得到的最好连接类型。

  如果EXPLAIN显示连接类型是“ALL”,而且你并不想从表里面选择出大多数记录,那么MySQL的操作效力将非常低,因为它要扫描全部表。你可以加入更多的索引来解决这个问题。预知更多信息,请参见MySQL的手册阐明。

  possible_keys:

  可能可以使用的索引的名字。这里的索引名字是创立索引时指定的索引昵称;如果索引没有昵称,则默认显示的是索引中第一个列的名字(在本例中,它是“firstname”)。默认索引名字的含义往往不是很明显。

  Key:它显示了MySQL实际运用的索引的名字。如果它为空(或NULL),则MySQL不运用索引。

  key_len:索引中被运用部分的长度,以字节计。在本例中,key_len是102,其中firstname占50字节,lastname占50字节,age占2字节。如果MySQL只运用索引中的firstname部分,则key_len将是50。

  ref:它显示的是列的名字(或单词“const”),MySQL将根据这些列来选择行。在本例中,MySQL根据三个常量选择行。

  rows:MySQL所认为的它在找到准确的结果之前必需扫描的记录数。显然,这里最梦想的数字就是1。

  Extra:这里可能出现许多不同的选项,其中大多数将对查询发生负面影响。在本例中,MySQL只是提醒我们它将用WHERE子句限制搜索结果集。

  索引的缺陷

  到目前为止,我们讨论的都是索引的长处。事实上,索引也是有缺陷的。

  首先,索引要占用磁盘空间。通常情形下,这个问题不是很突出。但是,如果你创立每一种可能列组合的索引,索引文件体积的增加速度将远远超过数据文件。如果你有一个很大的表,索引文件的大小可能到达操作体系允许的最大文件限制。

  第二,对于须要写入数据的操作,比如DELETE、UPDATE以及INSERT操作,索引会降低它们的速度。这是因为MySQL不仅要把篡改数据写入数据文件,而且它还要把这些篡改写入索引文件。

  【停止语】在大型数据库中,索引是提高速度的一个关键因素。不管表的结构是多么简单,一次500000行的表扫描操作无论如何不会快。如果你的网站上也有这种大规模的表,那么你确凿应该花些光阴去剖析可以采取哪些索引,并斟酌是否可以改写查询以优化使用。要了解更多信息,请参见MySQL manual。另外注意,本文假定你所运用的MySQL是3.23版,部分查询不能在3.22版MySQL上实行。


"

相关推荐

  • 网友评论

    • (*)

    最新评论