我有下面的db shema(MySQL 5.x),在其中我将项目的值保存在一个表中,并将每个属性的对应名称保存在另一个表中:
classified_attr(属于特定机密的属性)
cl_id | value
39393 | 173
cat_attr(属性名称):
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查询,以便在保持结构的同时以更快的方式检索包括名称在内的所有这些值?如果没有,那么存储这些值的更好方法是什么?
答案 0 :(得分:1)
好吧,您的查询有点奇怪,因为您多次将classifieds_attr
表自身连接到自身(ca_power.attr_group_id = ca_power.attr_group_id
和ca_avail.attr_group_id = ca_avail.attr_group_id
),这完全没有必要,特别是因为它是作为一部分完成的cat_attr
表的联接条件。
此外,您对classifieds_attr
和cat_attr
表的多个联接似乎仅在attr_group_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_attr
与classifieds_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
,那么还可以将第一个联接从外部联接切换为内部联接,并可能获得一些额外的性能。
答案 1 :(得分:0)
我将添加以下索引(如果您还没有的话):
create index ix1 on classifieds_attr (cl_id, attr_group_id);
create index ix2 on cat_attr (attr_id);
这将大大加快您的查询速度。不过,由于查询有两个多余的,无用的过滤条件,因此查询中有些麻烦。
您似乎有多个单列索引。但是,第一个索引-综合索引-对于性能至关重要。