【问题标题】:MYSQL slow duration or fetch time depending on "distinct" commandMYSQL 缓慢的持续时间或获取时间取决于“不同”命令
【发布时间】:2016-05-01 02:52:34
【问题描述】:

我有一个非常小、简单的 MYSQL 表,用于保存预先计算的财务数据。该表如下所示: 参考日期 |仪器| rate|startDate |maturityDate|carry1|carry2|carry3

3 个索引定义为:

唯一的 unique_ID(refDate,instrument)

参考日期(参考日期)

仪器(仪器)

目前的行数约为 1000 万,但对于每个 refDate,目前只有大约 5000 个不同的工具

我有一个查询,它在此表上自连接以生成如下输出: refDate|利率工具=X |利率工具 = Y|评级工具=Z|....

基本上返回时间序列数据,然后我可以在其中进行自己的分析。

问题出在:我原来的查询是这样的:

Select distinct AUDSpot1yFq.refDate,AUDSpot1yFq.rate as 'AUDSpot1yFq',
AUD1y1yFq.rate as AUD1y1yFq
from audratedb AUDSpot1yFq inner join audratedb AUD1y1yFq on
AUDSpot1yFq.refDate=AUD1y1yFq.refDate 
where AUDSpot1yFq.instrument = 'AUDSpot1yFq' and 
AUD1y1yFq.instrument = 'AUD1y1yFq' 
order by AUDSpot1yFq.refDate

注意,在下面这个特定的时间查询中,我实际上得到了 10 种不同的工具,这意味着查询要长得多,但遵循相同的命名模式、内部连接和 where 语句。

