如何使用 where 索引优化查询?
How I can optimize query with where index?
我有疑问
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
和table
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,2) NOT NULL,
change_7d double(8,2) NOT NULL,
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;
它包含超过 10 000 000 行,查询需要
显示第 0 - 24 行(共 32584 行,查询耗时 27.8344 秒。)
但没有 currency_id = 1
,它需要 4 秒。
更新 1
好的,我将密钥从 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 BY
与 GROUP BY
具有相同的列可以避免排序。 (在您的查询中,顺序可能略有不同,但可能无关紧要。)
数据类型问题...
BIGINT
占用8个字节; INT
仅占用 4 个字节,通常 足够大。缩小 table 提供了一些速度。
double(8,2)
占用 8 个字节 -- 不要在 FLOAT
或 DOUBLE
上使用 (m,n)
;它增加了一个额外的舍入。也许你的意思是 DECIMAL(8,2)
,占用 4 个字节。
我有疑问
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
和table
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,2) NOT NULL,
change_7d double(8,2) NOT NULL,
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;
它包含超过 10 000 000 行,查询需要
显示第 0 - 24 行(共 32584 行,查询耗时 27.8344 秒。)
但没有 currency_id = 1
,它需要 4 秒。
更新 1
好的,我将密钥从 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 BY
与 GROUP BY
具有相同的列可以避免排序。 (在您的查询中,顺序可能略有不同,但可能无关紧要。)
数据类型问题...
BIGINT
占用8个字节;INT
仅占用 4 个字节,通常 足够大。缩小 table 提供了一些速度。double(8,2)
占用 8 个字节 -- 不要在FLOAT
或DOUBLE
上使用(m,n)
;它增加了一个额外的舍入。也许你的意思是DECIMAL(8,2)
,占用 4 个字节。