[英]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;
使用多表UPDATE
而不是= ( SELECT ...)
代替OR
,編寫兩個單獨的UPDATEs
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.