我正在使用历史表,这些表存储“真实”表中的每个更改。
在时间戳列表中检索数据的那一刻,性能是可怕的。
这是我的表格的简化版本。
CREATE TABLE `changes` (
`ts` datetime DEFAULT NULL
) ENGINE=InnoDB;
CREATE TABLE `history` (
`h_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`start_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`end_ts` timestamp NULL DEFAULT NULL,
`pk` int(11) DEFAULT NULL,
`note` mediumtext,
PRIMARY KEY (`h_id`),
KEY `history_pk_ts_tsev_IDX` (`pk`,`start_ts`,`end_ts`) USING BTREE
) ENGINE=InnoDB;
这是我正在运行的查询:
SELECT * FROM `changes` AS `c`
JOIN `history` AS `h`
ON (`h`.`pk` = 9999
AND `c`.`ts` >= `h`.`start_ts`
AND `c`.`ts` < IFNULL(`h`.`end_ts`, `c`.`ts` + 1)
)
在 2.500 行changes
和 55.000 行中history
,查询需要大约 8 秒来获取第一行,大约需要 2 分钟来获取所有行。
这些表会增长得非常快,很快就会存储数百万行。
这是解释结果:
|id |select_type |table |partitions |type |possible_keys |key |key_len |ref |rows |filtered|Extra |
|---|------------|------|-----------|-----|-----------------------|----|--------|----|------|--------|---------------------------------------------------|
|1 |SIMPLE |c | |ALL | | | | |2448 |100 | |
|1 |SIMPLE |h | |ALL |history_pk_ts_tsev_IDX | | | |54227 |16.66 |Using where; Using join buffer (Block Nested Loop) |
我试图强制索引:
SELECT * FROM `changes` AS `c`
JOIN `history` AS `h` FORCE INDEX (history_pk_ts_tsev_IDX)
ON (`h`.`pk` = 2476
AND `c`.`ts` >= `h`.`start_ts`
AND `c`.`ts` < IFNULL(`h`.`end_ts`, `c`.`ts` + 1)
)
但是现在这个查询对于第一行大约需要 10 秒。再次,解释:
|id |select_type |table |partitions |type |possible_keys |key |key_len |ref |rows |filtered|Extra |
|---|------------|------|-----------|-----|-----------------------|-----------------------|--------|------|------|--------|----------------------|
|1 |SIMPLE |c | |ALL | | | | |2448 |100 | |
|1 |SIMPLE |h | |ref |history_pk_ts_tsev_IDX |history_pk_ts_tsev_IDX |5 |const |27113 |33.33 |Using index condition |
我试图以任何顺序和它们的组合创建索引,但没有运气:
- (pk, start_ts, end_ts)
- (start_ts, end_ts)
- (end_ts)
- (end_ts, start_ts)
- ...
我已经在 AWS 中可用的最大 MySQL RDS 中进行了测试,结果相同,因此不是硬件问题。
我真的迷路了。我错过了什么?
谢谢。