簡體   English   中英

MySQL的OR和ISNULL性能差

[英]MySQL poor OR and ISNULL performance

我對某些奇怪的mysql性能行為感到非常驚訝。 我的以下查詢大約需要3個小時才能運行:

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”列不為空,則應使用它;否則,應使用“ id”列。

如果我將查詢分為兩個查詢,則每個查詢需要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”或“ null checks”問題( 為什么這個mysql查詢(帶有null檢查)比另一個查詢慢呢? )。

ips_invoice表大約有400.000條記錄,ips_user_unit_locality大約100.000條記錄,ips_user大約35.000條記錄。

我在Ubuntu Amazon EC2實例中運行MySQL 5.5.49。

那么,第一個和第二個查詢出了什么問題? 造成明顯性能差異的原因是什么?

第一個和第二個查詢沒有什么“錯誤”。 但是,當您使用or處於join條件(或等效地,相關子查詢條件)中時,引擎通常無法使用索引。

這使得一切真的很慢。

您似乎至少了解一種解決方法,所以我不會提出其他建議。

編輯:

我將注意到您的查詢並沒有完全按照您在文本中指定的內容進行操作。 它獲取兩個用戶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;
  1. 使用多表UPDATE而不是= ( SELECT ...)

  2. 代替OR ,編寫兩個單獨的UPDATEs

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM