Mysql 使用组\u concat标记查询

Mysql 使用组\u concat标记查询,mysql,query-optimization,Mysql,Query Optimization,使用数据库模式标记此问题的已接受项是否可以使用组_concat查询大量数据?我需要为所有标记了标记x的项目获取带有标记的项目。使用带有大约50万个标记的组_concat的查询在>15秒时非常慢。不带标签的组_concat项目约为0.05秒 作为一个附带问题,这样做如何解决这个问题?这可能是一个索引策略不佳的情况。调整所链接问题的中所示的模式: CREATE Table Items ( Item_ID SERIAL, Item_Title VARCHAR(255), Conten

使用数据库模式标记此问题的已接受项是否可以使用组_concat查询大量数据?我需要为所有标记了标记x的项目获取带有标记的项目。使用带有大约50万个标记的组_concat的查询在>15秒时非常慢。不带标签的组_concat项目约为0.05秒


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

这可能是一个索引策略不佳的情况。调整所链接问题的中所示的模式:

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的串行数据类型是BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE的别名,因此是索引的

在Items_标记中定义外键约束将在外键列上创建索引


我建议在数据和数据之间进行混合。 因此,使用eggyal提供的规范化结构,我将执行以下非规范化结构:

CREATE TABLE Items_Tags_Denormalized (
  Item_ID    BIGINT UNSIGNED REFERENCES Items (Item_ID),
  Tags     BLOB,
  PRIMARY KEY (Item_ID)
) ENGINE=InnoDB;
在列标记中,您将拥有对应项目ID的所有标记标记标题。 现在您有两种方法来实现这一点:

创建一个周期性运行的cron,该cron将使用GROUP_CONCAT或任何适合您的方法构建此表Items_Tags_非规范化:在Items_Tags表中插入或删除时不会增加额外的负载;缺点:根据运行cron的频率,非规范化的表并不总是最新的

在插入和删除时为项目创建标签表,以保持项目的最新信息。标签表的非规范化优势:非规范化的表格始终是最新的;缺点:插入或删除表中的项目时会增加负载

考虑到优缺点,选择最适合您需要的解决方案


因此,最终您将得到Items\u Tags\u非规范化表,您将仅从中读取,而不进行其他操作。

为什么要使用group\u 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,它可以在没有标记的情况下加快查询速度。在组_CONCAT中,您选择Tags.Tag_Title并强制访问Tags表


你可以试着用Items\u Tags.Tag\u ID运行GROUP\u CONCAT来测试我的理论。

你能给出示例记录吗。因此,似乎可以通过将问题限制为最多5个标签来解决这个问题。是什么让你认为它在处理标记时使用了GROUP_CONCAT呢?@Barmar:SO上的标记限制不是出于性能原因,而是;至于,标签以规范化方式(PostTags表)和非规范化方式(posts.tags字段)与帖子相关联,后者使得使用帖子本身检索帖子的标签非常快速,前者使搜索带有特定标记组合的帖子变得容易。嗯,我很确定我有相同的索引,今晚晚些时候会检查。为什么不将非规范化标记字段添加到Items表中呢?这是如何做到的?关键是要有单独的模型:一个规范化,一个非规范化,您的解决方案还可以,但从设计角度来看,我建议将其分开,原因有很多:您需要重建表,您需要添加更多列等。此外,如果您在项目中添加非规范化标记列,表的性能将下降:更大的大小=较慢的查询