数据库
首页 > 数据库> > mysql-如何优化数据透视表的条件检查?

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