我发现你可以使用子查询来解决MySQL中的61个表连接限制。 https://stackoverflow.com/a/20134402/2843690
我正在试图找出如何轻松在我正在努力从Magento获取详细产品清单的程序中使用它(但我认为这个问题的答案可能适用于涉及eav的很多情况)。需要连接的表看起来像这样:
catalog_product_entity
+-----------+----------------+
| entity_id | entity_type_id |
+-----------+----------------+
| 1 | 4 |
| 2 | 4 |
| 3 | 4 |
| 4 | 4 |
| 5 | 4 |
| 6 | 4 |
| 7 | 4 |
| 8 | 4 |
| 9 | 4 |
+-----------+----------------+
catalog_product_entity_int
+----------+----------------+--------------+-----------+-------+
| value_id | entity_type_id | attribute_id | entity_id | value |
+----------+----------------+--------------+-----------+-------+
| 1 | 4 | 2 | 1 | 245 |
| 2 | 4 | 3 | 1 | 250 |
| 3 | 4 | 4 | 1 | 254 |
| 4 | 4 | 2 | 2 | 245 |
| 5 | 4 | 3 | 2 | 249 |
| 6 | 4 | 4 | 2 | 253 |
| 7 | 4 | 2 | 3 | 247 |
| 8 | 4 | 3 | 3 | 250 |
| 9 | 4 | 4 | 3 | 254 |
+----------+----------------+--------------+-----------+-------+
eav_attribute
+--------------+----------------+----------------+--------------+
| attribute_id | entity_type_id | attribute_code | backend_type |
+--------------+----------------+----------------+--------------+
| 1 | 4 | name | varchar |
| 2 | 4 | brand | int |
| 3 | 4 | color | int |
| 4 | 4 | size | int |
| 5 | 4 | price | decimal |
| 6 | 4 | cost | decimal |
| 7 | 4 | created_at | datetime |
| 8 | 3 | name | varchar |
| 9 | 3 | description | text |
+--------------+----------------+----------------+--------------+
eav_attribute_option
+-----------+--------------+
| option_id | attribute_id |
+-----------+--------------+
| 245 | 2 |
| 246 | 2 |
| 247 | 2 |
| 248 | 3 |
| 249 | 3 |
| 250 | 3 |
| 251 | 4 |
| 252 | 4 |
| 253 | 4 |
| 254 | 4 |
+-----------+--------------+
eav_attribute_option_value
+----------+-----------+-------------------+
| value_id | option_id | value |
+----------+-----------+-------------------+
| 15 | 245 | Fruit of the Loom |
| 16 | 246 | Hanes |
| 17 | 247 | Jockey |
| 18 | 248 | White |
| 19 | 249 | Black |
| 20 | 250 | Gray |
| 21 | 251 | Small |
| 22 | 252 | Medium |
| 23 | 253 | Large |
| 24 | 254 | Extra Large |
+----------+-----------+-------------------+
我正在编写的程序生成的SQL查询看起来像这样:
SELECT cpe.entity_id
, brand_int.value as brand_int, brand.value as brand
, color_int.value as color_int, color.value as color
, size_int.value as size_int, size.value as size
FROM catalog_product_entity as cpe
LEFT JOIN catalog_product_entity_int as brand_int
ON (cpe.entity_id = brand_int.entity_id
AND brand_int.attribute_id = 2)
LEFT JOIN eav_attribute_option as brand_option
ON (brand_option.attribute_id = 2
AND brand_int.value = brand_option.option_id)
LEFT JOIN eav_attribute_option_value as brand
ON (brand_option.option_id = brand.option_id)
LEFT JOIN catalog_product_entity_int as color_int
ON (cpe.entity_id = color_int.entity_id
AND color_int.attribute_id = 3)
LEFT JOIN eav_attribute_option as color_option
ON (color_option.attribute_id = 3
AND color_int.value = color_option.option_id)
LEFT JOIN eav_attribute_option_value as color
ON (color_option.option_id = color.option_id)
LEFT JOIN catalog_product_entity_int as size_int
ON (cpe.entity_id = size_int.entity_id
AND size_int.attribute_id = 4)
LEFT JOIN eav_attribute_option as size_option
ON (size_option.attribute_id = 4
AND size_int.value = size_option.option_id)
LEFT JOIN eav_attribute_option_value as size
ON (size_option.option_id = size.option_id)
;
编写代码以生成查询相对容易,查询相当容易理解;但是,我很容易达到61表加入限制,这是我用现实数据做的。我相信数学说21个整数类型属性将超过限制,这是在我开始添加varchar,text和decimal属性之前。
因此,我提出的解决方案是使用子查询来克服61表限制。
实现此目的的一种方法是将连接分组为61个连接的子查询。然后所有的小组都会加入。我想我可以弄清楚sql查询应该是什么样子,但是编写代码来生成查询似乎很困难。还有一个(虽然是理论上的)问题,如果有足够的属性,可能会再次违反61表限制。换句话说,如果我有62组61个表,则会出现MySQL错误。显然,人们可以通过将组的组分组到61来解决这个问题。但这只会使代码更难以编写和理解。
我认为我想要的解决方案是在子查询中嵌套子查询,以便每个子查询使用2个表(或一个表和一个子查询)的单个连接。直觉上,似乎代码对于这种查询更容易编写。不幸的是,考虑这些查询应该是什么样子会让我的大脑受到伤害。这就是我需要帮助的原因。
这样的MySQL查询会是什么样的?
答案 0 :(得分:2)
通过EAV设计加入太多属性是正确的,可能会超过联接的限制。甚至在此之前,可能存在实际的连接限制,因为这么多连接的成本在几何上变得越来越高。这有多糟糕取决于你的服务器的容量,但它可能比61低很多。
因此,查询EAV数据模型以产生结果,好像它存储在传统的关系模型中(每个属性一列)是有问题的。
解决方案:不要使用每个属性的连接,这意味着您不能指望以纯粹使用SQL的传统的每实体行格式生成结果。
我对Magento架构并不熟悉,但我可以从您的查询中推断出这样的东西可能有用:
SELECT cpe.entity_id
, o.value AS option
, v.value AS option_value
FROM catalog_product_entity AS cpe
INNER JOIN catalog_product_entity_int AS i
ON cpe.entity_id = i.entity_id AND i.attribute_id IN (2,3,4)
INNER JOIN eav_attribute_option AS o
ON i.value = o.option_id AND i.attribute_id = o.attribute_id
INNER JOIN eav_attribute_option_value AS v
ON v.option_id = o.option_id;
IN(2,3,4,...)
谓词是指定多个属性的位置。无需添加更多连接即可获得更多属性。它们只是作为行而不是列返回。
这意味着您必须编写应用程序代码来获取此结果集的所有行,并将它们映射到单个对象的字段中。
来自@Axel的评论,听起来像Magento提供辅助函数来执行此操作以消耗结果集并将其映射到对象中。