我有一个SQL查询,它提供了正确的结果,但执行速度太慢。
查询对以下三个表进行操作:
customers
包含许多客户数据,如姓名,地址,电话
为简化表格,我只使用名称。
customdatas
包含某些自定义(非客户)数据。 (该
表格是用软件创建的,这就是复数形式错误的原因
对于这个表)
customercustomdatarels
将自定义数据与客户关联。
客户
Id Name (many more columns)
-----------------------------------------------------------------------
8053c6f4c5c5c631054ddb13d9186117 MyCustomer ...
2efd2aa5711ddfade1f829b12dd88cf3 CheeseFactory ...
的CustomData
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
如何优化此查询?
答案 0 :(得分:3)
我不明白你在group_concat()
语句中使用子查询的原因。这不会产生你真正想要运行的代码吗?
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT('MAX(CASE WHEN ckm.colkey = ', colkey, ' THEN ccd.value 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;
注意:这是未经测试的,但想法是一样的。使用主from
语句中的值来表示您的工作,而不是使用一些额外的,不必要的子查询中的值。