使用数据库模式从此问题的标记中接受answer是否可以使用group_concat进行查询,该查询可以处理大量数据?我需要为所有标记为标记x的项目获取带有标签的项目。使用具有约.5百万个标签的group_concat的查询在>处非常慢。 15秒没有group_concat(项目没有标签),它是~0.05秒。
作为一个附带问题,SO如何解决这个问题?
答案 0 :(得分:5)
这可能是一个糟糕的索引策略的情况。调整您链接到的问题的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
中定义外键约束会在外键列上创建索引。
答案 1 :(得分:3)
我建议在normalized数据和denormalized数据之间进行混合 因此,使用 eggyal 提供的规范化结构,我将执行以下非规范化结构:
CREATE TABLE Items_Tags_Denormalized (
Item_ID BIGINT UNSIGNED REFERENCES Items (Item_ID),
Tags BLOB,
PRIMARY KEY (Item_ID)
) ENGINE=InnoDB;
在Tags
列中,您可以获得相应Tag_Title
的所有代码(Item_ID
)。
现在您有两种方法可以实现这一目标:
创建一个定期运行的cron,它将使用Items_Tags_Denormalized
或适合您的任何内容构建此表GROUP_CONCAT
(优点:在{{1}中插入或删除时不会产生额外的负载}; table;缺点:非规范化表并不总是最新的(取决于你运行cron的频率))
为插入和删除Items_Tags
表创建triggers以便及时了解Items_Tags
表(优点:非规范化表始终是最新的;缺点:在Items_Tags_Denormalized
表中插入或删除
考虑到优点和缺点,选择最适合您需求的解决方案。
因此,最后您将拥有Items_Tags
表格,您将仅在不执行其他操作的情况下阅读。
答案 2 :(得分:1)
为什么要使用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>
优先级可以针对项目进行最后修改,对标签也有一些重要性。
然后你用它的标签得到每个项目。代码中唯一的工作是查看结果行何时有下一个项目。
答案 3 :(得分:1)
如果我理解正确,GROUP_CONCAT
并不是你唯一要删除的东西,它使得查询更快,没有标签。在GROUP_CONCAT
内,您选择Tags.Tag_Title
并强制访问Tags表。
您可以尝试使用GROUP_CONCAT
运行Items_Tags.Tag_ID
来测试我的理论。