优化SQL查询

Fra*_*cis 4 mysql join

我正在尝试优化这个慢查询(> 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秒).

Dav*_*itt 6

WHERE条款中最具选择性的部分是什么?也就是说,哪个条件从结果集中删除了最可能的项目?

我猜它是mtu.ts过滤器.如果这是真的,你还应该索引mtu.ts列并尝试以可以使用索引的方式约束该列; 例如,通过使用BETWEEN运算符.

其他提示:

  • 将join子句直接附加到连接JOIN ... ON (),这使得查询更容易阅读,无论是对于人类还是优化器
  • 避免在查询中计算常量,例如 YEAR(NOW())
  • 避免在WHERE子句中选择列的功能,例如MONTH(mtu.ts).这减少了大量使用指数的可能性.
  • 规范化您的数据以避免套管问题mtu.dept = 'GUN' OR mtu.dept = 'gun'; 桌子上的单个UPDATE mtu SET dept = lower(dept)和适当CHECK dept = lower(dept)的内容将有助于避免这种疯狂.