我有一张超过2.5亿条记录的表格。我们的报告服务器使用类似的查询定期查询该表。
SELECT
COUNT(*),
DATE(updated_at) AS date,
COUNT(DISTINCT INT_FIELD)
FROM
TABLE_WITH_250_Million
WHERE
Field1 = 'value in CHAR'
AND field2 = 'VALUE in CHAR'
AND updated_at > '2012-04-27'
AND updated_at < '2012-04-28 00:00:00'
GROUP BY
Field2,
DATE(updated_at)
ORDER BY
date DESC
我试图在表上创建一个BTREE索引,包括Field1,Field2,Field3 DESC,但它没有给我正确的结果。
任何人都可以帮助我如何优化它。我的问题是我无法更改查询,因为我没有此报告服务器执行查询的代码。
任何帮助都会非常感激。
由于
这是我的表:
CREATE TABLE backup_jobs (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
backup_profile_id int(11) DEFAULT NULL,
state varchar(32) DEFAULT NULL,
limit int(11) DEFAULT NULL,
file_count int(11) DEFAULT NULL,
byte_count bigint(20) DEFAULT NULL,
created_at datetime DEFAULT NULL,
updated_at datetime DEFAULT NULL,
status_type varchar(32) DEFAULT NULL,
status_param_1 varchar(255) DEFAULT NULL,
status_param_2 varchar(255) DEFAULT NULL,
status_param_3 varchar(255) DEFAULT NULL,
started_at datetime DEFAULT NULL,
PRIMARY KEY (id),
KEY index_backup_jobs_on_state (state),
KEY index_backup_jobs_on_backup_profile_id (backup_profile_id),
KEY index_backup_jobs_created_at (created_at),
KEY idx_backup_jobs_state_updated_at (state,updated_at) USING BTREE,
KEY idx_backup_jobs_state_status_param_1_updated_at (state,status_param_1,updated_at) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=508748682 DEFAULT CHARSET=utf8;
答案 0 :(得分:0)
我确信所有250M行都没有出现在感兴趣的日期范围内。
问题是日期检查之间的性质强制进行表扫描,因为您无法知道日期的位置。
我建议您将250M行表分为几周,几个月,几个季度或几年,并且只扫描给定日期范围内的分区。您只需要扫描范围内的分区。这将有所帮助。
如果你沿着分区路走下去,你需要和MySQL DBA交谈,最好是熟悉分区的人。这不适合胆小的人。
答案 1 :(得分:0)
将int_field
添加到索引中:
CREATE INDEX idx_backup_jobs_state_status_param_1_updated_at_backup_profile_id ON backup_jobs (state, status_param_1, updated_at, backup_profile_id)
使其涵盖所有领域。
通过这种方式,表格查找(您将在计划中看到Using index
),这将使您的查询更快10x
(您的里程可能会有所不同)。
另请注意(至少对于提供的单日期范围)GROUP BY DATE(updated_at)
和ORDER BY date DESC
是多余的,只会使查询使用temporary
和filesort
任何真正的目的。但是,如果您无法更改查询,并不是说您可以做很多事情。
答案 2 :(得分:0)
根据您的查询,您必须在此处起带头作用 - 最小的粒度。我们不知道活动的频率是什么,Field1,Field2状态条目是什么,数据返回多远,在给定的单个日期中有多少条目是正常的。总而言之,我会首先根据最接近您的查询条件的最小粒度构建索引。
例如:如果你的&#34; Field1&#34;有十几种可能&#34; CHAR&#34;值,你正在应用&#34; IN&#34;在您的索引中,Field1是第一个,它将为每个日期和field2值命中每个char。 2.5亿条记录可能会强制执行大量索引分页活动,尤其是基于历史记录。与你的Field2一样。但是,由于你的&#34; Group By&#34;更新了Field2和date的子句,我将分别在索引的第一个/第二个位置中有一个。根据历史数据,我甚至倾向于在以下指数上进行拍摄,以日期为主要依据,并在其中作为次要标准。
index(Updated_At,Field2,Field1,INT_FIELD)
这样,您的整个查询只能在索引上完成,而不需要查询实际记录的原始数据。所有字段都在索引中,以便从中拉出。您有一个有限的日期范围,因此您的updated_at是合适的,并按顺序准备组。从那,你的&#34; CHAR&#34;来自Field2的值将很好地完成您的组。 Field1符合您的第三个标准&#34; IN&#34; char列表,最后是你的INT_FIELD for count(distinct)。
不知道索引需要多长时间才能建立2.5亿,但这就是我要开始的地方。