我有4臺MySQL數據庫(不止於此着呢,但只有這4個相關的問題),讓我們稱之爲A,B,C和D.這裏的架構:奇怪的MySQL連接行爲
CREATE TABLE A
(
pKey INT NOT NULL AUTO_INCREMENT,
name NVARCHAR(50),
PRIMARY KEY(pKey),
UNIQUE INDEX(name)
);
CREATE TABLE C
(
pKey INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(pKey)
);
CREATE TABLE B
(
pKey INT NOT NULL AUTO_INCREMENT,
aKey INT NOT NULL,
cKey INT NOT NULL,
PRIMARY KEY(pKey),
UNIQUE INDEX UniqueKey (aKey, cKey),
FOREIGN KEY(aKey) REFERENCES A(pKey),
FOREIGN KEY(cKey) REFERENCES C(pKey)
);
CREATE TABLE D
(
pKey INT NOT NULL AUTO_INCREMENT,
cKey INT NOT NULL,
PRIMARY KEY(pKey),
INDEX(cKey),
FOREIGN KEY(cKey) REFERENCES C(pKey)
);
我運行下面的查詢:
SELECT
--stuff...
FROM A
INNER JOIN B
ON A.pKey=B.aKey
INNER JOIN C
ON B.cKey=C.pKey
INNER JOIN D
ON D.cKey=C.pKey
WHERE
A.name=parameter_1;
麻煩的是,這是一臺服務器上運行一個大型數據庫,大多數表有100K +的記錄,它的情況並不少見一張桌子打破1000萬條記錄。一張桌子有超過2億條記錄。
撇開與MySQL的任何問題和架構(我卡與兩個),我越來越有當我使用這個查詢說明上面的查詢一些奇怪的行爲。由於這種行爲,我有幾個問題。我會先顯示奇怪的行爲。
如果我只是在MySql中解釋上面的查詢,那麼我會在EXPLAIN輸出的參考列中得到參考。但是,我需要將此查詢作爲較大查詢的子查詢來運行。 EXPLAINning較大查詢給了我這樣的事情以上查詢(這只是一個對應表在此查詢的較大查詢行):
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
| 1 | SIMPLE | A | const | PRIMARY,key1,key2 | key1 | 38 | | 1 | |
| 1 | SIMPLE | D | index | key3 | key3 | 12 | NULL | 73868 | Using index |
| 1 | SIMPLE | C | index | PRIMARY,key3 | PRIMARY | 8 | NULL | 1 | |
| 1 | SIMPLE | B | ref | key4,UniqueKey,key6 | key4 | 12 | const,DB.D.key3 | 1 | Using where; Using index |
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
MySQL是做兩點索引掃描和一個REF鍵入連接。如果我使用索引提示,我可以略微改善這一點,但只是略有改善。我之前說過,這個查詢是作爲一個子查詢運行的。下面是其他查詢的格式:
SELECT
--stuff
FROM
(
--sub-query1
) a
INNER JOIN
(
--the query I have a question about
) b
ON a.c1=b.c2
優化完全忽略表C中有利於做加入的兩個外鍵列,B.cKey = D.cKey的。 所以,這裏的問題1)爲什麼優化器忽略這樣的表C?
接下來,即使我使用索引提示,並且它忽略了表C,它仍然執行索引掃描以加入B和D,儘管有適當的索引。 爲什麼?
在上面的解釋中,它表明在表D中有73,868行,在這個問題時實際上有73,568行。其中一個查詢表(在這個問題中沒有顯示)有大約1億行,所以優化這個是相當重要的。對於完整查詢,行列的乘積約爲2.37E42。是的,我已經考慮了減少查詢中表的數量的方法;我需要獲取的信息需要每個我正在訪問的表,並且我無法更改數據庫的體系結構。
最後,我可以在這裏改變的唯一的東西是查詢和索引/約束。由於這是一個先前存在的系統,因此我一直堅持一切。 我還有其他方法可以更好地優化此操作嗎?
謝謝!
編輯:我定爲超級查詢的格式。
我添加了你建議的索引,並沒有區別。表C實際上具有更多列,即一個主鍵,並且我從這些列中選擇值。由於我不認爲這些附加列與JOIN操作有關,所以我沒有包含它們。 – wizard07KSU 2014-11-04 00:32:08