使用group_concat标记查询

时间:2013-05-18 03:48:14

标签: mysql query-optimization

使用数据库模式从此问题的标记中接受answer是否可以使用group_concat进行查询,该查询可以处理大量数据?我需要为所有标记为标记x的项目获取带有标签的项目。使用具有约.5百万个标签的group_concat的查询在>处非常慢。 15秒没有group_concat(项目没有标签),它是~0.05秒。

作为一个附带问题,SO如何解决这个问题?

4 个答案:

答案 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来测试我的理论。