我有一個JPA ManyToMany關係的設置,它給了我三個重要的表格:我的Ticket表,我的Join表和我的Inventory表。他們是MySQL 5.1上的InnoDB表。相關位是:三種查詢比一種更快 - 我的聯接有什麼錯誤?
Ticket:
+--------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| Status | longtext | YES | | NULL | |
+--------+----------+------+-----+---------+----------------+
JoinTable:
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| InventoryID | int(11) | NO | PRI | NULL | | Foreign Key - Inventory
| TicketID | int(11) | NO | PRI | NULL | | Foreign Key - Ticket
+-------------+---------+------+-----+---------+-------+
Inventory:
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| TStampString | varchar(32) | NO | MUL | NULL | |
+--------------+--------------+------+-----+---------+----------------+
TStampStrings的形式爲 「YYYY.MM.DD HH:MM:SS Z」(例如, '22點27分57秒2010.03.19 GMT')。現在都直接創造的門票對應於某些特定小時TStampString,使SELECT COUNT(*) FROM Ticket;
相同SELECT COUNT(DISTINCT(SUBSTRING(TStampString, 1, 13))) FROM Inventory;
我希望做的是重組基礎上TStampString的分鐘的間隔一定的門票:(SUBSTRING( TStampString,1,16))。所以我剖析和測試INSERT INTO的SELECT ... SELECT語句:
EXPLAIN SELECT SUBSTRING(i.TStampString, 1, 16) FROM Ticket t JOIN JoinTable j
ON t.ID = j.TicketID JOIN Inventory i ON j.InventoryID = i.ID WHERE t.Status
= 'Regroup' GROUP BY SUBSTRING(i.TStampString, 1, 16);
+--+------+---+--------+-------------+-----+-----+----------+-------+-----------+
|id| type |tbl| type | psbl_keys | key | len | ref | rows | Extra |
+--+------+---+--------+-------------+-----+-----+----------+-------+-----------+
|1 | SMPL | t | ALL | PRI | NULL| NULL| NULL | 35569 | where |
| | | | | | | | | | +temporary|
| | | | | | | | | | +filesort |
|1 | SMPL | j | ref | PRI,FK1,FK2 | FK2 | 4 | t.ID | 378 | index |
|1 | SMPL | i | eq_ref | PRI | PRI | 4 | j.Invent | 1 | |
| | | | | | | | oryID | | |
+--+------+---+--------+-------------+-----+-----+----------+-------+-----------+
什麼,這意味着我是在票務每一行,MySQL的第一位是後來的加入決定的行由於WHERE子句而無效。運行時肯定是可惡的(30分鐘後我放棄了)。請注意,t.Status ='Regroup'移動到第一個JOIN子句並且沒有WHERE子句時不會更快。
但有趣的是,如果我在三個步驟手動運行此查詢,做什麼,我想優化會做,每一步幾乎立即返回:
--Step 1: Select relevant Tickets (results dumped to file)
SELECT ID FROM Ticket WHERE Status = 'Regroup';
--Step 2: Get relevant Inventory entries
SELECT InventoryID FROM JoinTable WHERE TicketID IN (step 1s file);
--Step 3: Select what I wanted all along
SELECT SUBSTRING(TStampString, 1, 16) FROM Inventory WHERE ID IN (step 2s file)
GROUP BY SUBSTRING(TStampString, 1, 16);
在我的特別表中,第一查詢給154結果,第二個創建206,598行,第三個查詢返回9198行。所有這些組合都需要大約2分鐘才能運行,最後一個查詢具有唯一的重要運行時間。
將中間結果轉儲到文件非常麻煩,更重要的是我想知道如何編寫我的原始查詢以使其運行合理。那麼,我如何構建這個三表連接,使其儘可能快地運行,我知道是可能的?
UPDATE:我在Status(16)上添加了前綴索引,它將我的EXPLAIN配置文件行分別更改爲153,378和1(因爲第一行有一個要使用的密鑰)。我的查詢的JOIN版本現在需要大約6分鐘,這是可以忍受的,但仍然比手動版慢很多。我仍然想知道爲什麼這個連接執行得非常不理想,但可能是因爲無法在錯誤的MySQL 5.1中創建獨立的子查詢。如果足夠的時間過去了,我會接受添加索引作爲我的問題的解決方案,雖然這不完全是我的問題的答案。
最後,我最終手動重新創建了磁盤上連接的每一步。成千上萬個文件中的每一個都有一千個查詢,其速度仍然比我的MySQL版本要快。但是由於這個過程對於外行來說是非常具體而且沒有幫助的,我接受了ypercube對Add(Partial)索引的回答。
是否'Status'列真的要'longtext'而不是一些較短的類型,比如' VARCHAR(255)'? – 2012-07-30 23:43:45
我剛剛注意到,發佈此問題時,我以爲我曾告訴JPA我想要一個VARCHAR(16),但我想它並沒有提示。儘管如此,不想將模式轉換爲生產。 – 2012-07-30 23:46:26
表是InnoDB還是MyISAM? – 2012-07-30 23:54:14