使用數據庫模式從此問題接受的answer進行標記可以使用group_concat查詢來處理大量數據嗎?我需要爲所有標記爲x的項目標記物品。在具有〜500萬個標籤的group_concat上使用查詢時,速度非常慢,時間大於15秒。沒有group_concat(項目沒有標籤)是〜0.05秒。使用group_concat標記查詢
作爲一個側面問題,SO如何解決這個問題?
使用數據庫模式從此問題接受的answer進行標記可以使用group_concat查詢來處理大量數據嗎?我需要爲所有標記爲x的項目標記物品。在具有〜500萬個標籤的group_concat上使用查詢時,速度非常慢,時間大於15秒。沒有group_concat(項目沒有標籤)是〜0.05秒。使用group_concat標記查詢
作爲一個側面問題,SO如何解決這個問題?
這可能是一種糟糕的索引策略。適應的問題the accepted answer顯示的模式,以您鏈接:
CREATE Table Items (
Item_ID SERIAL,
Item_Title VARCHAR(255),
Content TEXT
) ENGINE=InnoDB;
CREATE TABLE Tags (
Tag_ID SERIAL,
Tag_Title VARCHAR(255)
) ENGINE=InnoDB;
CREATE TABLE Items_Tags (
Item_ID BIGINT UNSIGNED REFERENCES Items (Item_ID),
Tag_ID BIGINT UNSIGNED REFERENCES Tags (Tag_ID),
PRIMARY KEY (Item_ID, Tag_ID)
) ENGINE=InnoDB;
需要注意的是:
MySQL的SERIAL
數據類型爲BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE
的別名和,因此,被索引;
定義Items_Tags
中的外鍵約束在外鍵列上創建索引。
嗯我很確定我有相同的索引,今晚晚些時候會檢查。 –
@amiawizard:任何消息? – eggyal
我建議有normalized數據和denormalized數據之間的混合體。
所以使用eggyal我會做以下非規範化的結構提供標準化的結構:(Tag_Title
)爲相應Item_ID
CREATE TABLE Items_Tags_Denormalized (
Item_ID BIGINT UNSIGNED REFERENCES Items (Item_ID),
Tags BLOB,
PRIMARY KEY (Item_ID)
) ENGINE=InnoDB;
在Tags
欄,你會擁有所有的標籤。
現在你有2種方法來實現這一目標:
創建一個定期運行一個cron將使用GROUP_CONCAT
建立這個表格Items_Tags_Denormalized
或任何適合你(好處:當你插入或刪除不把額外的負載在Items_Tags
表;缺點:非規範化的表不會永遠是最新的(取決於你是否經常運行的cron))
上插入Items_Tags
表中創建triggers,並以不斷更新的刪除Items_Tags_Denormalized
表(優點:非規範化的t能夠將永遠是最新的;缺點:當您插入或Items_Tags
表中刪除額外的負載)
選擇何種解決方案適合您需求的最佳考慮的優點和缺點。
所以最後你會得到Items_Tags_Denormalized
表,從這裏你將只讀而不用做額外的操作。
爲什麼要使用group_concat呢?對於給定的標籤x,您表示選擇項目列表的速度很快。對於給定的項目列表,獲取所有標籤也應該很快。並且通常沒有某種限制,我的意思是一般網站在一頁上不顯示100000個條目。
我建議:
drop temporary table if exists lookup_item;
create temporary table lookup_item (item_id serial, primary key(item_id));
insert into lookup_item select i.id as item_id
from items i
where exists (select * from items_tags where item_id = i.id and tag_id = <tag_id>)
and <other conditions or limits>;
select * from lookup_item
inner join items_tags it on it.item_id = i.id
inner join tags t on t.id = it.tag_id
order by i.<priority>, t.<priority>
優先級可能是最後一次修改的項目和某種重要性的標籤。
然後你得到每個項目的標籤。代碼中唯一的工作是查看結果行何時具有下一個項目。
如果我理解正確,GROUP_CONCAT
不是你正在移除的唯一東西,這使得查詢更快速,沒有標籤。在GROUP_CONCAT
內部,您選擇Tags.Tag_Title
並強制要訪問標籤表。
你可以嘗試運行GROUP_CONCAT
與Items_Tags.Tag_ID
來測試我的理論。
你可以提供樣品記錄。 –
SO似乎通過將問題限制在最多5個標籤來解決這個問題。什麼讓你認爲它在處理標籤時使用'GROUP_CONCAT()'? – Barmar
@Barmar:SO上的標籤限制不是出於性能原因,而是[保持焦點](http://meta.stackexchange.com/a/34743);至於[SO的模式](http://meta.stackexchange.com/a/2678),標籤以規範化的方式(PostTags表)和非規範化的方式(Posts.Tags 'field) - 後者可以非常快速地檢索帖子本身的帖子標籤,而前者可以很容易地搜索具有特定標籤組合的帖子。 – eggyal