2011-07-31 12 views
3

我有一個DB結構,旨在以一種容易擴展的方式存儲特定對象的屬性。
有一個「對象」表。MySQL優化過濾鍵值對作爲記錄

+----+---------------------- 
| id | ....(name, type, etc) 
+----+---------------------- 

接下來,我有一個「屬性」表。

+----+------+ 
| id | Name | 
+----+------+ 

最後,一個「關係」表,用於保持所有與對應的值的數據作爲屬性對象對(作爲主鍵)。

+--------+---------+-------+ 
| id_obj | id_attr | value | 
+--------+---------+-------+ 

我需要爲一次滿足幾個條件的對象獲取ID。例如,我擁有名爲「Type」和「City」的屬性,我需要爲這些屬性的對應值爲「Apartment」和「City b」的對象獲取ID。

我管理的最佳解決方案拿出敲打我的頭靠在牆上,因爲經過昨日(當然,這個查詢的唯一好處是,它的實際工作,並獲取所需的記錄):

SELECT objects.id 
FROM (attributes INNER JOIN relations ON attributes.id = relations.id_attr) 
    INNER JOIN objects ON relations.id_obj = objects.id 
WHERE objects.id 
IN (
SELECT objects.id 
FROM (attributes INNER JOIN relations ON attributes.id = relations.id_attr) 
    INNER JOIN objects ON relations.id_obj = objects.id 
WHERE attributes.name = 'Type' AND relations.value = 'Apartment' 
) 
AND objects.id 
IN (
SELECT objects.id 
FROM (attributes INNER JOIN relations ON attributes.id = relations.id_attr) 
    INNER JOIN objects ON relations.id_obj = objects.id 
WHERE attributes.name = 'City' AND relations.value = 'City b' 
) 
GROUP BY objects.id ASC 
LIMIT 0 , 20 

問題是,存儲的數據量可能會變得有些大,我擔心所有這些子查詢(可能需要指定10-15個過濾器),每個解析整個數據庫可能會導致嚴重的性能問題(並不是說即使使用我有限的SQL技能,我也確信必須有更好的方式來做我需要做的事情)。
另一方面,數據庫的劇烈變化並不是一個真正的選擇,因爲使用它的代碼在很大程度上取決於當前的數據庫結構。
有沒有一種方法來檢查屬性的方式,我需要它在一個單一的查詢,有限的數量或沒有更改存儲的數據結構?


工作查詢,相當於以上,但更好的一個優化,學分DRapp

SELECT STRAIGHT_JOIN 
     rel.id_obj 
    from 
     relations rel 
     join attributes atr 
      on rel.id_attr = atr.id 
    where 
     (rel.value = 'Apartment' AND atr.name = 'Type' ) 
     or (rel.value = 'City b' AND atr.name = 'City') 
    group by 
     rel.id_obj 
    having 
     count(*) = 2 
    limit 
     0, 20 

回答

4

這應該得到你所需要的......每一個「OR」 d其中的條款條件,您可以繼續添加作爲一個合格的項目。然後,只需調整「Having」子句以符合您允許的標準相同的數量... 我已經把關係表放在第一位,因爲在城市或類型值的「值」上會有一個較小的匹配集。 ..確保您在「VALUE」列中的關係表上有一個索引。

SELECT STRAIGHT_JOIN 
     rel.id_obj 
    from 
     relations rel 
     join attributes atr 
      on rel.id_addr = atr.id 
    where 
     (rel.value = 'Apartment' AND atr.name = 'Type' ) 
     or (rel.value = 'Some City' AND atr.name = 'City') 
    group by 
     atr.id_obj 
    having 
     count(*) = 2 
    limit 
     0, 20 

如果希望所有從這個結果實際對象的數據,你會包裝它像...

select obj.* 
    from 
     (complete SQL statement above) PreQuery 
     join Object obj on PreQuery.id_obj = obj.id 
+0

謝謝!我知道我必須獲得滿足至少一項標準的所有記錄,然後以某種方式獲得滿足所有標準的記錄,但我不確定如何完全做到這一點。 STRAIGHT_JOIN選項是否通過將更小的「屬性」表中的數據連接到更大的表,從而使MySQL更高效地工作? – havelock

+0

我在原始問題中添加了適用於我的數據庫的查詢版本。 – havelock

+0

@Havelock,對不起,以前沒有回覆。 STRAIGHT_JOIN可以提供幫助,但是您真的需要知道查詢中的數據和最佳引導表,以獲得您想要的最小結果......例如,不要使用鏈接到數百萬記錄表的查找表。尋找能力較小/索引元素的標準。 – DRapp