如何在没有多个连接的情况下从标准化的数据库结构中检索值?

wnavrhmk  于 2021-06-15  发布在  Mysql
关注(0)|答案(2)|浏览(225)

我有下面的db shema(mysql 5.x),其中我保存了一个表中项目的值和另一个表中每个属性的对应名称:
分类属性(属于特定分类的属性)

cl_id | value
39393 | 173

类别属性(属性名称):

attr_id | attr_de
173       green
123       available

这适用于我需要的所有情况,但有一种情况除外,在这种情况下,我面临一些性能问题,因为我需要使用一个sql查询从一个项目(包括名称)中检索所有值。
为此,我为每个值多次连接表。例如

SELECT 
    ca_power.value AS power_id,
    catr_power.attr_de AS power,   
    ca_avail.value AS avail_id,  
    catr_avail.attr_de AS avail                              
FROM
    classifieds AS c
LEFT JOIN classifieds_attr AS ca_power ON c.ID = ca_power.cl_id AND ca_power.attr_group_id = 19
LEFT JOIN cat_attr AS catr_power ON ca_power.attr_group_id = ca_power.attr_group_id AND catr_power.attr_id =  ca_power.value
LEFT JOIN classifieds_attr AS ca_avail ON c.ID = ca_avail.cl_id AND ca_avail.attr_group_id = 17
LEFT JOIN cat_attr AS catr_avail ON ca_avail.attr_group_id = ca_avail.attr_group_id AND catr_avail.attr_id =  ca_avail.value

对于这两个属性和它们的名称,这是可以忽略的,但现在有超过10个属性,我面临着性能下降。
有没有一种方法可以改变我的sql查询,以便以更快的方式检索包括name在内的所有值,同时保留结构?如果没有,那么存储这些值的更好方法是什么呢?

9rygscc1

9rygscc11#

我将添加以下索引(如果您还没有):

create index ix1 on classifieds_attr (cl_id, attr_group_id);

create index ix2 on cat_attr (attr_id);

这将大大加快您的查询速度。然而,您的查询有一些可疑之处,因为它有两个冗余的、无用的过滤条件。
您似乎有多个单列索引。然而,第一个指标——综合指数——对业绩至关重要。

8yparm6h

8yparm6h2#

好吧,您的查询有点奇怪,因为您正在自动加入 classifieds_attr 表自身多次( ca_power.attr_group_id = ca_power.attr_group_id 以及 ca_avail.attr_group_id = ca_avail.attr_group_id )这是完全不必要的,尤其是作为 cat_attr table。
另外,您的多个连接到 classifieds_attr 以及 cat_attr 表似乎只有attr\u group\u id列不同(不在上面的规范中)。
您可以通过删除冗余联接并将其转换为透视查询来简化查询:

SELECT 
    c.id as classified_id,
    -- Power Group (19)
    max(case when ca.attr_group_id = 19 then ca.value end) AS power_id,
    max(case when ca.attr_group_id = 19 then catr.attr_de end) AS power,
    -- Avail Group (17)
    max(case when ca.attr_group_id = 17 then ca.value end) AS avail_id,
    max(case when ca.attr_group_id = 17 then catr.attr_de end) AS avail
FROM
    classifieds AS c
LEFT JOIN classifieds_attr AS ca
  ON c.ID = ca.cl_id
 AND ca.attr_group_id in (17,19)
LEFT JOIN cat_attr AS catr
  ON catr.attr_id =  ca.value
GROUP BY c.id

要添加其他列(组),只需复制聚合列(注意上面注解的列),更改case语句中的组id,并将适当的组id添加到第一个联接的in列表中。
你也可以尝试内部连接 cat_attrclassifieds_attr 假设 ca.value 是必填字段,是的外键 cat_attr 引用 attr_id . 您没有提供太多元数据,因此很难了解您的设置。不管怎样,这里有一个潜在的优化:

SELECT c.id as classified_id,
    -- Power Group (19)
       max(case when ca.attr_group_id = 19 then ca.value end) AS power_id,
       max(case when ca.attr_group_id = 19 then catr.attr_de end) AS power,
    -- Avail Group (17)
       max(case when ca.attr_group_id = 17 then ca.value end) AS avail_id,
       max(case when ca.attr_group_id = 17 then catr.attr_de end) AS avail
  FROM classifieds AS c
  LEFT JOIN classifieds_attr AS ca
       JOIN cat_attr AS catr
         ON catr.attr_id =  ca.value
    ON c.ID = ca.cl_id
   AND ca.attr_group_id in (17,19)
 GROUP BY c.id

如果你不想看到 classified.id 如果没有属性,则还可以将第一个连接从外部连接切换到内部连接,并可能获得一些额外的性能。

相关问题