我试图在MySQL上优化查询,运行大约需要15-20秒。我的数据表有大约10M行,查询尝试返回68,000条记录,这些记录匹配144个“运行”字段和35个“名称”字段。因为查询使用了两个in子句,所以我的索引似乎没有那么大的帮助。
以下是查询:
select * from data d where
d.data_type='Result' and
(d.run in ('8a7aee1f2a6232b1012a624da9201b92', '8a7aee1f2a6232b1012a625432a314ef' ,
... [144 runs]
)) and (d.name like 'itema[%]' or d.name like 'itemb[%]')
这是表格定义
CREATE TABLE `data` (
`data_type` varchar(31) NOT NULL,
`id` char(32) NOT NULL,
`entry_time` datetime default NULL,
`name` varchar(255) NOT NULL,
`step` int(11) default NULL,
`value` double NOT NULL,
`run` char(32) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK2EEFAA8ECCC6F3` (`run`),
KEY `data2` (`run`,`step`),
KEY `data3` (`data_type`,`name(10)`,`run`),
CONSTRAINT `FK2EEFAA8ECCC6F3` FOREIGN KEY (`run`) REFERENCES `run_archive` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
说明告诉我查询正在使用密钥数据。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE d range FK2EEFAA8ECCC6F3,data2,data3 data3 223 NULL 113271 Using where
我曾经运行144次查询(每次运行一次)。它似乎是执行一个查询的速度的两倍,但仍然太慢。
优化建议?我的想法是:
找到一个加速
的魔术指数
这个
非正规化数据(它是 容易摆脱奔跑,但是 这个名字更难了)
分裂 不同表格之间的数据 (很难用我的Java / Hibernate 的方法)
或者我只是在这里问不可能?
编辑:事实证明,最大的修复是增加我的innodb_buffer_pool的大小。执行此操作后,查询大约减少了1.5秒。我已经标记为“回答”一个修正案,稍微改善了它。
答案 0 :(得分:1)
考虑将result
记录从data
表中分离出去?我没有看到你result
的百分比,但也许值得在你的Prod数据库的Dev副本中进行基准测试。
你可以FK那些run
值吗?如果它们可以重用(?),也许可以创建一个Run
表?我的猜测是144个字符串匹配,即使是索引,也比int
或smallint
慢。同样,对这个建议或任何建议进行基准测试,显然会证明这一理论。
在name
属性中不包含like子句时,查询计划的差异是什么样的?
答案 1 :(得分:0)
根据run
上条件的选择性,提供索引
data_type, run, name(10)
在索引的早期提供用于前缀匹配的列的麻烦在于它在索引中分散匹配的行,需要从磁盘读取更大的索引部分。
此外,对运行的id使用较小的数据类型将减少索引大小并加快比较。这是一个不断改进的因素,但无论如何都值得。