2016-08-10 81 views
1

我對「IS NULL」MySQL檢查表示懷疑。我有這2個查詢。第一個在大約300秒內運行。第二個運行不到1秒!爲什麼這個mysql查詢(使用null檢查)比另一個更慢?

慢查詢:

SELECT count(distinct(u.id)) 
FROM ips_usuario AS u 
JOIN ips_fatura AS f 
    ON ((u.id = f.ips_usuario_id) OR 
     (u.ips_usuario_id_titular IS NOT NULL AND 
     u.ips_usuario_id_titular = f.ips_usuario_id)); 

enter image description here

快速查詢:

SELECT count(distinct(u.id)) 
FROM ips_usuario AS u 
JOIN ips_fatura AS f 
    ON ((u.id = f.ips_usuario_id) OR 
     (u.ips_usuario_id_titular = f.ips_usuario_id)); 

enter image description here

所有連接條件使用外鍵索引列。表ips_usuario有大約20,000條記錄,表ips_fatura有大約500.000條記錄。

+0

這真是奇怪的結果,你確定它不是因爲頁面緩存? – Arnial

+0

是的,我確定! –

回答

0

我很驚訝,要麼是快。我建議用exists替換它們:

SELECT COUNT(*) 
FROM ips_usuario u 
WHERE EXISTS (SELECT 1 FROM ips_fatura f WHERE u.id = f.ips_usuario_id) OR 
     EXISTS (SELECT 1 FROM ips_fatura f WHERE u.ips_usuario_id_titular = f.ips_usuario_id); 

而對於第二:

SELECT COUNT(*) 
FROM ips_usuario u 
WHERE EXISTS (SELECT 1 FROM ips_fatura f WHERE u.id = f.ips_usuario_id) OR 
     (u.ips_usuario_id_titular IS NOT NULL AND 
     EXISTS (SELECT 1 FROM ips_fatura f WHERE u.ips_usuario_id_titular = f.ips_usuario_id) 
    ) 

對於這兩個,你希望兩個指標:ips_fatura(ips_usuario_id)ips_fatura(ips_usuario_id_titular)。您可以檢查解釋以確保EXISTS正在使用該索引。如果不是這樣,MySQL的的新版本使用索引IN

SELECT COUNT(*) 
FROM ips_usuario u 
WHERE u.id IN (SELECT f.ips_usuario_id FROM ips_fatura f) OR 
     u.ips_usuario_id_titular IN (SELECT f.ips_usuario_id FROM ips_fatura f); 

在這兩種情況下(EXISTSIN)的目標是做一個「半聯接」。也就是說,只用一場比賽而不是全部比賽來罰球。這是一個重要的效率,因爲它允許查詢避免重複刪除。

我會推測這個問題是or的優化 - 通常會導致效率低下的算法JOIN。但是,也許MySQL在你的第一個案例中很聰明。但是在外部桌子上增加了IS NULL將其拋棄。

+0

奇怪的事情(至少對我來說)是「快速」查詢(使用「爲空」)不會爲第二個表使用任何索引,但會檢查相同數量的行並且工作速度提高300倍。 – Arnial

+0

爲什麼不使用左連接?存在的查詢通常表現不佳。 – TaylorN

+0

@TaylorN。 。 。你爲什麼要使用'LEFT JOIN'?首先,這將把所有東西都保存在第一個表格中。其次,它可能會產生重複,造成需要重複刪除。 –

相關問題