优化具有大值的{my} IN查询

时间:2017-11-12 07:21:29

标签: php mysql sql

我有一个像

这样的mysql查询
 SELECT `tbl_ticket`.`id`, `tbl_ticket`.`hd_user_username`, 
`tbl_ticket`.`hd_user_email`, `tbl_ticket`.`ticket_title`, 
`tbl_complain_type`.`complains` FROM `tbl_ticket` LEFT JOIN 
`tbl_ticket_complain` ON tbl_ticket_complain.ticket_id=tbl_ticket.id 
LEFT JOIN `tbl_complain_type` ON tbl_complain_type.id=tbl_ticket_complain.complain_id 
LEFT JOIN `tbl_assignment` ON tbl_assignment.ticket_id=tbl_ticket.id 
WHERE ((((`hd_user_username` LIKE '%searchterm%') 
AND (`tbl_assignment`.`id` IN ($array))) 
OR (`hd_user_email`='searchterm')) 
OR (`ticket_title`='searchterm')) OR (`tbl_complain_type`.`complains`='searchterm')

$array contains around 7000 values like `$array=array(1,2,3,..)`

此查询大约需要8秒钟才能执行。这个查询有替代解决方案吗? $ array的值来自另一个查询

select max(id) from tbl_assignment group by ticket_id

查询的缓慢是由于表之间的多个连接

2 个答案:

答案 0 :(得分:3)

如果数组中的值使用IN IN子句来自一个选择,你可以使用这个事实 IN子句相当于内部连接,因此您可以使用your_table_with_id和table.column之间的内部联接来匹配,例如:

  SELECT `
      tbl_ticket`.`id`
      , `tbl_ticket`.`hd_user_username`
      , `tbl_ticket`.`hd_user_email`
      , `tbl_ticket`.`ticket_title`
      , `tbl_complain_type`.`complains` 
  FROM `tbl_ticket` 
  LEFT JOIN `tbl_ticket_complain` ON tbl_ticket_complain.ticket_id=tbl_ticket.id 
  LEFT JOIN `tbl_complain_type` ON tbl_complain_type.id=tbl_ticket_complain.complain_id 
  LEFT JOIN `tbl_assignment` ON tbl_assignment.ticket_id=tbl_ticket.id 
  INNER JOIN your_table_with_id ON `tbl_assignment`.`id` = JOIN your_table_with_id.id
  WHERE ((((`hd_user_username` LIKE '%searchterm%') 
  OR (`hd_user_email`='searchterm')) 
  OR (`ticket_title`='searchterm')) OR (`tbl_complain_type`.`complains`='searchterm')

还要记住,使用IN子句的值的内容是有限的,并且在超出限制时失败

,在你的情况下

  SELECT `
      tbl_ticket`.`id`
      , `tbl_ticket`.`hd_user_username`
      , `tbl_ticket`.`hd_user_email`
      , `tbl_ticket`.`ticket_title`
      , `tbl_complain_type`.`complains` 
  FROM `tbl_ticket` 
  LEFT JOIN `tbl_ticket_complain` ON tbl_ticket_complain.ticket_id=tbl_ticket.id 
  LEFT JOIN `tbl_complain_type` ON tbl_complain_type.id=tbl_ticket_complain.complain_id 
  LEFT JOIN `tbl_assignment` ON tbl_assignment.ticket_id=tbl_ticket.id 
  INNER JOIN (
    select max(id) as id
    from tbl_assignment 
    group by ticket_id
  ) t ON `tbl_assignment`.`id` = t.id
  WHERE ((((`hd_user_username` LIKE '%searchterm%') 
  OR (`hd_user_email`='searchterm')) 
  OR (`ticket_title`='searchterm')) OR (`tbl_complain_type`.`complains`='searchterm'))

答案 1 :(得分:0)

这基本上是您的查询:

SELECT . . .
FROM tbl_ticket t LEFT JOIN 
     tbl_ticket_complain tc
     ON tc.ticket_id = t.id LEFT JOIN 
     tbl_complain_type tct
     ON tct.id = tc.complain_id LEFT JOIN
     tbl_assignment a
     ON a.ticket_id = t.id 
WHERE (((hd_user_username LIKE '%searchterm%' AND
         a.id IN ($array)
        ) OR
        `hd_user_email`='searchterm'
       ) OR
       ticket_title = 'searchterm'
     ) OR
     tct.complain` = 'searchterm';

性能问题与IN无关。实际上,MySQL会优化IN,如documentation

中所述
  

如果所有值都是常量,则根据类型评估它们   expr和排序。然后使用a完成对项目的搜索   二分搜索。这意味着,如果IN值列表,IN非常快   完全由常数组成。

你不会比带有常数的IN列表更快。

您的查询问题是OR s的字符串。优化器几乎不可能使用索引 - 因此必须创建完整的结果集然后过滤掉。

我很难看到如何在查询中改进这一点。有时,将查询拆分为更简单的块并使用unionunion all连接它们就可以了。您的条件有点难以理解,这使得这种方法对于局外人来说很难。