我们有一个看起来像这样的 MySQL 表(删除了无关紧要的列):
CREATE TABLE `my_data` (
`auto_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`created_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_ts` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`data_txt` varchar(256) CHARACTER SET utf8 NOT NULL,
`issued_ts` timestamp NULL DEFAULT NULL,
`account_id` int(11) NOT NULL,
PRIMARY KEY (`auto_id`),
KEY `account_issued_idx` (`account_id`,`issued_ts`),
KEY `account_issued_created_idx` (`account_id`,`issued_ts`,`created_ts`),
KEY `account_created_idx` (`account_id`,`created_ts`),
KEY `issued_idx` (`issued_ts`)
) ENGINE=InnoDB;
表中有大约 900M 行,其中一个 account_id 占这些行的 65% 以上。我被要求为 created_ts 和 issue_ts 编写跨日期范围的查询,这些查询依赖于 account_id,它似乎对自动增量键具有 1:1 的功能依赖性。
一个典型的查询如下所示:
SELECT *
FROM my_data
WHERE account_id = 1 AND
created_ts > TIMESTAMP('2012-01-01') AND
created_ts <= TIMESTAMP('2012-01-21')
ORDER BY created_ts DESC LIMIT 100;
查询的解释显示:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: my_data
type: range
possible_keys: account_issued_idx, account_issued_created_idx, account_created_idx,
key: account_issued_created_idx
key_len: 8
ref: NULL
rows: 365314721
Extra: Using where
问题是查询花费的时间太长并且最终被杀死。我已经让它运行了几次,它导致数据库主机停机,因为操作系统(Linux)用完了交换空间。
我反复研究过这个问题,并试图将查询分解为不相关的子查询、强制索引、使用显式 SELECT 子句并限制日期范围的窗口,但结果是一样的:性能差(太慢)并且对宿主过于繁重(总是死亡)。
我的问题是:
是否可以制定查询以将数据分割成日期范围并在实时调用中可接受地执行?( < 1s)
为了获得我被要求获得的性能,我是否缺少或可能有帮助的优化?
欢迎任何其他建议、提示或想法。
谢谢