0

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

我试图以相同的顺序在包括 Field1、Field2、Field3 DESC 的表上创建 BTREE 索引,但它没有给我正确的结果。

任何人都可以帮助我如何优化它。我的问题是我无法更改查询,因为我没有此报告服务器从中执行查询的代码。

任何帮助将非常感激。

谢谢


这是我的桌子:

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;
4

3 回答 3

0

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

问题是日期检查的中间性质会强制进行表扫描,因为您不知道日期在哪里。

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

如果您走分区的道路,您将需要与 MySQL DBA 交谈,最好是熟悉分区的人。这不适合胆小的人。

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

于 2012-04-27T15:54:35.763 回答
0

Add the int_field into the index:

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)

to make it cover all fields.

This way, table lookups go (you will see Using index in the plan) which will make your query some 10x faster (your mileage may vary).

Also note that (at least for the single-date range provided) GROUP BY DATE(updated_at) and ORDER BY date DESC are redundant and will only make the query to use temporary and filesort without any real purpose. Not that you can do much about it, though, if you cannot change the query.

于 2012-04-27T16:12:29.407 回答
0

根据您的查询,您必须在这里带头 - 最小粒度。我们不知道活动的频率是多少,Field1,Field2 状态条目是什么,您的数据可以追溯到多远,在给定的 SINGLE DATE 有多少条目是正常的。综上所述,我将首先基于与您的查询条件非常匹配的最小粒度来构建索引。

例如:如果您的“Field1”有十几个可能的“CHAR”值,并且您正在应用“IN”子句,并且 Field1 是索引中的第一个,它将针对每个日期和 field2 值命中每个字符。2.5 亿条记录可能会强制执行大量索引分页活动,尤其是基于历史记录。您的 Field2 也是如此。但是,由于您在 Field2 上的“分组依据”子句和更新日期,我将在索引的第一个/第二个位置分别拥有一个。根据历史数据,我什至倾向于以日期为主要依据,在此范围内以次要标准为依据。

索引(Updated_At、Field2、Field1、INT_FIELD)

这样,您的整个查询可以仅在索引上完成,而无需针对实际记录的原始数据进行查询。索引中的所有字段都可以从中提取。您有一个有限的日期范围,因此您的 updated_at 立即合格,并按顺序准备分组。从那时起,您来自 Field2 的“CHAR”值将很好地完成您的分组。Field1 来限定您的“IN”字符列表的第三个标准,最后是您的 INT_FIELD 计数(不同)。

不知道在 2.5 亿的基础上建立索引需要多长时间,但这就是我要开始的地方。

于 2012-04-27T23:57:22.730 回答