【发布时间】:2023-03-23 23:27:01
【问题描述】:
我有一个 SQL 查询,它给出了正确的结果,但执行速度太慢了。
查询对以下三个表进行操作:
customers包含大量客户数据,例如姓名、地址、电话 等等。为了简化表格,我只使用名称。customdatas包含某些自定义(非客户)数据。 (这 表是在软件中创建的,这就是复数形式错误的原因 对于这个表)customercustomdatarels将自定义数据与客户相关联。
客户
Id Name (many more columns)
-----------------------------------------------------------------------
8053c6f4c5c5c631054ddb13d9186117 MyCustomer ...
2efd2aa5711ddfade1f829b12dd88cf3 CheeseFactory ...
自定义数据
id key
-------------------------------------------------
22deb172c1af6e8e245634a751871564 favoritsport
86eea84d296df9309ad6ff36fd7f856e favoritcheese
customercustomdatarels(客户和自定义数据之间的关系 - 具有相应的值)
customer customdata value
-------------------------------------------------------------------------------------
8053c6f4c5c5c631054ddb13d9186117 22deb172c1af6e8e245634a751871564 cycling
8053c6f4c5c5c631054ddb13d9186117 86eea84d296df9309ad6ff36fd7f856e cheddar
2efd2aa5711ddfade1f829b12dd88cf3 22deb172c1af6e8e245634a751871564 football
2efd2aa5711ddfade1f829b12dd88cf3 86eea84d296df9309ad6ff36fd7f856e mouldy
我想要的是一个基本上由customers 中的所有数据组成的表,其中包含可变数量的额外列,对应于customercustomdatarels 中指定的自定义数据。
这些列应该在某个地方定义,因此我创建了下表,它定义了这些额外的列并将它们映射到customdata 表中的一个键:
test_customkeymapping
colkey customkey
---------------------
1 favoritsport
2 favoritcheese
结果应该是:
Name ExtraColumn_1 ExtraColumn_2
---------------------------------------------
CheeseFactory football mouldy
MyCustomer cycling cheddar
(因此,ExtraColumn_1 是客户最喜欢的运动的同义词,ExtraColumn_2 是客户最喜欢的奶酪的同义词。)
这个结果是通过执行以下查询来实现的:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT('MAX(CASE
WHEN ckm.colkey = ', colkey, ' THEN
(SELECT value FROM customercustomdatarels ccdr2
LEFT JOIN customdatas cd2
ON cd2.id = ccdr2.customdata
WHERE cd2.key = ckm.customkey AND c.Id = ccdr2.customer)
END) AS ', CONCAT('`ExtraColumn_', colkey, '`'))
) INTO @sql
FROM test_customkeymapping;
SET @sql = CONCAT('SELECT c.Name, ', @sql, '
FROM customers c
LEFT JOIN customercustomdatarels ccdr
ON c.Id = ccdr.customer
LEFT JOIN customdatas cd
ON cd.Id = ccdr.customdata
LEFT JOIN test_customkeymapping ckm
ON cd.key = ckm.customkey
GROUP BY c.Id');
PREPARE stmt FROM @sql;
EXECUTE stmt;
这行得通。但是太慢了(对于 7000 名客户,它需要大约 10 秒)。 查询受到此问题中的解决方案的极大影响: MySQL Join Multiple Rows as Columns
如何优化这个查询?
【问题讨论】:
-
想要这样的东西似乎是初学者的错误。通常您应该简单地接受列数是静态的。如果您想要动态数量的列,则必须动态生成查询,这对性能来说确实很糟糕。
-
很难(如果不是不可能的话)想出一个有用的合理场景。您似乎正在尝试在数据库中做一些您应该在应用程序中做的事情。
标签: mysql sql query-optimization