2016-10-02 5 views
0

私は奇妙なmysqlのパフォーマンスの動作に驚いています。私の次のクエリを実行するために約3時間を取っている:MySQLのORとISNULLのパフォーマンスが悪い

UPDATE ips_invoice AS f SET ips_locality_id = (
     SELECT ips_locality_id 
     FROM ips_user_unit_locality AS uul 
     JOIN ips_user AS u ON u.id = uul.ips_user_id 
     WHERE 
      (u.id = f.ips_user_id OR u.ips_user_id_holder = f.ips_user_id) AND 
      uul.date <= f.date 

     ORDER BY `date` DESC 
     LIMIT 1 
) 
WHERE f.ips_locality_id IS NULL; 

私はまた、次のいずれかを試してみましたが、同じ性能の結果を取得:ロジックは

UPDATE ips_invoice AS f SET ips_locality_id = (
     SELECT ips_locality_id 
     FROM ips_user_unit_locality AS uul 
     JOIN ips_user AS u ON u.id = uul.ips_user_id 
     WHERE 
      IFNULL(u.ips_user_id_holder, u.id) = f.ips_user_id 
      AND 
      uul.date <= f.date 

     ORDER BY `date` DESC 
     LIMIT 1 
) 
WHERE f.ips_locality_id IS NULL; 

されています:「ips_user_id_holder」の欄ではない場合null、私はそれを使用する必要があります、私は "ID"の列を使用する必要があります。

私は2つのクエリにクエリを分割する場合は、それぞれが実行するために15秒を取る:

 UPDATE ips_invoice AS f SET ips_locality_id = (
       SELECT ips_locality_id 
       FROM ips_user_unit_locality AS uul 
       JOIN ips_user AS u ON u.id = uul.ips_user_id 
       WHERE 
        u.ips_user_id_holder = f.ips_user_id 
        AND 
        uul.date <= f.date 

       ORDER BY `date` DESC 
       LIMIT 1 
     ) 
     WHERE f.ips_locality_id IS NULL; 

UPDATE ips_invoice AS f SET ips_locality_id = (
       SELECT ips_locality_id 
       FROM ips_user_unit_locality AS uul 
       JOIN ips_user AS u ON u.id = uul.ips_user_id 
       WHERE 
        u.id = f.ips_user_id 
        AND 
        uul.date <= f.date 

       ORDER BY `date` DESC 
       LIMIT 1 
     ) 
     WHERE f.ips_locality_id IS NULL; 

それは私が でのMySQLの「OR」または「ヌルチェック」で問題になった最初の時間ではありません比較的簡単なクエリ(Why this mysql query (with is null check) is so slower than this other one?)。

ips_invoiceテーブルは約400.000レコード、ips_user_unit_localityは約100.000レコード、ips_userは約35.000レコードです。

私はUbuntu Amazon EC2インスタンスでMySQL 5.5.49を実行しています。

したがって、最初と2番目のクエリで何が問題になっていますか?パフォーマンスの大幅な違いの原因は何ですか?

答えて

1

最初と2番目のクエリで「間違っている」ことは何もありません。ただし、join条件(またはそれに相当する相関サブクエリ条件)でorを使用すると、エンジンは通常インデックスを使用できません。

これはすべてを本当に遅くします。

あなたはそれを修正するための少なくとも1つの方法を理解しているようですので、私は何も提案しません。

EDIT:

私はあなたのクエリは、テキストで指定し、正確に何をしないことに注意します。 2つのユーザーIDのいずれかの最新の日付を取得します。 IDの優先順位付けが必要なようです。

UPDATE ips_invoice f 
    SET ips_locality_id = 
     COALESCE((SELECT ips_locality_id 
        FROM ips_user_unit_locality uul JOIN 
         ips_user u 
         ON u.id = uul.ips_user_id 
        WHERE u.ips_user_id_holder, f.ips_user_id AND 
         uul.date <= f.date 
        ORDER BY uul.date DESC 
        LIMIT 1 
       ), 
        (SELECT ips_locality_id 
        FROM ips_user_unit_locality uul 
        WHERE uul.ips_user_id = f.ips_user_id AND 
         uul.date <= f.date 
        ORDER BY uul.date DESC 
        LIMIT 1 
       ) 
       ) 
WHERE f.ips_locality_id IS NULL; 
+0

うわー、面白い別の方法。ありがとうございます! –

0
  1. 使用マルチテーブルUPDATE代わりに代わりOR

  2. = (SELECT ...)の2つの別々のUPDATEsを記述します。そうであれば、これはより多くのあなたが欲しいクエリです。

関連する問題