2012-02-17 114 views
1

我一直在搞亂整天試圖找到爲什麼我的查詢性能很糟糕。這非常簡單,但可能需要15分鐘才能執行(我在該階段中止查詢)。我加入了一張有超過200萬條記錄的表格。MySQL加入性能極差

這是選擇

SELECT 
    audit.MessageID, alerts.AlertCount 
FROM 
    audit 
LEFT JOIN (
     SELECT MessageID, COUNT(ID) AS 'AlertCount' 
     FROM alerts 
     GROUP BY MessageID 
    ) AS alerts ON alerts.MessageID = audit.MessageID 

這是EXPLAIN

| id | select_type | table  | type | possible_keys | key     | key_len | ref | rows | filtered | Extra  | 
| 1 | PRIMARY  | AL   | index | NULL   | IDX_audit_MessageID | 4  | NULL | 2330944 | 100.00 | Using index | 
| 1 | PRIMARY  | <derived2> | ALL | NULL   | NULL     | NULL | NULL | 124140 | 100.00 |    | 
| 2 | DERIVED  | alerts  | index | NULL   | IDX_alerts_MessageID | 5  | NULL | 124675 | 100.00 | Using index | 

這是模式

# Not joining, just showing types 
CREATE TABLE messages (
    ID     int NOT NULL AUTO_INCREMENT, 
    MessageID   varchar(255) NOT NULL, 
    PRIMARY KEY (ID), 
    INDEX IDX_messages_MessageID (MessageID) 
); 

# 2,324,931 records 
CREATE TABLE audit (
    ID     int NOT NULL AUTO_INCREMENT, 
    MessageID   int NOT NULL, 
    LogTimestamp  timestamp NOT NULL, 
    PRIMARY KEY (ID), 
    INDEX IDX_audit_MessageID (MessageID), 
    CONSTRAINT FK_audit_MessageID FOREIGN KEY(MessageID) REFERENCES messages(ID) 
); 

# 124,140 
CREATE TABLE alerts (
    ID     int NOT NULL AUTO_INCREMENT, 
    AlertLevel   int NOT NULL, 
    Text    nvarchar(4096) DEFAULT NULL, 
    MessageID   int DEFAULT 0, 
    PRIMARY KEY (ID), 
    INDEX IDX_alert_MessageID (MessageID), 
    CONSTRAINT FK_alert_MessageID FOREIGN KEY(MessageID) REFERENCES messages(ID) 
); 

需要注意一些非常重要的事項 - 'audit'或'alerts'中的MessageID不是1:1; MessageID可以存在於一個表中,但不能存在於另一個表中,或者可以存在於兩者中(這是我加入的目的);在我的測試數據庫中,都沒有的MessageID存在。換句話說,我的查詢將返回230萬記錄,其中0作爲計數。

另一件需要注意的是用於使用MessageID作爲varchar(255)的'audit'和'alert'表。我創建了'消息'表,期望它能修復連接。它實際上使其更糟糕。以前,它需要78秒,現在,它永遠不會返回。

我對MySQL有什麼想法?

回答

1

子查詢對於MySQL引擎來說非常難以優化。請嘗試:

SELECT 
    audit.MessageID, COUNT(alerts.ID) AS AlertCount 
FROM 
    audit 
LEFT JOIN alerts ON alerts.MessageID = audit.MessageID 
GROUP BY audit.MessageID 
+0

解決了這個問題。謝謝謝謝!如果可以的話,我會給你+10。 – Blazes 2012-02-17 16:37:28

1

您正在加入子查詢。

子查詢結果實際上是一個臨時表 - 請注意查詢執行計劃中的<derived2>。正如你可以看到的那樣,它們沒有被索引,因爲它們是短暫的。

您應該使用連接將查詢作爲單個單元執行,而不是連接到第二個查詢的結果。

編輯:安德魯已發佈an answer與一個例子如何做你的工作在一個正常的聯接查詢,而不是在兩個步驟。