使用巨大的where子句优化SQL查询

时间:2018-12-30 14:32:15

标签: mysql sql query-performance

我正在使用Laravel的系统上工作,用户可以填充一些过滤器来获取所需的数据。 数据不是实时准备的,一旦设置了过滤器,就会将作业推送到队列,并且一旦查询完成,就会创建一个CSV文件。然后,用户会收到一封包含已创建文件的电子邮件,以便他们可以下载它。

我发现作业中花了30分钟以上的时间来处理一项作业,当我检查时发现一些用户创建的过滤器具有600多个值。

此过滤器值的翻译如下:

SELECT filed1, 
       field2, 
       field6 
FROM   table 
       INNER JOIN table2 
               ON table.id = table2.cid 
/* this is how we try not to give same data to the users again so we used NOT IN */ 
WHERE  table.id NOT IN(SELECT data_id 
                       FROM   data_access 
                       WHERE  data_user = 26) 
       AND ( /* this bit is auto populated with the filter values */ 
           table2.filed_a = 'text a' 
            OR table2.filed_a = 'text b' 
            OR table2.filed_a = 'text c' ) 

好吧,我没想到用户会疯狂地使用庞大的过滤器集进行微调。他们可以这样做,但是需要一种解决方案来使此查询更快。

一种方法是使用过滤器值动态创建一个临时表,并对INNER JOIN的查询进行隐蔽,但不确定是否会提高性能。 同样,鉴于在正常的一天中,系统将需要创建至少40个带有ish的临时表,然后再将其删除。从长远来看,这会成为另一个问题吗?

除临时表方法外,我想听听其他可能帮助我解决此问题的建议。

1 个答案:

答案 0 :(得分:2)

我建议这样编写查询:

SELECT ?.filed1, ?.field2, ?.field6  -- qualify column names (but no effect on performance)
FROM table t JOIN
     table2 t2
     ON t.id = t2.cid 

WHERE NOT EXISTS (SELECT 1
                  FROM data_access da
                  WHERE t.id = da.data_id AND da.data_user = 26
                 ) AND
     t2.filed_a IN ('text a', 'text b', 'text c') ;

然后,我将推荐索引。最可能:

  • table2(filed_a, cid)
  • table1(id)(如果id已经是主键,则可能不需要)
  • data_access(data_id, data_user)

您可以将其作为自己的查询进行测试。我不知道如何让Laravel产生这种效果(假设它符合您的性能目标)。