2016-04-24 10 views
0

私は時間がかかりすぎていました(32分)ので、他の方法を試してみました。MySQLの最適化。なぜoption2がoption1よりも速いのですか

私はようやく5秒以内に別のものを書きました 問題は私の最適化を理解できないことです。

誰かがそれがはるかに速くなる方法を説明することができます。

hugeTableが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 

があり、ここでより多くのステップとまったく同じ要求を行うための方法ですが、道より高速を持っている494 500行

を持っています:

-- 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レベルを上げるのに役立ちます。

+0

50万行のうち1000行を更新するのに5秒はかかりません。しかし、根本的な問題は、簡単な結合ではなくサブクエリの使用と一緒に索引付けの欠如であると思われます。 EXPLAIN(および関連するすべてのテーブルの適切なCREATEステートメント)を使用すると、より多くのことがわかります。 – Strawberry

+0

両方のテーブルはキーもインデックスもなく単純です。この質問では、私は5秒より早くしようとはしていません。最初の方法が32分かかる理由を理解したい。 –

答えて

0

dstに複合インデックスを追加します。INDEX(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 ...)は、暗黙的なテンポラリテーブルに 'マテリアライズされている場合もあります。
  • このようなマテリアライズド・サブクエリには索引が作成されている場合と作成されていない場合があります。
  • dstまたはsrcのいずれかに適切なインデックスがない場合、「エフォート」の量は2つのテーブルのサイズの積になります。ケース2では、dstがはるかに小さいことに注意してください。 (これはあなたが探している答えかもしれません)
  • テーブルがRAMに完全にキャッシュされていない場合、人為的に他のI/Oよりも多くなる可能性があります。 I/Oバインドされたクエリは、同じクエリがRAMに完全にキャッシュされている場合、クエリの10倍の速度です。 (これは答えが少ない可能性がありますが、答えの一部である可能性があります)
  • 3テーブルUPDATEを使用すると、おそらく上記の問題のいくつかが解消されます。そして、それはタイミング差をなくす(またはしない)かもしれない。

さらに議論については、

  • MySQLバージョン
  • SHOW CREATE TABLEを提供してください - 各テーブル
  • EXPLAIN UPDATE ...用 - 各テーブルにinnodb_buffer_pool_size
  • SHOW TABLE STATUSどのくらいです
  • - - 更新ごとに - 少なくとも5.6必要です
  • テーブルの何パーセントが(id2 = inputId2)ですか?
+0

ありがとうございます。しかし、私の質問はそれをより速くする方法ではありません。私が知りたいのは、2番目のメソッドが5秒かかるときに表示される最初のメソッドが32分かかる理由です。 –

+0

@m_pOatrixこの場合、答えは「インデックスがないため」です。索引の欠落は、1000行の表よりも50万行の表のほうが重要です。 – Strawberry

+0

私はそれを理解しています。インデックスは素晴らしいと便利です。しかし、私は2つの質問の速度の違いを理解したい。 32分対5秒(同じ表、同じ結果)。インデックスを追加すると、両方のクエリは高速になりますが、他のクエリとはまったく異なります。おそらく24分対1秒。テーブルではなくクエリに注目してください。 –

関連する問題