簡體   English   中英

優化查詢以返回大量記錄,這是避免數百個聯接的一種方式。 這是一個聰明的解決方案嗎?

[英]Optimizing a query returning a lot of records, a way to avoid hundreds of join. Is it a smart solution?

我不是很聰明的SQL,並且對如何優化查詢存在以下疑問。 我正在使用MySql

我有這個數據庫架構:

在此處輸入圖片說明

這是將特定商品進入特定市場的最后價格( Market_Commodity_Price_Series表中的最后日期)返回的查詢。

它包含許多聯接以檢索所有相關信息:

SELECT MCPS.id AS series_id,
        MD_CD.market_details_id AS market_id,
        MD_CD.commodity_details_id AS commodity_id,
        MD.market_name AS market_name,
        MCPS.price_date AS price_date,
        MCPS.avg_price AS avg_price,
        CU.ISO_4217_cod AS currency, 
        MU.unit_name AS measure_unit, 
        CD.commodity_name_en,
        CN.commodity_name 
FROM Market_Commodity_Price_Series AS MCPS
INNER JOIN MeasureUnit AS MU ON MCPS.measure_unit_id = MU.id
INNER JOIN Currency AS CU ON MCPS.currency_id = CU.id
INNER JOIN MarketDetails_CommodityDetails AS MD_CD ON MCPS.market_commodity_details_id = MD_CD.id
INNER JOIN MarketDetails AS MD ON MD_CD.market_details_id = MD.id
INNER JOIN CommodityDetails AS CD ON MD_CD.commodity_details_id = CD.id
INNER JOIN CommodityName AS CN ON CD.id = CN.commodity_details_id
INNER JOIN Languages AS LN ON CN.language_id  = LN.id
WHERE MD.id = 4
AND CD.id = 4 
AND LN.id=1
ORDER BY price_date DESC LIMIT 1

我的疑問是:使用上一個查詢,我將從Market_Commodity_Price_Series表中提取與特定商品有關的所有記錄到特定市場中,進行大量聯接 ,並根據price_date字段整理這些記錄並限制為最后一個。

我認為這可能會花費很多,因為我可以擁有很多記錄(因為Market_Commodity_Price_Series表包含每日信息)。

該查詢有效,但我認為可以通過更智能的方式來完成。

所以我認為我可以做這樣的事情:

1)使用類似這樣的查詢來選擇與特定商品的最后價格進入特定市場有關的記錄:

SELECT measure_unit_id, 
        currency_id, 
        market_commodity_details_id, 
        MAX(price_date) price_date
FROM Market_Commodity_Price_Series  AS MCPS 
INNER JOIN MarketDetails_CommodityDetails AS MD_CD ON MCPS.market_commodity_details_id = MD_CD.id
WHERE MD_CD.market_details_id = 4
AND MD_CD.commodity_details_id = 4
GROUP BY measure_unit_id, currency_id, market_commodity_details_id

返回與該信息有關的單個記錄:

measure_unit_id      currency_id          market_commodity_details_id price_date
--------------------------------------------------------------------------------
1                    2                    24                          05/10/2017

像表一樣使用此輸出(我不知道確切的名稱,也許是視圖?),然后將此“表”與MeasureUnit,Currency,MarketDetails,CommodityDetails,CommodityName和Languages表中的其他必需信息連接。

我認為可能會更好,因為這樣我將使用MAX(price_date)price_date僅將與最新價格相關的記錄提取到Market_Commodity_Price_Series中,而不是獲取所有記錄,從而對最新記錄進行排序和限制。

此外,大多數JOIN操作都在執行上一個查詢返回的單個記錄,而不是在我的查詢的第一個版本返回的所有記錄上執行(可能是成百上千個)。

可能是一個聰明的解決方案?

如果是,那么此查詢的輸出(將其視為表)與其他表的正確語法是什么?

JOIN尤其是在主鍵上-不一定昂貴。 看起來您的聯接正在遵循數據模型。

如果不了解查詢的性能特征,就不會開始優化查詢。 運行需要多長時間? 要對多少條記錄進行排序以獲取最新記錄?

您的WHERE子句似乎在極大地限制數據。 您還可以設置索引以幫助使用WHERE子句子句-但是,由於字段來自不同的表,因此使用索引或全部使用索引可能很棘手。

您有一個復雜的數據模型,很難遵循。 由於多個nm關系,您似乎正在獲得笛卡爾積。 如果是這樣,那可能會對性能產生很大的影響,並且沿着每個維度預聚合數據是正確的方法。

但是,如果不了解當前查詢的行為,我就不會開始優化查詢。

一種方法是制作一個單獨的讀取模型表,它來自CQRS方法 ,其中包含僅用於選擇且不包含任何聯接的所有必需屬性,但是每次其他一些表更改一個時,您將需要更新讀取模型表。創建一個視圖

您在編寫有效查詢方面做得相當不錯。

您沒有使用SELECT * ,因為它會產生腫且多余的中間結果集,因此可能會破壞具有大量聯接的查詢的性能。 但是您的中間結果集(您對ORDER BY應用的結果集)並沒有腫。

您的WHERE col = val子句主要提到表的主鍵(我想)。 那很好。

您的大表Market_Commodity_Price_Series可能使用復合覆蓋索引 同樣,其他一些表可能需要這種索引。 但這應該是另一個問題的話題。

如果您正在執行ORDER BY ... LIMIT並使用LIMIT函數丟棄大部分結果,則建議的優化方法(訂購主要由id值組成的中間結果集)將大有幫助。 但是您沒有這樣做。

如果不了解您的數據,就很難提供明確的意見。 但是,如果是我,我將使用您的第一個查詢。 在您投入生產時(以及其他復雜的查詢中),我會密切注意。 當(如果不是)性能開始下降時,則可以執行EXPLAIN並找出索引表的最佳方法。 您已經編寫了一個可以使您的應用程序啟動並運行的查詢,已經做得很好。 去吧!

暫無
暫無

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

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