【发布时间】:2021-11-16 08:08:24
【问题描述】:
我有这个表架构:
CREATE TABLE `exchange` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`exchange` double unsigned NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`platform_id` bigint unsigned NOT NULL,
`product_id` bigint unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `exchange_created_at_index` (`created_at`),
KEY `exchange_product_id_created_at_id_index` (`product_id`,`created_at`,`id`),
KEY `exchange_product_id_created_at_platform_id_id_index` (`product_id`,`created_at`,`platform_id`,`id`),
KEY `exchange_platform_fk` (`platform_id`),
KEY `exchange_platform_id_created_at_id_index` (`platform_id`,`created_at`,`id`),
CONSTRAINT `exchange_platform_fk` FOREIGN KEY (`platform_id`) REFERENCES `platform` (`id`) ON DELETE CASCADE,
CONSTRAINT `exchange_product_fk` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
这个表大约有 14.761.479 行
我正在尝试优化这个查询:
SELECT *
FROM `exchange`
WHERE (
`created_at` >= '2021-09-17 22:36:11'
AND `platform_id` = 1
AND `id` IN (
SELECT MIN(`id`)
FROM `exchange`
WHERE `created_at` >= '2021-09-17 22:36:11'
GROUP BY `product_id`
)
);
425 rows in set (14,69 sec)
仅子查询大约需要 2 秒:
SELECT MIN(`id`)
FROM `exchange`
WHERE `created_at` >= '2021-09-17 22:36:11'
GROUP BY `product_id`;
729 rows in set (2,11 sec)
解释是:
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: exchange
partitions: NULL
type: ref
possible_keys: exchange_created_at_index,exchange_platform_fk,exchange_platform_id_created_at_id_index
key: exchange_platform_fk
key_len: 8
ref: const
rows: 6955794
filtered: 50.00
Extra: Using where
*************************** 2. row ***************************
id: 2
select_type: SUBQUERY
table: exchange
partitions: NULL
type: index
possible_keys: exchange_created_at_index,exchange_product_id_created_at_id_index,exchange_product_id_created_at_platform_id_id_index
key: exchange_product_id_created_at_id_index
key_len: 21
ref: NULL
rows: 13911589
filtered: 50.00
Extra: Using where; Using index
2 rows in set, 1 warning (0,00 sec)
和警告:
Level: Note
Code: 1003
Message: /* select#1 */ select `crypto`.`exchange`.`id` AS `id`,`crypto`.`exchange`.`exchange` AS `exchange`,`crypto`.`exchange`.`created_at` AS `created_at`,`crypto`.`exchange`.`platform_id` AS `platform_id`,`crypto`.`exchange`.`product_id` AS `product_id` from `crypto`.`exchange` where ((`crypto`.`exchange`.`platform_id` = 1) and (`crypto`.`exchange`.`created_at` >= TIMESTAMP'2021-09-17 22:36:11') and <in_optimizer>(`crypto`.`exchange`.`id`,`crypto`.`exchange`.`id` in ( <materialize> (/* select#2 */ select min(`crypto`.`exchange`.`id`) from `crypto`.`exchange` where (`crypto`.`exchange`.`created_at` >= TIMESTAMP'2021-09-17 22:36:11') group by `crypto`.`exchange`.`product_id` having true ), <primary_index_lookup>(`crypto`.`exchange`.`id` in <temporary table> on <auto_distinct_key> where ((`crypto`.`exchange`.`id` = `<materialized_subquery>`.`MIN(``id``)`))))))
1 row in set (0,00 sec)
为什么在 PRIMARY 查询中 EXPLAIN key 仅是 exchange_platform_fk 而不是 exchange_platform_id_created_at_id_index?
我需要添加哪些索引来优化这个查询?
将 WHERE 条件移至子查询最差:
SELECT *
FROM `exchange`
WHERE (
`id` IN (
SELECT MIN(`id`)
FROM `exchange`
WHERE (
`created_at` >= '2021-09-17 22:36:11'
AND `platform_id` = 1
)
GROUP BY `product_id`
)
);
425 rows in set (19,86 sec)
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: exchange
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 13911589
filtered: 100.00
Extra: Using where
*************************** 2. row ***************************
id: 2
select_type: SUBQUERY
table: exchange
partitions: NULL
type: ref
possible_keys: exchange_created_at_index,exchange_product_id_created_at_id_index,exchange_product_id_created_at_platform_id_id_index,exchange_platform_fk,exchange_platform_id_created_at_id_index,exchange_platform_id_created_at_index
key: exchange_platform_fk
key_len: 8
ref: const
rows: 6955794
filtered: 50.00
Extra: Using where; Using temporary
2 rows in set, 1 warning (0,00 sec)
谢谢!
【问题讨论】:
-
很难找到提供正确信息的查询优化问题。你的可以。谢谢。
标签: mysql query-optimization explain