这很慢,在工作台中我将其计时为 7-8 秒的持续时间(但接近 0 获取时间,因为我在运行服务器的机器上有工作台)。当我剥离不同的,持续时间下降到 0.25-0.5 秒(更易于管理),当我剥离“order by”时,它变得更快(

当我对缩减的查询(具有可怕的获取时间)运行解释时,我得到:

1   SIMPLE  AUDSpot1yFq     ref unique_ID,refDate,instrument    instrument  39  const   1432    100.00  Using where
1   SIMPLE  AUD1y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where
1   SIMPLE  AUD2y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where
1   SIMPLE  AUD3y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where
1   SIMPLE  AUD4y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where
1   SIMPLE  AUD5y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where
1   SIMPLE  AUD6y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where
1   SIMPLE  AUD7y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where
1   SIMPLE  AUD8y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where
1   SIMPLE  AUD9y1yFq       ref unique_ID,refDate,instrument    unique_ID   42  historicalratesdb.AUDSpot1yFq.refDate,const 1   100.00  Using where

我现在意识到不需要 distinct,当我将输出输出到数据框时,我可以丢弃并在 pandas 中排序。这太棒了。但我不知道如何缩短 Fetch 时间。我不会在这个网站上赢得任何能力竞赛,但我已经尽可能多地搜索并且找不到这个问题的解决方案。非常感谢任何帮助。

~可可

【问题讨论】:

  • 嗨社区,我不确定为什么这个解决方案有效(考虑到我没有认为我在获取时间方面以非常有意义的方式更改了查询)但似乎我的时间基本上崩溃了在我更改 innodb_buffer_pool_size(从 1G 到 2G)后,我希望尽可能快。我想更改请求,当您从 select 语句中删除“distinct”时,任何人都可以解释这种行为发生如此巨大的变化吗?数据是否变得更难拼接在一起?如果我改为使用子选择查询,它的性能会更好吗?

标签: mysql optimization distinct fetch duration


【解决方案1】:

该问题未提及现有索引,也未显示任何查询的 EXPLAIN 输出。

提高性能的快速方法是添加索引:

   ... ON audratedb (instrument,refdate,rate)

要回答我们为什么要添加该索引,我们需要了解 MySQL 如何处理 SQL 语句、哪些操作是可能的以及哪些是必需的。要查看 MySQL 是如何实际处理您的语句的,您需要使用 EXPLAIN 来查看查询计划。

【讨论】:

  • 在上面添加了一个解释语句,使我在桌面上的索引更加明显。具体来说,有3个指标,refDate,instrument,和一个唯一索引(refDate,instrument)
【解决方案2】:

(我必须简化表别名才能阅读它:)

Select  distinct
           s.refDate,
           s.rate as AUDSpot1yFq,
           y.rate as AUD1y1yFq
    from  audratedb AS s
    join  audratedb AS y  on s.refDate = y.refDate
    where  s.instrument = 'AUDSpot1yFq'
      and  y.instrument = 'AUD1y1yFq'
    order by  s.refDate 

需要索引:

INDEX(instrument, refDate)  -- To filter and sort, or
INDEX(instrument, refDate, rate)  -- to also "cover" the query.

假设查询并不比你说的复杂。我看到EXPLAIN 已经有更多的表了。请提供SHOW CREATE TABLE audratedb 和整个SELECT

回到你的问题...

DISTINCT 是通过以下两种方式之一完成的:(1) 对表进行排序,然后进行 dedup,或 (2) 在内存中的哈希中进行 dedup。请记住,您正在删除所有 3 列(refDate、s.rate、y.rate)。

ORDER BY 是收集所有数据后的排序。但是,使用建议的索引(不是您拥有的索引),不需要排序,因为索引将按所需顺序获取行。

但是...同时拥有DISTINCTORDER BY both 可能会使优化器感到困惑,以至于它会做一些“愚蠢”的事情。

你说(refDate,instrument)UNIQUE,但你没有提到PRIMARY KEY,也没有提到你使用的是哪个引擎。如果您使用 InnoDB,那么PRIMARY KEY(instrument, refDate)按此顺序,将进一步加快速度,并避免需要任何新索引。

此外,拥有(a,b)(a) 是多余的。也就是说,您当前的架构不需要INDEX(refDate),但是通过更改PK,您将不需要INDEX(instrument)

底线:仅

PRIMARY KEY(instrument, refDate),
INDEX(refDate)

并且没有其他索引(除非您可以显示一些需要它的查询)。

更多关于EXPLAIN。注意Rows 列是如何表示 1432, 1, 1, ... 这意味着它扫描了第一个表的估计 1432 行。由于缺乏适当的索引,这可能远远超过必要的。然后它只需要查看其他每个表中的 1 行。 (没有比这更好的了。)

SELECT 中有多少行没有DISTINCTORDER BY?这告诉您在进行提取和JOINing 之后 需要多少工作。我怀疑它只是少数。对于DISTINCTORDER BY,“少数”真的很便宜;因此,我认为您在吠叫错误的树。即使是 1432 行,处理起来也很快。

至于buffer_pool...表有多大?做SHOW TABLE STATUS。我怀疑该表超过 1GB,因此它无法放入 buffer_pool。因此,提高缓存大小将使查询在 RAM 中运行,而不是撞到磁盘(至少在它被缓存之后)。请记住,在冷缓存上运行查询将有大量 I/O。随着缓存预热,查询将运行得更快。但如果缓存太小,您将继续需要 I/O。 I/O 是处理过程中最慢的部分。

我希望您至少有 6GB 的 RAM;否则,2G 可能会大到危险的地步。交换对性能非常不利。

【讨论】:

  • 瑞克,感谢您的帮助。将您标记为已回答该问题,因为基本上您已经教会了我足够多的知识来解决这个问题。好像是我的桌子。我现在从您的回答中了解到我应该显示哪些额外数据(例如,该表中有大约 10 mio 行,返回结构有 1432 行)。再次感谢,
猜你喜欢
  • 2012-03-14
  • 2019-10-28
  • 1970-01-01
  • 2022-10-14
  • 2016-04-12
  • 1970-01-01
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多