MySQL 5.7中INNODB表计数查询的MySQL忽略索引
我们有一个运行MySQL 5.1的旧数据库。我们现在想将其迁移到MySQL 5.7,但一些正常工作的查询突然变得非常慢,慢了60倍或更多 有问题的INNODB表事件在其他列中有一个COMPANY_ID外键,指向COMPANY表,以及DATETIME类型的EVENT_DATETIME。公司ID、事件日期时间上有一个索引,为了测试,我添加了一个事件日期时间、公司ID。 目前,基本上所有活动都有公司ID 1,但这将发生变化 我们有一个计数查询来查询去年的事件数:MySQL 5.7中INNODB表计数查询的MySQL忽略索引,mysql,hibernate,indexing,mysql-5.7,Mysql,Hibernate,Indexing,Mysql 5.7,我们有一个运行MySQL 5.1的旧数据库。我们现在想将其迁移到MySQL 5.7,但一些正常工作的查询突然变得非常慢,慢了60倍或更多 有问题的INNODB表事件在其他列中有一个COMPANY_ID外键,指向COMPANY表,以及DATETIME类型的EVENT_DATETIME。公司ID、事件日期时间上有一个索引,为了测试,我添加了一个事件日期时间、公司ID。 目前,基本上所有活动都有公司ID 1,但这将发生变化 我们有一个计数查询来查询去年的事件数: select count(distin
select count(distinct this_.EVENT_ID) as y0_ from EVENT this_
where this_.EVENT_DATETIME>='2018-10-22 00:00:00'
and this_.EVENT_DATETIME<='2019-11-21 00:00:00'
and this_.COMPANY_ID = 1;
结果是大约1000000行,过去需要1.5秒,现在需要100秒。虽然MySQL 5.1上的查询使用公司ID和事件日期时间的索引,但MySQL 5.7上的索引被忽略。看起来,如果MySQL发现它必须解析太多的行,那么它会在索引上放弃,即使这会有所帮助。如果我将窗口缩小到10个月,MySQL 5.7会再次使用索引
因此,在MySQL 5.1上,使用了索引COMPANY\u ID、EVENT\u DATETIME
在MySQL上,它只对公司ID使用外键索引
如果我在没有公司ID上的where的情况下运行查询
select count(distinct this_.EVENT_ID) as y0_ from EVENT this_
where this_.EVENT_DATETIME>='2018-10-22 00:00:00'
and this_.EVENT_DATETIME<='2019-11-21 00:00:00';
查询速度要快得多
有没有办法强迫MySQL 5.7使用某个索引
如果我将查询重写为:
select count(distinct this_.EVENT_ID) as y0_ from EVENT this_
where this_.EVENT_DATETIME>='2018-10-22 00:00:00'
and this_.EVENT_DATETIME<='2019-11-21 00:00:00'
GROUP BY COMPANY_ID HAVING COMPANY_ID = 1;
它又回到了大约1到1.5秒。问题是我们可能有不止一个这样的查询,而这些查询是由Hibernate标准生成的,这些标准不支持这样的查询,因此我的解决方案在现实生活中无法工作
更新:
MySQL 5.7
在40秒内解释12个月查询1050757行
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "673838.60"
},
"table": {
"table_name": "this_",
"access_type": "ref",
"possible_keys": [
"PRIMARY",
"FK_EVENT_COMPANY",
"IX_REFERENCE",
"IX_DATE_TIME",
"EVENT_DATETIME",
"IDX_CE_COMPANY_TYPE",
"IDX_CE_COMPANY_DATE",
"IDX_CE_DATE_COMPANY"
],
"key": "FK_EVENT_COMPANY",
"used_key_parts": [
"COMPANY_ID"
],
"key_length": "4",
"ref": [
"const"
],
"rows_examined_per_scan": 2698153,
"rows_produced_per_join": 1135826,
"filtered": "42.10",
"cost_info": {
"read_cost": "134208.00",
"eval_cost": "227165.40",
"prefix_cost": "673838.60",
"data_read_per_join": "1G"
},
"used_columns": [
"EVENT_ID",
"COMPANY_ID",
"EVENT_DATETIME"
],
"attached_condition": "((`test`.`this_`.`EVENT_DATETIME` >= '2018-10-22 00:00:00') and (`test`.`this_`.`EVENT_DATETIME` <= '2019-11-21 00:00:00'))"
}
}
}
解释10个月的查询
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "634047.16"
},
"table": {
"table_name": "this_",
"access_type": "range",
"possible_keys": [
"PRIMARY",
"FK_EVENT_COMPANY",
"IX_REFERENCE",
"IX_DATE_TIME",
"EVENT_DATETIME",
"IDX_CE_COMPANY_TYPE",
"IDX_CE_COMPANY_DATE",
"IDX_CE_DATE_COMPANY"
],
"key": "IDX_CE_DATE_COMPANY",
"used_key_parts": [
"EVENT_DATETIME"
],
"key_length": "9",
"rows_examined_per_scan": 1578860,
"rows_produced_per_join": 789430,
"filtered": "50.00",
"using_index": true,
"cost_info": {
"read_cost": "476161.16",
"eval_cost": "157886.00",
"prefix_cost": "634047.16",
"data_read_per_join": "1G"
},
"used_columns": [
"EVENT_ID",
"COMPANY_ID",
"EVENT_DATETIME"
],
"attached_condition": "((`test`.`this_`.`COMPANY_ID` = 1) and (`test`.`this_`.`EVENT_DATETIME` >= '2019-01-22 00:00:00') and (`test`.`this_`.`EVENT_DATETIME` <= '2019-11-21 00:00:00'))"
}
}
}
有趣的是,第一个12个月的慢速查询在附加的\u条件中不显示公司\u ID,而第二个10个月的查询附加的\u条件检查公司\u ID
分析表的建议并没有改变它看起来的任何东西
更新2:
解释MySQL 5.1不支持JSON格式需要1.3秒
1 SIMPLE this_ range FK_EVENT_COMPANY,IX_DATE_TIME,EVENT_DATETIME,IDX_CE_COMPANY_TYPE,IDX_CE_COMPANY_DATE IDX_CE_COMPANY_DATE 16 NULL 2018704 Using where; Using index
查询计划器可能根据可用的统计信息做出错误的决策。您可以尝试运行ANALYZE来重建统计数据,并为计划人员提供更好的数据。请注意,ANALYZE在快速运行时会阻塞表 更新 在阅读MySQL文档时,我发现以下段落: 在MySQL 5.7.18之前,InnoDB通过扫描聚集索引处理SELECT COUNT*语句。从MySQL 5.7.18开始,InnoDB通过遍历最小的可用辅助索引来处理SELECT COUNT*语句,除非索引或优化器提示指示优化器使用不同的索引。如果不存在次索引,则扫描聚集索引 参考: 这意味着计数行为在您使用的版本上发生了完全的变化。这或许可以解释这种差异 最佳指标为
INDEX(COMPANY_ID, EVENT_DATETIME, EVENT_ID) -- in this order
我觉得您的日期范围是1年+一天+1秒。这是故意的吗
如果EVENT_ID是主键,请提供SHOW CREATE TABLE,那么COUNTDISTINCT EVENT_ID可以是COUNT*。但查询似乎是由hibernate生成的,不确定是否可以添加索引提示。在这两个版本上运行explain并将结果发布在此处。解释将显示查询计划,您将能够比较它们。我指的是MySQL 5.1和5.7中的解释。。因此,我们可以比较两个版本的查询计划器的决定。请提供SHOW CREATE TABLE,而不是试图用散文来描述它。5.7的哪个版本?谢谢您的建议。我尝试过分析表,但这似乎没有改变任何东西。5.7.18 changelog:SELECT COUNT*性能在某些情况下会下降,因为MySQL 5.7.2中引入了一个修改,导致InnoDB通过遍历聚集索引而不是较小的二级索引来计算行数。修改被恢复。错误23046302,错误80580