2010-10-11 144 views
3

我遇到了一個查詢「太長」。該查詢在10個左右表格之間有50多個左連接。爲了簡要概述數據庫模型,連接的表格是存儲特定數據類型(例如:date_fields,integer_fields,text_fields等)的數據的表格,每個表格都有一個值列,一個「數據字段」和一個票證號碼。該查詢是基於「票證」與其「數據字段」之間的關聯表以編程方式構建的。優化在同一個表上使用多個左連接的查詢

的加入語句看起來類似以下內容:

...FROM tickets t 
LEFT JOIN ticket_text_fields t001 ON(t.id=t001.ticket_id AND t001.textfield_id=7) 
... 
LEFT JOIN ticket_date_fields t056 ON(t.id=t056.ticket_id AND t056.datafield_id=434) 

在使用上查詢說明顯示如下:

1 SIMPLE t  ref idx_dataset_id     idx_dataset_id 5 const 2871 Using where; Using temporary; Using filesort 
1 SIMPLE t001 ref idx_ticket_id,idx_datafield_id idx_ticket_id 5 t.id 5 
... 
1 SIMPLE t056 ref idx_ticket_id,idx_datafield_id idx_ticket_id 5 t.id 8 

我可以採取什麼方向來調整這個查詢?所有指標似乎都已到位。也許應該減少t表(門票)行號(2871)。剩下多少個連接太多?數據字段表是否應該只加入一次,然後爲每個數據查詢所需的數據?

回答

7

您正在使用名爲Entity-Attribute-Value的可怕antipattern變體。您將屬性存儲在單獨的行中,因此如果您想重新構建看起來像傳統數據行的東西,則需要爲每個屬性創建一個連接。

這並不奇怪,這會創建一個包含50個連接的查詢。這對於大多數數據庫高效運行來說太多了(您尚未識別出您正在使用哪個數據庫)。最終,您還需要其他幾個屬性,並且您可能會超出數據庫的一些體系結構限制。

解決方法是:不重建SQL中的行。

而是將屬性查詢爲多行,而不是試圖將它們組合到一行中。

SELECT ... FROM tickets t 
INNER JOIN ticket_text_fields f ON t.id=f.ticket_id 
WHERE f.textfield_id IN (7, 8, 9, ...) 
UNION ALL 
SELECT ... FROM tickets t 
INNER JOIN ticket_date_fields d ON t.id=d.ticket_id 
WHERE d.datafield_id IN (434, 435, 436, ...) 

然後你必須寫在你的應用程序遍歷所產生的行集功能,並逐一收集屬性到應用空間中的對象,這樣的話,如果它是一個單一的實體,您可以使用它。

+1

偉大的迴應比爾!我不能在不改變模式的情況下想到一個好的解決方案,所以我不斷重新加載這個問題,看看別人會說些什麼。我喜歡你的解決方案。 – 2010-10-11 17:32:09

+0

同意。感謝您的信息和解決方案! – 2010-10-12 17:29:56

0

了更清晰的查詢我會用這樣的:

SELECT ... FROM tickets as t 
JOIN ticket_text_fields as txt ON t.id = txt.ticket_id 
JOIN ticket_date_fields as dt ON t.id = dt.ticket_id 
WHERE txt.textfield_id IN (...) 
AND dt.datefield_id IN (...) 

加盟將可能離開了,但是這取決於你的數據的結構。
查詢中沒有聯合,只有兩個聯接