mysql-如何优化数据透视表的条件检查?
作者:互联网
在recent question中,StevieG向我展示了如何解决数据透视表的问题.新的问题是我必须检查数据透视表上的某些条件.让我们进行最后的查询:
SELECT
c.id,
GROUP_CONCAT(if(d.name = 'p1', d.value, NULL)) AS 'p1',
GROUP_CONCAT(if(d.name = 'p2', d.value, NULL)) AS 'p2',
GROUP_CONCAT(if(d.name = 'p3', d.value, NULL)) AS 'p3',
GROUP_CONCAT(if(d.name = 'p4', d.value, NULL)) AS 'p4',
GROUP_CONCAT(if(d.name = 'p5', d.value, NULL)) AS 'p5',
GROUP_CONCAT(if(d.name = 'p6', d.value, NULL)) AS 'p6'
FROM container c
JOIN data d ON c.id = d.container
GROUP BY c.id
显然,我无法添加WHERE子句(例如,如果我想检查p5> 30).我发现了两种方法可以解决此问题.首先是通过在派生表中进行转换:
SELECT * FROM (
SELECT
c.id,
GROUP_CONCAT(if(d.name = 'p1', d.value, NULL)) AS 'p1',
GROUP_CONCAT(if(d.name = 'p2', d.value, NULL)) AS 'p2',
GROUP_CONCAT(if(d.name = 'p3', d.value, NULL)) AS 'p3',
GROUP_CONCAT(if(d.name = 'p4', d.value, NULL)) AS 'p4',
GROUP_CONCAT(if(d.name = 'p5', d.value, NULL)) AS 'p5',
GROUP_CONCAT(if(d.name = 'p6', d.value, NULL)) AS 'p6'
FROM container c
JOIN data d ON c.id = d.container
GROUP BY c.id
) WHERE p5>30
我发现的另一种方法是添加HAVING子句:
SELECT
c.id,
GROUP_CONCAT(if(d.name = 'p1', d.value, NULL)) AS 'p1',
GROUP_CONCAT(if(d.name = 'p2', d.value, NULL)) AS 'p2',
GROUP_CONCAT(if(d.name = 'p3', d.value, NULL)) AS 'p3',
GROUP_CONCAT(if(d.name = 'p4', d.value, NULL)) AS 'p4',
GROUP_CONCAT(if(d.name = 'p5', d.value, NULL)) AS 'p5',
GROUP_CONCAT(if(d.name = 'p6', d.value, NULL)) AS 'p6'
FROM container c
JOIN data d ON c.id = d.container
GROUP BY c.id
HAVING p5>30
问题在于性能.我使用的测试数据库有50.000个条目,但产量可能高达100万.第一个句子(没有检查p5> 30的那个句子)在我的开发计算机(没有缓存)中执行1000个句子需要0’60秒,但是第二个和第三个句子要花5分钟以上的时间才能完成.
我知道有一个不带数据索引的隐式派生表生成,但是我有什么选择来优化它呢?
解决方法:
由于数据(容器,名称)是唯一的,因此您无需使用GROUP_CONCAT.
那这个呢:
SELECT
c.id,
d_p1.value AS 'p1',
d_p2.value AS 'p2',
d_p3.value AS 'p3',
d_p4.value AS 'p4',
d_p5.value AS 'p5'
FROM container AS c
LEFT JOIN data AS d_p1 ON (d_p1.container = c.id AND d_p1.name = 'p1')
LEFT JOIN data AS d_p2 ON (d_p2.container = c.id AND d_p2.name = 'p2')
LEFT JOIN data AS d_p3 ON (d_p3.container = c.id AND d_p3.name = 'p3')
LEFT JOIN data AS d_p4 ON (d_p4.container = c.id AND d_p4.name = 'p4')
LEFT JOIN data AS d_p5 ON (d_p5.container = c.id AND d_p5.name = 'p5')
WHERE d_p5.value > 30
如果数据(容器,名称)上有索引,则查询应在几秒钟内运行.
如果data.name的长度超过几个字符(例如5个字符),则应该使用替代键(整数)代替data.name.
标签:query-optimization,mysql 来源: https://codeday.me/bug/20191127/2074549.html