我正在尝试优化这个慢查询(> 2s)
SELECT COUNT(*)
FROM crmentity c, mdcalls_trans_activity_update mtu, mdcalls_trans mt
WHERE (mtu.dept = 'GUN' OR mtu.dept = 'gun') AND
mtu.trans_code = mt.trans_code AND
mt.activityid = c.crmid AND
MONTH(mtu.ts) = 2 AND
YEAR(mtu.ts) = YEAR(NOW()) AND
c.deleted = 0 AND
c.smownerid = 28
Run Code Online (Sandbox Code Playgroud)
这是我使用EXPLAIN时的输出:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE c index_merge PRIMARY,crmentity_smownerid_idx,crmentity_deleted_smownerid_idx,crmentity_smownerid_deleted_idx crmentity_smownerid_idx,crmentity_deleted_smownerid_idx 4,8 NULL 91 Using intersect(crmentity_smownerid_idx,crmentity_deleted_smownerid_idx); Using where; Using index
1 SIMPLE mt ref activityid activityid 4 pharex.c.crmid 60
1 SIMPLE mtu ref dept_idx dept_idx 5 const 1530 Using where
Run Code Online (Sandbox Code Playgroud)
它使用我创建的索引(dept_idx),但是对于1,380,384条记录的数据集运行查询仍需要2秒多的时间.还有另一种以最佳方式表达此查询的方法吗?
更新:使用David的建议,查询现在只有几毫秒,而不是运行超过2秒(实际上,MySQL版本5.0上的51秒).
该WHERE条款中最具选择性的部分是什么?也就是说,哪个条件从结果集中删除了最可能的项目?
我猜它是mtu.ts过滤器.如果这是真的,你还应该索引mtu.ts列并尝试以可以使用索引的方式约束该列; 例如,通过使用BETWEEN运算符.
其他提示:
JOIN ... ON (),这使得查询更容易阅读,无论是对于人类还是优化器YEAR(NOW())MONTH(mtu.ts).这减少了大量使用指数的可能性.mtu.dept = 'GUN' OR mtu.dept = 'gun'; 桌子上的单个UPDATE mtu SET dept = lower(dept)和适当CHECK dept = lower(dept)的内容将有助于避免这种疯狂.