mysql查询索引优化

Myth丶恋晨 2022-06-13 12:12 456阅读 0赞

索引一般用于在数据规模大时对查询进行优化的一种机制,对于一般的查询来说,MySQL会去遍历整个表,来查询符合要求的结果;如果借助于索引,mysql会将要索引的字段按照一定的算法进行处理,并生成一个类似于书本目录的文件存放在相应的位置,这样在查询时,mysql会先去查找这些”目录”,然后根据这些”目录”来快速定位所需记录的位置,这样的查找不用遍历整个记录集,速度自然会很快,对于海量数据尤其如此。

  1. 关于如何创建索引,网上有相关的例子,这里不多讲,但是有一个需要注意,在向存在索引的表中插入数据时,因为要维护索引信息,要比不存在索引的表慢一些,因此当数据量大时,可以考虑在插入完数据之后再建立索引。索引分为单列索引和组合索引,对于这两种索引,分别介绍其优化问题。

1、单列索引

  1. 单列所有只包含一个字段,一个表可以包含多个单列索引,但是不要把这个和组合索引混淆。利用以下sql创建[测试][Link 2]表:







01 —创建包含单列索引的index_test_single_a表







02 CREATE TABLE index_test_a (







03   id int(11) NOT NULL AUTO_INCREMENT,







04   title char(255) CHARACTER SET utf8 NOT NULL,







05   content text CHARACTER SET utf8,







06   num int(11) DEFAULT NULL,







07   PRIMARY KEY (id),







08   UNIQUE KEY indexName (title),







09   UNIQUE KEY numIndex (num)







10 ) ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=latin1;







11  







12 —创建不包含单列索引的index_test_single_b表







13 CREATE TABLE index_test_b (







14   id int(11) NOT NULL AUTO_INCREMENT,







15   title char(255) CHARACTER SET utf8 NOT NULL,







16   content text CHARACTER SET utf8,







17   num int(11) DEFAULT NULL,







18   PRIMARY KEY (id)







19 ) ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=latin1;

其中a表包含title的单列索引,b表的title字段不存在索引,但是两个表都有一个主键id,其实主键也是索引的一种,这个会在后面详细解释。

写程序向这两个表中各导入10000条数据,然后就可以测试了。

1.1、测试查询索引字段所用的时间,代码如下:








01 <?php







02     //phpinfo();







03     ini_set(‘max_execution_time’, 200);







04     $con = mysql_connect(“localhost:3306”,“root”,“710100”);







05     if (!$con)







06     {  







07       die(‘Could not connect: ‘ . mysql_error());







08     }







09     else{







10             mysql_select_db(“test”,$con);







11          







12      







13         $sqlA “select * from index_test_a where title = ‘title_4999’;”;







14          







15          







16          







17         $sqlB “select * from index_test_b where  title = ‘title_4999’;”;







18      







19         $startTimeA = microtime();







20          







21          







22          







23         $result = mysql_query($sqlAor   die“Invalid   query:   “  .   mysql_error());







24          







25         $endTimeA = microtime();







26          







27         echo “A表查询所有记录所用时间:”.(($endTimeA-$startTimeA)*1000).“毫秒”;







28          







29         echo “<br>”;







30          







31         $startTimeB = microtime();







32          







33         $result = mysql_query($sqlBor   die“Invalid   query:   “  .   mysql_error());







34          







35         $endTimeB = microtime();







36          







37         echo “B表查询所有记录所用时间:”.(($endTimeB-$startTimeB)*1000).“毫秒”;







38         mysql_close($con);







39     }







40      







41      







42 ?>

执行结果如下:

A表查询所有记录所用时间:0.624毫秒

B表查询所有记录所用时间:44.484毫秒

可以看到仅仅10000条记录的查找差别,时间已经相差了几十倍,因此对于经常查询的字段,索引是十分必要的。相应的,如果我们查询没有做索引的字段,那么是没有区别的,将以上的sql语句改为如下所示:








1 $sqlA “select * from index_test_a where content = ‘content_4999’;”;







2          







3 $sqlB “select * from index_test_b where  content = ‘content_4999’;”;

结果如下:

A表查询所有记录所用时间:23.848毫秒

B表查询所有记录所用时间:24.155毫秒

1.2、测试like查询

在我们项目中,如果数据量大,则不推荐like查询,因为其查询效率比较低,但是对于索引字段来说,like能命中吗?

可以将sql语句改成如下所示:








1 $sqlA “select * from index_test_a where title like ‘4999%’”;







2 $sqlB “select * from index_test_b where title like ‘4999%’”;

测试结果如下:

A表查询所有记录所用时间:0.488毫秒

B表查询所有记录所用时间:25.281毫秒

可以看到对于模糊查询来说,如果是前缀匹配,则会命中索引,但是如果我们将sql改为后缀匹配或者任意匹配,那么二者所消耗的查询时间是一致的:








1 $sqlA “select * from index_test_a where title like ‘%4999’”;







2 $sqlB “select * from index_test_b where title like ‘%4999’”;







1 $sqlA “select * from index_test_a where title like ‘%4999’”;







2 $sqlB “select * from index_test_b where title like ‘%4999’”;

A表查询所有记录所用时间:44.742毫秒

B表查询所有记录所用时间:45.752毫秒

即二者都没有命中索引。

