2013-07-18 59 views
2
CREATE TABLE Attributes (
    id  VARCHAR(40), 
    type VARCHAR(16), 
    data VARCHAR(2048), 
    PRIMARY KEY(id,type) 
);

這是我試圖運行的查詢的一般格式。一般的想法是,'對象'具有唯一的id,然後像JavaScript對象那樣具有鍵/值對。如何減少此查詢中連接表的數量?

SELECT a1.id, a1.data, a2.data, a3.data, a4.data, a6.data 
    FROM Attributes a1, Attributes a2, Attributes a3, Attributes a4, Attributes a5 
    LEFT JOIN Attributes a6 ON (a6.id=a5.id AND a6.type = 'Foreign Id') 
     WHERE a1.id=a2.id 
      AND a1.id=a3.id 
      AND a1.id=a4.id 
      AND a1.id=a5.id 
      AND a1.type = 'First Name' 
      AND a2.type = 'Middle Name' 
      AND a3.type = 'Last Name' 
      AND a4.type = 'Timestamp' 
      AND a5.type = 'Count' 
      AND a5.data = 'MY_ID' 

在此查詢中'Foreign Id'是一個可選屬性。問題是我得到

SELECT將檢查超過MAX_JOIN_SIZE行;檢查你的 WHERE並使用SET SQL_BIG_SELECTS = 1或SET MAX_JOIN_SIZE =#如果 SELECT沒問題。

我意識到我可以這麼說,但警告讓我擔心這個查詢的效率非常低。有沒有更好的方式來制定查詢?

回答

5

由於主鍵鍵是ID, Type你可以使用集合功能,並確保查詢仍然是確定的,降低了查詢0加入:

SELECT a.ID, 
     MAX(CASE WHEN a.type = 'First Name' THEN a.Data END) AS FirstName, 
     MAX(CASE WHEN a.type = 'Last Name' THEN a.Data END) AS LastName, 
     MAX(CASE WHEN a.type = 'Timestamp' THEN a.Data END) AS `Timestamp`, 
     MAX(CASE WHEN a.type = 'Count' THEN a.Data END) AS `Count`, 
     MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) AS MY_ID, 
     MAX(CASE WHEN a.Type = 'Foreign Id' THEN a.Data END) AS ForeignId 
FROM Attributes a 
GROUP BY a.ID; 

值得注意的是,雖然該實體 - 屬性 - 值模型是一個SQL反模式,你可能會更好地規範化你的數據以將屬性存儲爲列,而不必使用上述查詢將行轉換爲列。

編輯

要添加基於屬性過濾器中使用的HAVING條款:

SELECT a.ID, 
     MAX(CASE WHEN a.type = 'First Name' THEN a.Data END) AS FirstName, 
     MAX(CASE WHEN a.type = 'Last Name' THEN a.Data END) AS LastName, 
     MAX(CASE WHEN a.type = 'Timestamp' THEN a.Data END) AS `Timestamp`, 
     MAX(CASE WHEN a.type = 'Count' THEN a.Data END) AS `Count`, 
     MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) AS MY_ID, 
     MAX(CASE WHEN a.Type = 'Foreign Id' THEN a.Data END) AS ForeignId 
FROM Attributes a 
GROUP BY a.ID 
HAVING MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) = 1; 
+0

哈哈,真棒,謝謝! – chacham15

+0

+1,只是在列中存儲屬性將是* normalization *,而不是* denormalization *。 EAV反模式甚至不是關係;它不能以任何正常形式。 –

+0

在我的情況下,我沒有選擇,但爲了知道更好的是不是EAV NOSQL的一般前提? – chacham15

0

你的屬性表是窄的,但有很多行。你要麼做一堆自我加入,要麼用group by a.id查詢並使用聚合函數。後一種方法消除了連接,但仍然遇到很多行。

我認爲一個更好的選擇是使你的數據模型稍微規格化。這將涉及創建一個包含'First Name'列,'Middle Name'列等的表。然後,與ID關聯的各種屬性都在同一行上。你最終得到一個更寬的表格,但行數少得多,而且沒有連接。