MySQL Query永远运行

时间:2012-04-27 15:48:40

标签: mysql

我有一张超过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;

3 个答案:

答案 0 :(得分:0)

我确信所有250M行都没有出现在感兴趣的日期范围内。

问题是日期检查之间的性质强制进行表扫描,因为您无法知道日期的位置。

我建议您将250M行表分为几周,几个月,几个季度或几年,并且只扫描给定日期范围内的分区。您只需要扫描范围内的分区。这将有所帮助。

如果你沿着分区路走下去,你需要和MySQL DBA交谈,最好是熟悉分区的人。这不适合胆小的人。

http://dev.mysql.com/doc/refman/5.1/en/partitioning.html

答案 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是多余的,只会使查询使用temporaryfilesort任何真正的目的。但是,如果您无法更改查询,并不是说您可以做很多事情。

答案 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亿,但这就是我要开始的地方。