如何使用位置索引优化查询?

问题描述

我有疑问

select `price`,`asset_id` 
from `history_average_pairs` 
where `currency_id` = 1 
  and date(`created_at`) >= DATE_SUB(Now(),INTERVAL 7 DAY) 
group by hour(created_at),date(created_at),asset_id 
order by `created_at` asc

和桌子

CREATE TABLE IF NOT EXISTS history_average_pairs (
  id bigint(20) unsigned NOT NULL,asset_id bigint(20) unsigned NOT NULL,currency_id bigint(20) unsigned NOT NULL,market_cap bigint(20) NOT NULL,price double(20,6) NOT NULL,volume bigint(20) NOT NULL,circulating bigint(20) NOT NULL,change_1h double(8,2) NOT NULL,change_24h double(8,change_7d double(8,created_at timestamp NOT NULL DEFAULT current_timestamp(),updated_at timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),total_supply bigint(20) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE history_average_pairs
  ADD PRIMARY KEY (id),ADD KEY history_average_pairs_currency_id_asset_id_foreign (currency_id,asset_id),ALTER TABLE history_average_pairs
  MODIFY id bigint(20) unsigned NOT NULL AUTO_INCREMENT;

它包含超过1亿行,查询需要

显示0-24行(共32584行,查询耗时27.8344秒。)

但是如果没有currency_id = 1,则大约需要4秒钟。

更新1

Okey,我将密钥从currency_id,asset_id更新为currency_id,asset_id,created_at,并且花费了

显示0-24行(共32784行,查询耗时6.4831秒。)

它快得多,有任何提议可以更快地做到吗? GROUP BY在这里每小时仅排第一行。 例如:

19:01:10 
19:02:14 
19:23:15

我只需要19:01:10

解决方法

您可以重新定义过滤谓词,以避免在列上使用表达式。例如:

select max(`price`) as max_price,`asset_id` 
from `history_average_pairs` 
where `currency_id` = 1 
  and created_at >= date_add(curdate(),interval - 7 day)
group by hour(created_at),date(created_at),asset_id 
order by `created_at` asc

然后,如果您添加索引,此查询可能会更快:

create index ix1 on `history_average_pairs` (`currency_id`,created_at);
,

您必须使测试“可更改”;改变

date(`created_at`) >= DATE_SUB(NOW(),INTERVAL 7 DAY)

created_at >= CURDATE() - INTERVAL 7 DAY

则最佳索引为

INDEX(currency_id,-- 1st because of "=" test
      created_at,-- 2nd to finish out WHERE
      asset_id)      -- only for "covering"

设计索引时,通常通常最好先处理WHERE

GROUP BY无法使用索引。你真的想要第一个小时吗?

“我只需要19:01:10”尚不清楚,因此我没有考虑在内。日期在哪里? asset_id在哪里?请参阅“ only_full_group_by”。您是否需要“ groupwise max”?

使ORDER BYGROUP BY具有相同的列可以避免排序。 (在您的查询中,顺序可能会稍有不同,但是可能没关系。)

数据类型问题...

  • BIGINT占用8个字节; INT仅占用4个字节,并且通常足够大。缩小桌子可以加快速度。
  • double(8,2)占用8个字节-请勿在{{1​​}}或(m,n)上使用FLOAT;它增加了一个额外的舍入。也许您的意思是DOUBLE,它需要4个字节。