MySQL - 视图 - 超慢查询

时间:2011-09-24 03:54:22

标签: mysql sql view query-optimization

这很奇怪。我正在尝试在MySQL中使用Views(对于具有Sybase和SQL Server的更多经验,我是MySQL的新手)。无论如何,这个新项目我们都在使用MySQL,因为它似乎具有良好的性能。然而,为了简化Web前端的查询,我们决定创建一些视图,一切都运行良好,但它们需要永远运行。

视图非常简单,只需选择语句(这些表中确实有几百万行)。比如说这个查询:

SELECT CAST(classifier_results.msgDate as DATE) AS mdate
       ,classifier_results.objClass AS objClass
       ,COUNT(classifier_results.objClass) AS obj
       ,classifier_results.subjClass AS subjClass
       ,COUNT(classifier_results.subjClass) AS subj 
FROM classifier_results 
WHERE (classifier_results.msgDate >= (curdate() - 20)) 
GROUP BY 
  CAST(classifier_results.msgDate as DATE)
  ,classifier_results.objClass
  ,classifier_results.subjClass 
ORDER BY classifier_results.msgDate DESC

以普通方式运行时,大约需要1.5秒才能返回结果。

然而,当这个查询被放入视图中时(即) - 即

CREATE VIEW  V1a_sentiment_AI_current AS    
SELECT CAST(classifier_results.msgDate as DATE) AS mdate
       ,classifier_results.objClass AS objClass
       ,COUNT(classifier_results.objClass) AS obj
       ,classifier_results.subjClass AS subjClass
       ,COUNT(classifier_results.subjClass) AS subj 
FROM classifier_results 
WHERE (classifier_results.msgDate >= (curdate() - 20)) 
GROUP BY 
  CAST(classifier_results.msgDate as DATE)
  ,classifier_results.objClass
  ,classifier_results.subjClass 
ORDER BY classifier_results.msgDate DESC

查询大约需要10倍(22-30秒)。所以我想也许有一些优化或查询缓存不能与Views一起使用,或者我们在MySQL配置中错过了一些设置。但有没有办法加快这个视图,所以它只是这个查询的一个不错的占位符?

对两个查询运行EXPLAIN: 正常选择给出:

  

1,SIMPLE,classifier_results,ALL,idx_date ,,,, 594845,使用where;使用临时;使用filesort

视图选择给出:

  

1,PRIMARY ,, ALL ,,,,, 100,
  2,DERIVED,classifier_results,ALL,idx_date ,,,, 594845,使用where;使用临时;使用filesort

3 个答案:

答案 0 :(得分:1)

这是一个非常常见的问题。编写DRY,可重用的SQL可能非常困难。我找到了一种解决方法。

首先,正如其他人所指出的,你可以而且应该使用VIEWs尽可能使用set ALGORITHM = MERGE来执行此操作,以便使用它们的任何查询在合并的SQL语句的where子句上进行优化,而不是使VIEW评估整个视图,这可能是灾难性的大。

在这种情况下,由于组/计数方面您无法使用MERGE,因此您可能希望尝试使用创建临时会话表的存储过程作为变通方法。

这种技术允许您编写可重用的查询,这些查询可以从中间件/框架代码访问,并从其他存储过程中调用,因此您可以保持代码包含,可维护和可重用。

即。如果您事先知道将在某些条件下过滤查询,请将它们放在存储过程中。 (对数据集进行后置过滤或组合可能更有效 - 这取决于您如何使用数据以及需要哪些常用集合。)

CREATE PROCEDURE sp_create_tmp_V1a_sentiment_AI_current(parm1, parm2 etc)
BEGIN

  drop temporary table if exists tmp_V1a_sentiment_AI_current;

  create temporary table tmp_V1a_sentiment_AI_current
  as
  SELECT CAST(classifier_results.msgDate as DATE) AS mdate
         ,classifier_results.objClass AS objClass
         ,COUNT(classifier_results.objClass) AS obj
         ,classifier_results.subjClass AS subjClass
         ,COUNT(classifier_results.subjClass) AS subj 
  FROM classifier_results 
  WHERE (classifier_results.msgDate >= (curdate() - 20)) 
  -- and/or other filters on parm1, parm2 passed in
  GROUP BY 
    CAST(classifier_results.msgDate as DATE)
    ,classifier_results.objClass
    ,classifier_results.subjClass 
  ORDER BY classifier_results.msgDate DESC;

END;

现在,只要您需要处理这些数据,就可以调用该过程,然后选择结果(可能还有其他where子句参数),或者在任何其他查询中加入它。

该表是一个会话临时表,因此它将持续超出对该过程的调用。调用代码可以在数据完成后丢弃,也可以在会话进行或后续调用sproc时自动进行。

希望有所帮助。

答案 1 :(得分:0)

尝试使用以下方法重新创建视图:

CREATE ALGORITHM = MERGE VIEW `V1a_sentiment_AI_current` AS    
SELECT CAST(classifier_results.msgDate as DATE) AS mdate
   ,classifier_results.objClass AS objClass
   ,COUNT(classifier_results.objClass) AS obj
   ,classifier_results.subjClass AS subjClass
   ,COUNT(classifier_results.subjClass) AS subj 
FROM classifier_results 
WHERE (classifier_results.msgDate >= (curdate() - 20)) 
GROUP BY 
  CAST(classifier_results.msgDate as DATE)
  ,classifier_results.objClass
  ,classifier_results.subjClass 
ORDER BY classifier_results.msgDate DESC

可以找到有关MySQL视图处理算法的更多信息here

答案 2 :(得分:0)

由于select列表中的count()聚合,

此处不能使用MERGE;在这些情况下,它可能有助于指定TEMPTABLE以保存引擎不必在它们之间做出决定。一旦我决定使用哪种算法,我会查看EXPLAIN计划并尝试添加索引提示或找到缺失的索引。