mysql全文索引 很慢,速度不如like的百分之一

mysql全文索引 很慢,速度不如like的百分之一,第1张

从explain开始说起吧,很显然第一个sql语句压根没用任何索引(key列内什么都没有)!第二个倒是用到索引,却是主键索引,并非你添加的fulltext索引!接下来,分析下原因:sql1:执行步骤:先s_a和s_a_t两表笛卡尔集,然后筛选满足on条件的,接着在从结果集中筛选满足where字句的;该过程中处理的记录条目为69*105479,并且未用到任何索引,未用到的原因可能是你先定义了一个复合索引a_concent_split(a_title_split,a_content_split),然后又定义了一个a_content_split2(a_content_split),当引擎执行查找优化时候会先用到a_content_split,可是又由于复合索引是从最左边开始(不能跳过第一个字段),而你却忽略了a_title_split字段,故未能正常使用索引。sql2:执行步骤:先调用where字句对s_a表进行筛选形成新的s_a表,然后与s_a_t表笛卡尔积,再利用on字句筛选,最后再次利用where字句形成最终结果集;经过第一个where,该过程处理结果集会大幅少于sql1,并且该过程还用到了主键索引。你所设置的fulltext索引再次没有用到,原因是like字句中开始部分为模糊匹配%时候用不了全文索引,这与fulltext存储机制有关。另,你说的删除速度慢,原因:设置fulltext字段设置太多,fulltext索引在更新删除大量数据时候,需要同步更改索引,你的三个fulltext压力太大!改进方法:1、删除a_content_split索引重试 2、在删除时候打开delay_key_write变量有关fulltext比较复杂,用的时候要谨慎设置,还有很多参数也对其有影响另外sql语句中外连接有关on where字句也是个比较绕的地方,两者你都占了,唉,所以我写的略复杂,前天看到该问题,思忖两天这才作答望有结果了予以回复交流!

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 查询的优化,添加更合适的索引可以避免性能问题:执行计划使用索引并不意味着就能执行快。

如果要删除的数据量比较小的话对索引以及性能是微乎其微的,但是一旦需要删除的数据很大(比如总数据1KW,500W是需要删除的数据)就会对造成整体查询变慢,新数据的插入也会因为数据量比较多,构建索引变慢。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/6249249.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-19
下一篇 2023-03-19

发表评论

登录后才能评论

评论列表(0条)

保存