【问题标题】:How can I optimize a query that returns a lot of records, then order by a date field and return only the latest one? [duplicate]如何优化返回大量记录的查询,然后按日期字段排序并仅返回最新记录? [复制]
【发布时间】:2018-03-18 05:26:56
【问题描述】:

我不是很喜欢数据库,我对这个查询的可能优化有以下疑问(在 MySql 数据库上定义):

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

它包含大量的连接只是因为表中的信息非常规范。

此查询返回特定市场(**WHERE MD.id = 4)中商品的最后价格(AND CD.id = 4)相关信息。

所以我首先检索特定市场中特定商品的所有价格列表(可能是很多记录),然后我这样做:

ORDER BY price_date DESC LIMIT 1

我认为这种方式可能在计算上可能会很昂贵,因为查询的第一部分(除了最后一个 ORDER BY 语句之外的整个查询将检索大量记录,然后必须对其进行排序。

有问题吗?最终,优化此查询的明智策略是什么? (我不知道...)

【问题讨论】:

  • 查询的编写方式没什么可做的。它归结为使用适当的索引。发布EXPLAIN <your_query>;的结果
  • @fancyPants ehhh 我的疑问是:这个查询可以用更好的方式编写吗?
  • 查询看起来不错,运行需要多长时间?
  • @AndreaNobili 没有比这更好的了。这个查询没有什么复杂的。这是直截了当的。您只需加入一些表并读取数据。而已。这里没有什么可重写的。
  • 如果查询运行时间过长,问题往往出在数据结构本身,而不是查询上。正如@fancyPants 建议的那样,您应该确保使用正确的索引,这将有助于使查询运行得比查询本身的任何“优化”都快得多。

标签: mysql sql database query-optimization rdbms


【解决方案1】:

完整性检查...MD_CD.commodity_details_idCN.commodity_details_id 不同吗?还是打错字了?

摆脱

INNER JOIN Languages AS LN ON CN.language_id  = LN.id
 ...
AND LN.id=1

相反,只需使用AND CN.language_id = 1

在尝试配方时运行EXPLAIN SELECT ...

似乎大多数事情都以commodity_details_id = 4 为中心。所以说AND MD_CD.commodity_details_id = 4,而不是MD.id = 4CD.id = 4

现在,让我们尝试重新制定它以提高一点效率。让我们从主过滤器开始——AND MD_CD.commodity_details_id = 4,让我们说FROM MD_CD JOIN ...。然后添加JOINs,直到我们可以到达MCPS.price_dateso we can work onORDER BY price_date DESC LIMIT 1`:

SELECT very-few-columns
    FROM MD_CD
    JOIN ...  (the minimal set of tables)
    JOIN MCPS ON ...
    WHERE MD_CD.commodity_details_id = 4
    ORDER BY MCPS.price_date DESC LIMIT 1

在继续之前,调试上面的代码以确保它提供了正确的一行。

要完成查询,有两种方法:

计划 A:使用“派生表”并在以下位置添加更多 JOIN:

SELECT lots-of-stuff
    FROM ( the above query ) AS x
    JOIN the rest of the tables

B 计划:在 SELECT 中对缺失的列使用子查询:

SELECT some stuff,
       ( SELECT commodity_name_en FROM CN
             WHERE commodity_details_id = CD.id ) AS commodity_name_en,
       etc
    FROM ... (as above)

(请注意我在 http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table 中关于多对多模式的建议)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-05
    • 1970-01-01
    相关资源
    最近更新 更多