簡體   English   中英

MySQL - 視圖 - 超慢查詢

[英]MySQL - Views - Super slow query

這很奇怪。 我正在嘗試在MySQL中使用Views(對於具有Sybase和SQL Server的更多經驗,我是MySQL的新手)。 無論如何,這個新項目我們都在使用MySQL,因為它似乎具有良好的性能。 然而,為了簡化Web前端的查詢,我們決定創建一些視圖,一切都運行良好,但它們需要永遠運行。

視圖非常簡單,只是select語句(這些表中確實有幾百萬行) 比如說這個查詢:

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

這是一個非常普遍的問題。 編寫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時自動進行。

希望這很有幫助。

嘗試使用以下方法重新創建視圖:

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視圖處理算法的更多信息,請參見此處

由於select列表中的count()聚合,因此無法在此處使用MERGE; 在這些情況下,它可能有助於指定TEMPTABLE以保存引擎不必在它們之間做出決定。 一旦我決定使用哪種算法,我會查看EXPLAIN計划並嘗試添加索引提示或找到缺少的索引。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM