处理多态关联:有没有"too many" LEFT JOIN这样的东西?
Dealing with polymorphic association: is there such a thing as "too many" LEFT JOIN?
我有十个table(Product_A、Product_B、Product_C等),每个都有一个主键指向父 table 产品。
基本上,我应用了来自 Bill Karwin 的 SQL 反模式书籍中的建议(此处描述的反模式解决方案:
https://fr.slideshare.net/billkarwin/practical-object-oriented-models-in-sql/34-Polymorphic_Assocations_Exclusive_Arcs_Referential )
为了加载子产品,我使用了这样的东西:
SELECT * FROM Product
LEFT JOIN Product_A USING (product_id)
LEFT JOIN Product_B USING (product_id)
LEFT JOIN Product_C USING (product_id)
LEFT JOIN Product_D USING (product_id)
WHERE product_id = 1337
etc.
我担心我得到的子 table 产品类型越多,我必须添加的 JOIN 子句就越多,导致查询最终变得非常慢。
如果我们处理数十个子子 [=37=]s,使用 LEFT JOIN 来防止多态关联反模式是否仍然是一种解决方案?
我是否应该开始考虑对父 table 产品使用查询以获取 "product_type" 然后根据值对适当的子 table 执行另一个查询存储在父 table?
的 "product_type" 列中
更新:关于此主题的第一个回复指出这是糟糕的设计,我应该创建一个 table 组合来自子 table 的列。但是每种产品类型都有自己的属性。换句话说:"A TV might have a pixel count, but that wouldn't make much sense for a blender."
谢谢
进入这些 table 的数据类型是什么?它只是关于产品的元数据吗?如果是这种情况,您可以创建一个 tall table 来描述每个产品。
例如,具有三列的 Product_Details table:product_id、product_data_key、值。其中 product_data_key 曾经是 Product_A、Product_B、Product_C...
中的列
您甚至可以有一个单独的 table 来更好地描述 product_data_key,因此它只是 Product_Details 中的一个外键。
MySQL 对连接数有硬性限制。限制是 61 个连接,并且它是不可配置的(我查看了源代码,它实际上只是硬编码)。因此,如果您有超过 62 种产品类型,这将无法在单个查询中使用。
如果数据存储在您描述的结构中,我会 运行 为每个产品类型单独查询,这样您就不会进行太多连接。
或者先针对 Product
table 进行查询,如果需要详细信息,然后再对产品类型特定的 table 进行其他查询。
例如,您什么时候需要一次收集所有特定于产品的详细信息?在某种搜索页面上?您认为您可以将代码设计为在搜索页面上仅显示主要 Product
table 的属性吗?
只有当用户点击特定产品时,您才会转到不同的页面以显示详细信息。或者如果不是不同的页面,也许它会是一个动态的 HTML 东西,你可以在其中展开一个“+”按钮来获取详细信息,并且每次你这样做时,运行 一个 AJAX 请求详细信息。
是的,您可以使用 product_type
(所谓的 "discriminator")来帮助 DBMS 生成更好的查询计划并避免不必要的连接。你可以这样做:
SELECT
*
FROM
Product
LEFT JOIN Product_A
ON product_type = 1 -- Or whatever is the actual value in your case.
AND Product.product_id = Product_A.product_id
LEFT JOIN Product_B
ON product_type = 2
AND Product.product_id = Product_B.product_id
LEFT JOIN Product_C
ON product_type = 3
AND Product.product_id = Product_C.product_id
LEFT JOIN Product_D
ON product_type = 4
AND Product.product_id = Product_D.product_id
WHERE
Product.product_id = 1337
DBMS 应该能够短路所有 "branches" 没有权利 product_type
并避免相应的连接。1
这是否真的比使用单独的查询来获取 product_type
然后选择相应的 "special" 查询(并引发另一次数据库往返)更好 - 这是您应该测试的东西。一如既往,测试有代表性的数据量!
1 至少 Oracle 或 SQL 服务器会这样做 - 请检查 MySQL!
也许改变你的设计?一个产品可以有很多属性(和很多相同的属性),而这些属性有值。
我建议三个表:
Products ProductsAttributes Attributes
-Product_Id -Product_Id -Attribute_Id
-... -Attribute_Id -Attribute_Name
-Value -...
-...
这样使用:
SELECT p.Product_Id, a.Attribute_Name, pa.Value FROM Products p
JOIN ProductsAttributes pa ON pa.Product_Id = p.ProductId
JOIN Attributes a ON a.Attribute_Id = pa.Attribute_Id
然后您可以重用属性,将它们绑定到产品,并存储它们的值。每个产品只有它需要的属性。
我有十个table(Product_A、Product_B、Product_C等),每个都有一个主键指向父 table 产品。
基本上,我应用了来自 Bill Karwin 的 SQL 反模式书籍中的建议(此处描述的反模式解决方案: https://fr.slideshare.net/billkarwin/practical-object-oriented-models-in-sql/34-Polymorphic_Assocations_Exclusive_Arcs_Referential )
为了加载子产品,我使用了这样的东西:
SELECT * FROM Product
LEFT JOIN Product_A USING (product_id)
LEFT JOIN Product_B USING (product_id)
LEFT JOIN Product_C USING (product_id)
LEFT JOIN Product_D USING (product_id)
WHERE product_id = 1337
etc.
我担心我得到的子 table 产品类型越多,我必须添加的 JOIN 子句就越多,导致查询最终变得非常慢。
如果我们处理数十个子子 [=37=]s,使用 LEFT JOIN 来防止多态关联反模式是否仍然是一种解决方案?
我是否应该开始考虑对父 table 产品使用查询以获取 "product_type" 然后根据值对适当的子 table 执行另一个查询存储在父 table?
的 "product_type" 列中更新:关于此主题的第一个回复指出这是糟糕的设计,我应该创建一个 table 组合来自子 table 的列。但是每种产品类型都有自己的属性。换句话说:"A TV might have a pixel count, but that wouldn't make much sense for a blender."
谢谢
进入这些 table 的数据类型是什么?它只是关于产品的元数据吗?如果是这种情况,您可以创建一个 tall table 来描述每个产品。
例如,具有三列的 Product_Details table:product_id、product_data_key、值。其中 product_data_key 曾经是 Product_A、Product_B、Product_C...
中的列您甚至可以有一个单独的 table 来更好地描述 product_data_key,因此它只是 Product_Details 中的一个外键。
MySQL 对连接数有硬性限制。限制是 61 个连接,并且它是不可配置的(我查看了源代码,它实际上只是硬编码)。因此,如果您有超过 62 种产品类型,这将无法在单个查询中使用。
如果数据存储在您描述的结构中,我会 运行 为每个产品类型单独查询,这样您就不会进行太多连接。
或者先针对 Product
table 进行查询,如果需要详细信息,然后再对产品类型特定的 table 进行其他查询。
例如,您什么时候需要一次收集所有特定于产品的详细信息?在某种搜索页面上?您认为您可以将代码设计为在搜索页面上仅显示主要 Product
table 的属性吗?
只有当用户点击特定产品时,您才会转到不同的页面以显示详细信息。或者如果不是不同的页面,也许它会是一个动态的 HTML 东西,你可以在其中展开一个“+”按钮来获取详细信息,并且每次你这样做时,运行 一个 AJAX 请求详细信息。
是的,您可以使用 product_type
(所谓的 "discriminator")来帮助 DBMS 生成更好的查询计划并避免不必要的连接。你可以这样做:
SELECT
*
FROM
Product
LEFT JOIN Product_A
ON product_type = 1 -- Or whatever is the actual value in your case.
AND Product.product_id = Product_A.product_id
LEFT JOIN Product_B
ON product_type = 2
AND Product.product_id = Product_B.product_id
LEFT JOIN Product_C
ON product_type = 3
AND Product.product_id = Product_C.product_id
LEFT JOIN Product_D
ON product_type = 4
AND Product.product_id = Product_D.product_id
WHERE
Product.product_id = 1337
DBMS 应该能够短路所有 "branches" 没有权利 product_type
并避免相应的连接。1
这是否真的比使用单独的查询来获取 product_type
然后选择相应的 "special" 查询(并引发另一次数据库往返)更好 - 这是您应该测试的东西。一如既往,测试有代表性的数据量!
1 至少 Oracle 或 SQL 服务器会这样做 - 请检查 MySQL!
也许改变你的设计?一个产品可以有很多属性(和很多相同的属性),而这些属性有值。
我建议三个表:
Products ProductsAttributes Attributes
-Product_Id -Product_Id -Attribute_Id
-... -Attribute_Id -Attribute_Name
-Value -...
-...
这样使用:
SELECT p.Product_Id, a.Attribute_Name, pa.Value FROM Products p
JOIN ProductsAttributes pa ON pa.Product_Id = p.ProductId
JOIN Attributes a ON a.Attribute_Id = pa.Attribute_Id
然后您可以重用属性,将它们绑定到产品,并存储它们的值。每个产品只有它需要的属性。