MySQL优化。为什么option2比option1快得多

时间:2016-04-24 06:31:43

标签: mysql python-2.7 optimization

我写了一个查询,它花了太多时间(32分钟),所以我尝试了其他方法来更快地找到一个。

我终于写了另一个不到5秒 问题是我不了解我的优化。

有人可以解释它是如何快得多的。

hugeTable有494 500行

smallTable1有983行

smallTable2有983行

cursor.execute('UPDATE hugeTable dst,
    (
     SELECT smallTable1.hugeTableId, smallTable2.valueForHugeTable 
     FROM smallTable2
     INNER JOIN smallTable1 ON smallTable1.id = smallTable2.id
     -- This select represent 983 rows
)src
    SET dst.columnToUpdate = src.valueForHugeTable 
    WHERE dst.id2 = %s AND dst.id = src.hugeTableId;', inputId2)

-- Condition : dst.id2 = %s alone target 983 rows.
-- Combinasion of : dst.id2 = %s AND dst.id = src.hugeTableId target a single unique row.

-- This query takes 32 minutes

这是一种使用更多步骤执行完全相同的请求的方法,但速度更快:

-- First create a temporary table to hold (983) rows from hugeTable that has to be updated
cursor.execute('CREATE TEMPORARY TABLE tmpTable AS 
             SELECT * from hugeTable 
             WHERE id2 = %s;', inputid)          

-- Update the rows into tmpTable instead of into hugeTable
cursor.execute('UPDATE tmpTable dst, 
                (
                    SELECT smallTable1.hugeTableId, smallTable2.valueForHugeTable
                    FROM smallTable2 
                    INNER JOIN smallTable1 ON smallTable1.id = smallTable2.id
                    -- This select represent 983 rows 
                )src 
                SET dst.columnToUpdate = src.valueForHugeTable
                WHERE dst.id = src.hugeTableId;')

-- Then delete the (983) rows we want to update
cursor.execute('DELETE FROM hugeTable WHERE id2 = %s;', inputId2)
-- And create new rows replacing the above deleled ones with rows from tmpTable
cursor.execute('INSERT INTO hugeTable SELECT * FROM tmpTable;')

-- This takes litle under 5 seconds.

我想知道为什么第一种方法需要花费很多时间。 理解这将有助于我获得新的MySql级别。

1 个答案:

答案 0 :(得分:0)

将复合索引添加到dstINDEX(id2, id)(按任意顺序)。

更多

案例1:

UPDATE  hugeTable dst, 
      ( SELECT  smallTable1.hugeTableId, smallTable2.valueForHugeTable
            FROM  smallTable2
            INNER JOIN smallTable1  ON smallTable1.id = smallTable2.id 
      )src SET dst.columnToUpdate = src.valueForHugeTable
    WHERE  dst.id2 = 1234
      AND  dst.id = src.hugeTableId;

案例2:

CREATE  TEMPORARY TABLE tmpTable AS 
SELECT  *
    from  hugeTable
    WHERE  id2 = 1234;
UPDATE  tmpTable dst, 
      ( SELECT  smallTable1.hugeTableId, smallTable2.valueForHugeTable
            FROM  smallTable2
            INNER JOIN smallTable1  ON smallTable1.id = smallTable2.id 
      )src SET dst.columnToUpdate = src.valueForHugeTable
    WHERE  dst.id = src.hugeTableId;

在不知道MySQL版本并看到EXPLAINs的情况下,我只能猜测它们为何如此不同......

  • 子查询( SELECT ... JOIN ... )可能会也可能不会被“物化”到隐式临时表中。 (较新的版本更擅长这样做。)
  • 这样的具体化子查询可能有也可能没有为其创建索引。 (同样,新版本更好。)
  • 如果dstsrc上没有足够的索引,那么'努力'的数量就是两个表大小的乘积。请注意,在案例2中,dst要小得多。 (这可能是您正在寻找的答案。)
  • 如果表没有完全缓存在RAM中,人工可能会涉及比其他更多的I / O.当I / O绑定查询完全缓存在RAM中时,它通常是同一查询的10倍。 (这不太可能是答案,但可能是答案的一部分。)
  • 拥有3个表UPDATE可能会消除上述一些问题。它可能(或可能不)消除时间差异。

如需进一步讨论,请提供

  • MySQL版本
  • SHOW CREATE TABLE - 针对每个表格
  • innodb_buffer_pool_size
  • 有多大
  • SHOW TABLE STATUS - 针对每个表格
  • EXPLAIN UPDATE ... - 每次更新 - 至少需要5.6
  • 该表中有多少百分比( id2 = inputId2 )