1.3、测试or语句,将sql改为如下所示:








1 $sqlA“select * from index_test_a where  content=’content_4999’ or title=’title_4999’;”;







2  







3 $sqlB“select * from index_test_b where  content=’content_4999’ or title=’title_4999’;”;

测试结果如下:

A表查询所有记录所用时间:49.904毫秒

B表查询所有记录所用时间:50.131毫秒

继续将sql改为如下:








1 $sqlA “select * from index_test_a where  id=4999  or title=’title_4999’;”;







2  







3 $sqlB “select * from index_test_b where  id=4999  or title=’title_4999’;”;

测试结果如下:

A表查询所有记录所用时间:0.86毫秒

B表查询所有记录所用时间:47.318毫秒

从上面的结果可以看到,当or中有一个字段没有索引的时候,那么将不会命中索引;反之,如果or运算的所有字段均做了索引,那么是可以命中的。

1.4、测试in,将sql语句继续改为如下所示:








1 $sqlA “select title from index_test_a  where title in (‘title_4999’,’title_5000’);”;







2 $sqlB “select title from index_test_b  where title in (‘title_4999’,’title_5000’);”;

测试结果为:

A表查询所有记录所用时间:0.817毫秒
B表查询所有记录所用时间:24.234毫秒

可见对于索引字段,in也是可以命中索引的。

1.5、测试<,>,between等,将sql改为如下所示:








1 $sqlA “select title from index_test_a  where num < 999;”;







2 $sqlB “select title from index_test_b  where num < 999;”;

测试结果如下:

A表查询所有记录所用时间:11.469毫秒

B表查询所有记录所用时间:21.728毫秒

可见二者差别不是很大,因此是没有命中索引的。

1.6、对于mysql函数,索引的命中,将sql改为如下所示:








1 $sqlA “select num from index_test_a  where char(num) in (‘999’,’9999’);”;







2 $sqlB “select num from index_test_b  where  char(num) in (‘999’,’9999’);”;

得到的结果如下所示:

A表查询所有记录所用时间:11.322毫秒

B表查询所有记录所用时间:12.429毫秒

所以如果在条件中使用函数,那么索引将会失效。

2、组合索引

组合索引包括对多个列的索引,而不是多个单列索引的组合,将表a中的所以改成(title,num)的组合索引,进行以下测试:

2.1、or测试

将sql语句改成如下所示:








1 $sqlA “select * from index_test_a where  num=4999  or title=’title_4999’;”;







2 $sqlB “select * from index_test_b where  num=4999 or title=’title_4999’;”;

结果如下所示:

A表查询所有记录所用时间:52.535毫秒

B表查询所有记录所用时间:53.031毫秒

这时索引没有命中,索引组合索引的or运算和两个单列索引的or运算是不同的,前者失效而后者依然有效。

2.2、and测试

将sql语句改成如下所示:








1 $sqlA “select * from index_test_a where  num=4999  and title=’title_4999’;”;







2 $sqlB “select * from index_test_b where  num=4999 and title=’title_4999’;”;

结果如下所示:

A表查询所有记录所用时间:0.666毫秒

B表查询所有记录所用时间:43.042毫秒

继续改为如下所示:








1 $sqlA “select * from index_test_a where  num=4999 ;”;







2 $sqlB “select * from index_test_b where  num=4999 ;”;

得到的结果为:

A表查询所有记录所用时间:39.398毫秒

B表查询所有记录所用时间:41.057毫秒

而改成如下sql:








1 $sqlA “select * from indextest_a where  title=’title‘4999 ;”;







2 $sqlB “select * from index_test_b where  title=’title_4999’ ;”;

得到的结果则为:

A表查询所有记录所用时间:0.753毫秒

B表查询所有记录所用时间:48.248毫秒

由以上三组结果可以看出,组合索引是最左前缀匹配的,即条件中要包含第一个索引列,才会命中索引。

3、 索引的优缺点

利用索引可以大大加快我们的搜索,但是维护索引需要额外的开销,尤其是当索引较多的时候,大量的数据会很容易带来索引量的膨胀,因此对于频繁要用到的查询,我们才需要做索引,这样才能以最小的代价获得最大的性能提升。

发表评论

表情:
评论列表 (有 0 条评论,456人围观)

还没有评论,来说两句吧...

相关阅读

    相关 MySQL索引查询优化

    索引相关 索引基数 基数是数据列所包含的不同值的数量,例如,某个数据列包含值 1、3、7、4、7、3,那么它的基数就是 4。 索引的基数相对于数据表行数较高(也就

    相关 mysql查询索引优化

    索引一般用于在数据规模大时对查询进行优化的一种机制,对于一般的查询来说,[MySQL][]会去遍历整个表,来查询符合要求的结果;如果借助于索引,[mysql][MySQL]会将

    相关 MYSQL索引查询优化

    [MYSQL索引与查询优化][MYSQL] 一、什么是索引 1、简单定义 索引通过各种数据结构实现值到行(值=》行)位置的映射,没有索引会全表扫描; 2、索引的

    相关 Mysql索引查询效率优化

    Mysql索引查询效率优化 1.为什么要使用索引?什么是索引 答:使用索引可以大幅度增强查询的速度。但是我们在一些频繁修改或者删除的表上面,不建议建立太多的索引,因为