mysql添加索引,查询反而变慢

1.表结构,time1添加普通索引:

CREATE TABLE `time_table` (
    `time1` INT(11) NULL DEFAULT NULL,
    `time2` INT(11) NULL DEFAULT NULL,
    INDEX `time1` (`time1`)
)
ENGINE=MyISAM
;

2.蠕虫复制创建200万条数据

insert into time_table select * from time_table


3.开始查询:time1有索引,time2没索引,数据200万

set profiling=1;
select * from time_table where time2=1111111;
select * from time_table where time1=1111111;
show profiles;

4.结果,加了索引反而变慢了:

clipboard.png

重新反思,蠕虫复制的表的内容过于简单了,总共400百万条数据,200万条数据time1=11111,time2=11111,还有200万条数据,time1=22222,time2=22222,

重新制造200万条数据,先蠕虫复制400百万条数据,time2=1,然后新加字段time1(自增),在update time2=time1,
最终的表如下(time1是唯一索引):

clipboard.png

查询时间分析,符合预期:

clipboard.png

然后改成唯一索引,也符合预期:

clipboard.png

但是依旧有问题:
为什么800万条数据,数据几乎一样(一半为111111,一半为2222)

clipboard.png
添加索引的字段,反而查询更慢。

自己的猜想:数据一样,索引是不是作用效果几乎没有,但是因为有了索引,字段存储空间多了,查询慢了,纯属自己乱想,希望可以解答一二!

希望可以交流下,qq:2210170490
阅读 14k
4 个回答

依照楼主的数据,我也造了400万数据:

mysql> select * from index_test limit 5;
id1 id2
11111 11111
22222 22222
11111 11111
22222 22222
11111 11111

id1创建索引
执行确实是id2谓词条件比较快:
mysql> select * from index_test where id1=11111;
2097152 rows in set (3.00 sec)
mysql> select * from index_test where id2=11111;
2097152 rows in set (2.32 sec)
id1的profile是这样的:
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000080 |
| checking permissions | 0.000014 |
| Opening tables | 0.000024 |
| init | 0.000033 |
| System lock | 0.000015 |
| optimizing | 0.000018 |
| statistics | 0.035408 |
| preparing | 0.000033 |
| executing | 0.000007 |
| Sending data | 2.963681 |
| end | 0.000021 |
| query end | 0.000015 |
| closing tables | 0.000020 |
| freeing items | 0.003474 |
| logging slow query | 0.000117 |
| cleaning up | 0.000072 |
+----------------------+----------+

id2的profile是这样的:
Status Duration
starting 0.000074
checking permissions 0.000012
Opening tables 0.000025
init 0.000032
System lock 0.000014
optimizing 0.000018
statistics 0.000025
preparing 0.000019
executing 0.000006
Sending data 2.318096
end 0.000020
query end 0.000034
closing tables 0.000022
freeing items 0.004327
logging slow query 0.000093
cleaning up 0.000060

可以看到id1耗时相对显著的是statistics,Sending data,主要集中在Sending data。
Sending data
The thread is reading and processing rows for a SELECT statement, and sending data to the client。
也就是说,id1=11111比id2=11111花费更多的时间在数据读取上。而id1上的是二级索引,用到该索引还有一个回表的花销,在这种数据基数小,索引的选择性就太差,这种情况不应该使用索引。
如果非要使用索引,就要避免回表,创建覆盖索引。
alter table index add index com_idx(id1,id2);
测试结果就可以看到id1=11111比id2=11111快了:
mysql> select * from index_test where id1=11111;
2097152 rows in set (1.71 sec)
mysql> select * from index_test where id2=11111;
2097152 rows in set (2.57 sec)
对应profile如下:

id1=11111
Status Duration
starting 0.000149
checking permissions 0.000084
Opening tables 0.000032
init 0.000026
System lock 0.000013
optimizing 0.000013
statistics 0.000198
preparing 0.000019
executing 0.000006
Sending data 1.710508
end 0.000024
query end 0.000015
closing tables 0.000019
freeing items 0.003275
logging slow query 0.000068
cleaning up 0.000025
id2=11111
Status Duration
starting 0.000066
checking permissions 0.000012
Opening tables 0.000020
init 0.000024
System lock 0.000011
optimizing 0.000013
statistics 0.000021
preparing 0.000015
executing 0.000006
Sending data 2.566770
end 0.000025
query end 0.000077
closing tables 0.000034
freeing items 0.004227
logging slow query 0.000093
cleaning up 0.000018

800万条数据 一半111一半222,你建立的索引的区分度不高,mysql优化器不会使用索引而会选择全表扫描 可以explain查看搜索计划

查询的某些字段的值很长吧
show profile for query 13;
show profile for query 14;

建议执行看下是什么导致索引的比较长。
其实这没有可比性,time1和time2值的分布并不一样,导致带索引的查询反而更长,可能是time1=1111111的记录更多,从而需要更长时间返回。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题