mysql 中 创建索引很慢,怎么解决
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql 中 创建索引很慢,怎么解决相关的知识,希望对你有一定的参考价值。
1. 执行计划中明明有使用到索引,为什么执行还是这么慢?2. 执行计划中显示扫描行数为 644,为什么 slow log 中显示 100 多万行?
a. 我们先看执行计划,选择的索引 “INDX_BIOM_ELOCK_TASK3(TASK_ID)”。结合 sql 来看,因为有 "ORDER BY TASK_ID DESC" 子句,排序通常很慢,如果使用了文件排序性能会更差,优化器选择这个索引避免了排序。
那为什么不选 possible_keys:INDX_BIOM_ELOCK_TASK 呢?原因也很简单,TASK_DATE 字段区分度太低了,走这个索引需要扫描的行数很大,而且还要进行额外的排序,优化器综合判断代价更大,所以就不选这个索引了。不过如果我们强制选择这个索引(用 force index 语法),会看到 SQL 执行速度更快少于 10s,那是因为优化器基于代价的原则并不等价于执行速度的快慢;
b. 再看执行计划中的 type:index,"index" 代表 “全索引扫描”,其实和全表扫描差不多,只是扫描的时候是按照索引次序进行而不是行,主要优点就是避免了排序,但是开销仍然非常大。
Extra:Using where 也意味着扫描完索引后还需要回表进行筛选。一般来说,得保证 type 至少达到 range 级别,最好能达到 ref。
在第 2 点中提到的“慢日志记录Rows_examined: 1161559,看起来是全表扫描”,这里更正为“全索引扫描”,扫描行数确实等于表的行数;
c. 关于执行计划中:“rows:644”,其实这个只是估算值,并不准确,我们分析慢 SQL 时判断准确的扫描行数应该以 slow log 中的 Rows_examined 为准。
4. 优化建议:添加组合索引 IDX_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID)
优化过程:
TASK_DATE 字段存在索引,但是选择度很低,优化器不会走这个索引,建议后续可以删除这个索引:
select count(*),count(distinct TASK_DATE) from T_BIOMA_ELOCK_TASK;+------------+---------------------------+| count(*) | count(distinct TASK_DATE) |+------------+---------------------------+| 1161559 | 223 |+------------+---------------------------+
在这个 sql 中 REL_DEVID 字段从命名上看选择度较高,通过下面 sql 来检验确实如此:
select count(*),count(distinct REL_DEVID) from T_BIOMA_ELOCK_TASK;+----------+---------------------------+| count(*) | count(distinct REL_DEVID) |+----------+---------------------------+| 1161559 | 62235 |+----------+---------------------------+
由于有排序,所以得把 task_id 也加入到新建的索引中,REL_DEVID,task_id 组合选择度 100%:
select count(*),count(distinct REL_DEVID,task_id) from T_BIOMA_ELOCK_TASK;+----------+-----------------------------------+| count(*) | count(distinct REL_DEVID,task_id) |+----------+-----------------------------------+| 1161559 | 1161559 |+----------+-----------------------------------+
在测试环境添加 REL_DEVID,TASK_ID 组合索引,测试 sql 性能:alter table T_BIOMA_ELOCK_TASK add index idx_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID);
添加索引后执行计划:
这里还要注意一点“隐式转换”:REL_DEVID 字段数据类型为 varchar,需要在 sql 中加引号:AND T.REL_DEVID = 000000025xxx >> AND T.REL_DEVID = '000000025xxx'
执行时间从 10s+ 降到 毫秒级别:
1 row in set (0.00 sec)
结论
一个典型的 order by 查询的优化,添加更合适的索引可以避免性能问题:执行计划使用索引并不意味着就能执行快。 参考技术A mysql建立索引删除索引很慢的解决
目前情况
建立索引非常慢,需8分钟...
目前环境:
----------------
table行: 30W
版本5.0.45-community-nt
系统XP CPU2.11G MEM2G
测试语句:
----------------------
CREATE INDEX i_atian ON gaopinzi(atian)DROP INDEX i_atian ON gaopinzi
解决方法:调整my.ini的参数配制..不个_size统统加大10倍..
----------------------------------------------------
原来
read_buffer_size=64Kread_rnd_buffer_size=256Ksort_buffer_size=203Kinnodb_additional_mem_pool_size=2Minnodb_log_buffer_size=1M[SQL] DROP INDEX i_atian ON gaopinzi
受影响的行: 322750
时间: 459.031s
my.ini 提升10倍数
read_buffer_size=80M
read_rnd_buffer_size=80M
sort_buffer_size=88M
innodb_additional_mem_pool_size=200M
innodb_log_buffer_size=100M
QL] DROP INDEX i_atian ON gaopinzi
受影响的行: 322750
时间: 33.766s
[SQL] CREATE INDEX i_atian ON gaopinzi(atian)
受影响的行: 322750
时间: 35.890s 参考技术B
创建索引很慢一般是由于表里的数据太多造成的,
你可以先把表里的数据备份导出成sql脚本
用delete from table;删除表里所有的数据
给 表创建索引,因为表里没有数据,速度 会很快
执行备份的sql脚本导入数据到表里
mysql 数据库,表每天会插入30W条数据,该表数据千万级,查询效率很慢,建立索引是不是利大于弊?
呵呵,我认为可以建立索引,但必须要合理分配IO为什么:
1:索引是建立在表的一列或多个列上的辅助对象,目的是加快访问表中的数据(加快查询);
2:通常,通过索引查询数据比全表扫描要快. 当ORACLE找出执行查询和Update语句的最佳路径时, ORACLE优化器将使用索引. 除了那些LONG或LONG RAW数据类型, 你可以索引几乎所有的列. 在大型表中使用索引特别有效.
3:虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价. 索引需要空间来 存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢.
4:解决方案:
4.1利用分表操作。千万级的数据必须要用垂直分表操作,这样每天插入的数据在不同的表中,索引也就在不同的表的索引中,减少插入带来的效率问题
4.2 索引表空间和数据表空间分开存放。不要把索引和表数据建立在一个磁盘中,利用两个磁盘,分别进行IO操作,也就是索引表空间和数据表空间彻底分开。提高系统IO吞吐量。会有一定的效果,但不如第一个的效果好 参考技术A 如果经常查询肯定要建索引的。索引会占空间,硬盘够大的话。扩大就是了。追问
建立索引会影响插入效率吧?建立索引后每天30W的数据插入量效率大概会降低多少?
参考技术B 必须建立索引追问建立索引会影响插入效率吧?建立索引后每天30W的数据插入量效率大概会降低多少?
以上是关于mysql 中 创建索引很慢,怎么解决的主要内容,如果未能解决你的问题,请参考以下文章