【发布时间】:2019-10-20 11:42:19
【问题描述】:
我已经使用 MySQL (phpmyadmin) 为使用 CodeIgniter Framework (PHP) 开发的电子商务网站实现了 EAV 模型。 EAV 模型是这样的:
表格:产品
id | name | description
-------------------------
1 | prod_1 | lorem
2 | prod_2 | ipsum
表格:属性
id | name | description
-------------------------
1 | attr_1 | dolor
2 | attr_2 | sit
3 | attr_3 | amet
表格:Product_Attributes
id | prod_id | attr_id
-------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 2 | 2
5 | 2 | 3
我使用多个连接生成了一个结果,如下所示:
product_name | attribute_name | product_description
---------------------------------------------------
prod_1 | attr_1 | lorem
prod_1 | attr_2 | lorem
prod_2 | attr_1 | ipsum
prod_2 | attr_2 | ipsum
prod_2 | attr_3 | ipsum
上述结果使用的查询如下:
function getProductList() {
return $this->db->select('p.name as product_name, a.name as attribute_name, p.description as product_description')
->from('products as p')
->join('product_attributes as pa', 'pa.prod_id = p.id', 'LEFT')
->join('attributes as a', 'a.id = pa.attr_id', 'LEFT')
->get();
}
但是,我想要的查询结果如下:
product_name | attribute_name | product_description
-------------------------------------------------------------
prod_1 | (attr_1, attr_2) | lorem
prod_2 | (attr_1, attr_2, attr_3) | ipsum
当前查询结果的缺点是我必须对结果执行嵌套循环以显示产品及其属性的列表,这会影响性能。我愿意接受任何改进查询性能或其结果的建议。
--编辑--
我还有其他与Products 表链接的表。比如说,有一个额外的表格如下:
表格:尺寸
id | name | value
-----------------
1 | length | 20
2 | breadth| 15
3 | height | 20
表格:Product_Dimensions
id | prod_id | dim_id
-------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 2
因此,预期的输出修改如下:
product_name | attribute_name | product_description| dimension_name | dimension_value
----------------------------------------------------------------------------------------------------------
prod_1 | (attr_1, attr_2) | lorem | (length, breadth, height) | (20, 15, 20)*
prod_2 | (attr_1, attr_2, attr_3) | ipsum | (length, breadth) | (20, 15)
但是,得到的输出如下:
product_name | attribute_name | product_description| dimension_name | dimension_value
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
prod_1 | (attr_1, attr_2, attr_1, attr_2, attr_1, attr_2) | lorem | (length, breadth, height, length, breadth, height) | (20, 15, 20, 20, 15, 20)
prod_2 | (attr_1, attr_2, attr_3, attr_1, attr_2, attr_3) | ipsum | (length, breadth, length, breadth, length, breadth) | (20, 15, 20, 15, 20, 15)
--编辑--
当在GROUP_BY下使用DISTINCT时,输出修改如下:
product_name | attribute_name | product_description| dimension_name | dimension_value
----------------------------------------------------------------------------------------------------------
prod_1 | (attr_1, attr_2) | lorem | (length, breadth, height) | (20, 15)*
prod_2 | (attr_1, attr_2, attr_3) | ipsum | (length, breadth) | (20, 15)
*您可以看到预期输出和获得的输出之间的差异。使用DISTINCT 也会删除预期的重复项。
SQL Fiddle 来试试here。
【问题讨论】:
-
您关心的是在 PHP 中运行循环吗?您是否测量过它的性能影响?如果它很重要甚至是可测量的,我会感到惊讶,因为在与数据库对话的任何代码中,查询的执行时间可能比应用程序代码的执行时间长得多。 SQL 产生二维结果,通常的做法是在显示逻辑中将它们重新格式化为更多维度,除非您有明显的性能问题,否则您已将其隔离到循环中,我建议您已经存在的内容是好的和正确的。跨度>
-
@MichaelBerkowski 感谢您分享知识。但是,我想知道是否有更好的方法来查询结果。因为,我所说明的示例包括仅具有有限属性的 3 个表的连接,但是,我正在处理的数据库需要多个此类连接,每个产品至少具有 20 个属性(可能会进一步增加)。因此,如果我必须显示一个包含 10k+ 产品的列表,则查询结果可能包含 20k+ 行,这是循环迭代的次数。
-
这确实是一个大循环。下面使用 GROUP_CONCAT() 建议的示例将重新格式化查询,但可能仍需要在您的视图中使用循环。它们将对查询性能产生影响,可能等同于仅对 2D 结果使用循环。
标签: php mysql codeigniter entity-attribute-value