2011-09-24 748 views
9

这是一个奇怪的。我试图在MySQL中使用视图(我对MySQL有相当的新意,并且有更多的Sybase和SQL Server的经验)。任何方式这个新项目我们使用MySQL,因为它似乎有良好的性能。然而,为了更简单地查询网络前端,我们决定创建一些视图,一切运行良好,但它们需要永远运行。MySQL - 视图 - 超慢查询

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

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秒)。所以我想也许有一些优化或查询缓存,不适用于视图或可能有一些我们已经错过了在MySQL配置设置。但是有什么办法可以加速这个视图,所以它只是这个查询的一个很好的占位符?

运行EXPLAIN在两个查询: 正常的选择给出了:

1,操作简便,classifier_results,ALL,idx_date,,,,594845,使用其中;使用临时;使用文件排序

的视图中选择给出:

1,PRIMARY,ALL,,,,,100,
2,衍生classifier_results,ALL,idx_date,,,,594845,使用哪里;使用临时;使用文件排序

+0

如果在查看和从视图中选择时使用EXPLAIN,你会得到不同的结果吗? – Cocowalla

+0

已添加到问题中。查询计划看起来是一样的,即时假设eprimary只是从视图返回,因为它是嵌套在某种意义上,没有什么可以指示20秒+额外运行.... – NightWolf

+1

我认为'DERIVED'意味着它正在使用一个临时表,这是杀害性能 – Cocowalla

回答

0

尝试重新创建一个使用此视图:关于MySQL的观点处理算法

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 

更多信息,可以发现。

+0

好的感谢为此链接。之前的观点是未定义的。通过尝试将算法更改为MERGE给出: 0行受影响,1警告: 1354现在无法在此处使用视图合并算法(假定未定义的算法)。试图用TEMPTABLE算法创建视图很好。所以用UNDEFINED即时猜测它可能使用TempTable作为未定义似乎在合并和可测试之间做出选择。所以这可能是问题,因为手册说合并更有效率...... – NightWolf

+0

尝试从视图中删除'ORDER BY'子句并查看它是否可以使用MERGE'算法 – Cocowalla

+0

删除ORDER BY仍然不希望作为合并工作。 '1354查看合并算法现在不能在这里使用(假定未定义算法)' – NightWolf

0

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

1

这是一个非常普遍的问题。编写DRY,可重用的SQL可能非常困难。尽管我找到了一个解决方法。首先,正如其他人已经指出的那样,您可以并且应该使用VIEW来尽可能地使用set ALGORITHM = MERGE来完成此操作,以便使用它们的任何查询都在合并SQL语句的where子句上进行了优化,而不是使用VIEW评估可能是灾难性大的整个视图。

在这种情况下,由于组/计数方面的原因您不能使用MERGE,因此您可能需要尝试使用创建临时会话表的存储过程作为解决方法。

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

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

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子句参数),或以任何其他查询加盟。

该表是一个会话临时表,因此它会持续超出对该过程的调用。调用代码可以在完成数据后将其删除,或者在会话结束或随后调用存储区时自动启动。

希望有帮助。