MYSQL 慢持续时间或获取时间取决于"distinct"命令



我有一个非常小,简单的MYSQL表,用于保存预先计算的财务数据。 该表如下所示:参考日期 |学院 |利率|开始日期 |到期日期|结转1|进位2|进位3

3 个指数定义为:

唯一unique_ID(参考日期,仪器)

引用日期

(引用日期)

仪器

(仪器)

现在大约有 1000 万行,尽管对于每个 refDate,现在只有大约 5000 种不同的工具

我有一个查询,它自联接在此表上以生成如下输出:参考日期|汇率工具=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 秒(更易于管理),当我剥离"排序依据"时,它变得更快(<0.1 秒,此时我不在乎)。 但是我的获取时间爆炸到~7秒。 所以总的来说,我一无所获,但它都变成了获取时间问题。 当我从将执行提升和工作的 python 脚本运行此查询时,无论是否包含不同的内容,我都会得到大致相同的时间。

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

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 不是必需的,当我将输出到数据帧时,我可以在熊猫中抛出和排序排序。 真棒。 但是我不知道如何缩短获取时间。 我不会在这个网站上赢得任何能力竞赛,但我已经尽可能多地搜索了,找不到这个问题的解决方案。 任何帮助将不胜感激。

~可可

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

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) 对表进行排序,然后进行重复排序,或 (2) 在内存中的哈希中执行重复数据删除。 请记住,您正在删除所有 3 列(refDate、s.rate、y.rate)。

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

但。。。 同时使用DISTINCTORDER BY可能会使优化器感到困惑,以至于它做了一些"愚蠢"的事情。

你说(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可能会大得很危险。 交换对性能非常不利。

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

提高性能的快速答案是添加索引:

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

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

最新更新