【发布时间】:2017-07-13 08:45:26
【问题描述】:
我遇到了性能问题:
一家商店有一个商品过滤器,其中包含“颜色”、“尺寸”、“性别”和“特征”类别。所有这些详细信息都存储在article_criterias 表中,如下所示:
article_criterias的表格布局是;该表大约有 36.000 行:
article_id | group | option | option_val
100 | "size" | "35" | 35.00
100 | "size" | "36" | 36.00
100 | "size" | "36½" | 36.50
100 | "color" | "40" | 40.00
100 | "color" | "50" | 50.00
100 | "gender" | "1" | 1.00
101 | "size" | "40" | 40.00
...
我们有一个根据当前选择的条件动态构建的 SQL 查询。该查询适用于 2-3 个条件,但在选择超过 5 个选项时会变得非常慢(每个额外的 INNER JOIN 大约会使执行时间增加一倍)
我们怎样才能让这个 SQL 更快,甚至可以用更高效的概念代替内部连接?
这是查询(逻辑正确,只是性能不好):
-- This SQL is generated when the user selected the following criteria
-- gender: 1
-- color: 80 + 30
-- size 36 + 37 + 38 + 39 + 42 + 46
SELECT
criteria.group AS `key`,
criteria.option AS `value`
FROM articles
INNER JOIN article_criterias AS criteria ON articles.id = criteria.article_id
INNER JOIN article_criterias AS criteria_gender
ON criteria_gender.article_id = articles.id AND criteria_gender.group = "gender"
INNER JOIN article_criterias AS criteria_color1
ON criteria_color1.article_id = articles.id AND criteria_color1.group = "color"
INNER JOIN article_criterias AS criteria_size2
ON criteria_size2.article_id = articles.id AND criteria_size2.group = "size"
INNER JOIN article_criterias AS criteria_size3
ON criteria_size3.article_id = articles.id AND criteria_size3.group = "size"
INNER JOIN article_criterias AS criteria_size4
ON criteria_size4.article_id = articles.id AND criteria_size4.group = "size"
INNER JOIN article_criterias AS criteria_size5
ON criteria_size5.article_id = articles.id AND criteria_size5.group = "size"
INNER JOIN article_criterias AS criteria_size6
ON criteria_size6.article_id = articles.id AND criteria_size6.group = "size"
INNER JOIN article_criterias AS criteria_size7
ON criteria_size7.article_id = articles.id AND criteria_size7.group = "size"
WHERE
AND (criteria_gender.option IN ("1"))
AND (criteria_color1.option IN ("80", "30"))
AND (criteria_size2.option_val BETWEEN 35.500000 AND 36.500000)
AND (criteria_size3.option_val BETWEEN 36.500000 AND 37.500000)
AND (criteria_size4.option_val BETWEEN 37.500000 AND 38.500000)
AND (criteria_size5.option_val BETWEEN 38.500000 AND 39.500000)
AND (criteria_size6.option_val BETWEEN 41.500000 AND 42.500000)
AND (criteria_size7.option_val BETWEEN 45.500000 AND 46.500000)
【问题讨论】:
-
检查索引,INNER JOIN 条件中使用的字段,以及 where 条件。索引将使搜索变得快速。
-
您正在努力解决的问题称为“实体属性值”或“EAV”。就关系数据库而言,您已经从地狱中获得了反模式。您需要不同的数据库或不同的方法。
-
虽然我同意太空人的观点,但您确定查询真的按预期工作吗?您的查询当前将查找特定性别的鞋子,颜色为 80 OR(!) 30,尺寸为 36 AND (!) 37(以及其他),因此如果您拥有除 39 之外的所有尺寸的鞋子,则没有结果。您如果您也使用
or作为尺寸,已经可以在这里节省很多加入/时间,类似于颜色:只加入一次,例如使用join ... criteria_size2 on ... criteria_size2.group = "size" and (criteria_size2.option_val BETWEEN 35.5 AND 36.5 or criteria_size2.option_val BETWEEN 36.5 AND 37.5 or ...)。 -
@LoztInSpace 是的,我知道......但是,现在更改数据库结构不是一种选择。您应该已经看到原始查询是如何工作的(在最低分支中使用 SQL 的 3 个嵌套循环)...
-
请注意,组、选项和键是保留字,因此它们都比表/列标识符的灵感选择少。
标签: mysql join query-performance entity-attribute-value