2012-02-17 12 views
1

なぜ私のクエリのパフォーマンスがひどいのかを調べようと1日中困惑しています。非常にシンプルですが、実行に15分以上かかります(その段階でクエリを中断します)。私は200万を超えるレコードを持つテーブルに参加しています。MySQL JOINのパフォーマンスが極端に悪い

これは選択です:

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 

これはこれは、スキーマある

| 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 | 

をEXPLAINです:

# 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) 
); 

いくつかの非常に重要なことに注意してください。 - MessageIDは 'audit'または 'alerts'の1:1ではありません。 MessageIDは1つのテーブルに存在することはできますが、他のテーブルに存在することはできません。または両方に存在する可能性があります(これは自分の参加の目的です)。私のテストDBには、がありません。どちらもMessageIDのがあります。言い換えれば、私のクエリは0としてカウント230万レコードを返します。

「audit」テーブルと「alert」テーブルは、MessageIDをvarchar(255)として使用していました。私はそれが結合を修正することを期待して 'メッセージ'テーブルを作成しました。実際にはが悪化しました以前は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

1

サブクエリに参加しています。

サブクエリの結果は事実上一時的なテーブルです。クエリの実行計画には<derived2>が含まれています。あなたがそこに見ることができるように、それらは一時的なものであるため、索引付けされていません。

2番目のクエリの結果に結合するのではなく、結合を使用して1つの単位としてクエリを実行する必要があります。

EDIT:Andrewは、2つの手順ではなく、通常の結合クエリで作業を行う方法の例として、an answerを投稿しました。

関連する問題