mysql - 没有适当索引的长时间运行查询

时间:2018-04-29 14:56:58

标签: mysql performance optimization indexing query-optimization

这个查询在生产中运行大约15个小时,我正在寻找改进的替代方案,

我认为可能有所帮助的一些改进在这里被评论:

SELECT  table1.*
    FROM  table1
    WHERE  UPPER(LEFT(table1.cloumn1, 1)) IN ('A', 'B')
      AND  table1.cloumn2 = 'N' /* add composite index for cloumn2,
        column3 */
      AND  table1.cloumn3 != 'Y'
      AND  table1.id IN (
        SELECT  MAX(id)
            FROM  table1
            GROUP BY  column5,column6
                        ) /* move this clause to 2nd after
    where  */
      AND  table1.column4 IN (
        SELECT  column1
            FROM  table2
            WHERE  column2 IN ('VALUE1', 'VALUE2')
              AND  (SUBSTRING(column3,6,1) = 'Y'
                      OR  SUBSTRING(column3,25,1) = 'Y')
                          ) /* move this clause to 1st after
    where  */
      AND  (table1.column5,table1.column6) NOT IN (
        SELECT  column1, column2
            FROM  table3
            WHERE  table3.column3 IN ('A', 'B')/* add index for this column*/
           )
      AND  DATE_FORMAT(timstampColumn, '%Y/%m/%d') > DATE_ADD(CURRENT_DATE,
                INTERVAL - 28 DAY)) /* need index  ON this col? */ ;

感谢任何意见/建议。

更新:只更新过滤顺序,查询性能提高到~28秒,在添加一些索引并将一些子查询替换为连接后将在此处更新

2 个答案:

答案 0 :(得分:1)

假设您可以添加有用的索引(这将有助于您的某些检查),那么可以尝试尽早排除行。

我怀疑你在table1上为每个column5 / column6组合排了很多行。如果您可以尽早获得每个中的最新内容(即,使用您加入的子查询),那么您可以在需要检查任何非索引的WHERE子句之前从table1中排除大多数行。您还可以通过对table3上的子查询进行进一步连接来排除其中一些。

未经测试,但如果我对您的数据库结构的假设是正确的,那么这可能是一个改进: -

SELECT table1.* 
FROM 
(
    SELECT MAX(table1.id) AS max_id
    FROM table1 
    INNER JOIN 
    (
        SELECT DISTINCT column1, column2 
        FROM table3
        WHERE table3.column3 IN ('A', 'B')
        AND DATE_FORMAT(timstampColumn, '%Y/%m/%d') > DATE_ADD(CURRENT_DATE, INTERVAL - 28 DAY)
    ) sub0_0
    ON table1.column5 = sub0_0.column1
    AND  table1.column6 = sub0_0.column2
    WHERE (table1.cloumn1 LIKE 'A%' OR table1.cloumn1 LIKE 'B%')
    AND table1.cloumn2 = 'N'
    AND table1.cloumn3 != 'Y'
    GROUP BY table1.column5,
            table1.column6
) sub0
INNER JOIN table1
ON table1.id = sub0.max_id
INNER JOIN
(
    SELECT DISTINCT column1 
    FROM table2
    WHERE column2 IN ('VALUE1', 'VALUE2') 
    AND (SUBSTRING(column3,6,1) = 'Y' 
    OR SUBSTRING(column3,25,1) = 'Y')
) sub1
ON table1.column4 = sub1.column1

答案 1 :(得分:0)

(看SHOW CREATE TABLE可能有帮助。)

AND  DATE_FORMAT(timstampColumn, '%Y/%m/%d') > DATE_ADD(CURRENT_DATE,
            INTERVAL - 28 DAY))

不能使用索引;这可能是等价的:

AND  timstampColumn > CURRENT_DATE - INTERVAL 28 DAY

请提供EXPLAIN

您使用的是哪个版本?

它可能(依赖于版本)帮助将IN ( SELECT ... )子句转换为'派生'表:

JOIN ( SELECT ... ) ON ...

WHERE (x,y) IN ...未得到很好的优化。他们有什么类型的价值观?

使用* _ci排序规则,

UPPER(LEFT(table1.cloumn1, 1)) IN ('A', 'B')

可以做到:

LEFT(table1.cloumn1, 1) IN ('A', 'B')

这对性能没有显着帮助。最好不要拆分列进行测试。

这可能会使用涉及cloumn1的索引:

    table1.cloumn1 >= 'A'
AND table1.cloumn1 <  'C'

事物的顺序和在一起很少很重要。 INDEX中的顺序可以产生很大的不同。