我有一个表来存储csv文件中的数据。它是一个大表(超过4000万行)。这是它的结构:
CREATE TABLE `imported_lines` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`day` date NOT NULL,
`name` varchar(256) NOT NULL,
`origin_id` int(11) NOT NULL,
`time` time(3) NOT NULL,
`main_index` tinyint(4) NOT NULL DEFAULT 0,
`transaction_index` tinyint(4) NOT NULL DEFAULT 0,
`data` varchar(4096) NOT NULL,
`error` bit(1) NOT NULL,
`expressions_applied` bit(1) NOT NULL,
`count_records` smallint(6) NOT NULL DEFAULT 0,
`client_id` tinyint(4) NOT NULL DEFAULT 0,
`receive_date` datetime(3) NOT NULL,
PRIMARY KEY (`id`,`client_id`),
UNIQUE KEY `uq` (`client_id`,`name`,`origin_id`,`receive_date`),
KEY `dh` (`day`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50100 PARTITION BY HASH (`client_id`) PARTITIONS 15 */
当我使用一天过滤条件执行SELECT时,它非常快(0.4 s)返回数据。但是,随着日期范围的增加,它会变慢,直到出现超时错误。
这是查询:
SELECT origin_id, error, main_index, transaction_index,
expressions_applied, name, day,
COUNT(id) AS total, SUM(count_records) AS sum_records
FROM imported_lines FORCE INDEX (dh)
WHERE client_id = 1
AND day >= '2017-07-02' AND day <= '2017-07-03'
AND name IN ('name1', 'name2', 'name3', ...)
GROUP BY origin_id, error, main_index, transaction_index, expressions_applied, name, day;
我认为IN子句可能会失去性能。我还尝试向该查询添加uq
索引,这带来了一点收获(FORCE INDEX (dh, uq)
)。
另外,我尝试进行INNER JOIN (SELECT name FROM providers WHERE id = 2) prov ON prov.name = il.name
,但也无法加快查询速度。
编辑 解释查询
id - 1
select_type - SIMPLE
table - imported_lines
type - range
possible_keys - uq, dh
key - dh
key_len - 261
ref - NULL
rows - 297988
extra - Using where; Using temporary; Using filesort
有什么建议应该做什么?
答案 0 :(得分:0)
我做了一些更改,添加了一个具有多列的新索引(如@Uueerdo所建议),并根据另一个用户的建议重写了查询(但他删除了答案)。
我运行了一些EXPLAIN PARTITIONS
的查询,并通过SQL_NO_CACHE
进行了测试,以确保它不会使用缓存,并且在一个月的时间内搜索数据现在需要1.8秒
它快得多了! 这就是我所做的:
ALTER TABLE `imported_lines` DROP INDEX dh;
ALTER TABLE `imported_lines` ADD INDEX dhc (`day`, `name`, `client_id`);
查询:
SELECT origin_id, error, main_index, transaction_index,
expressions_applied, name, day,
COUNT(id) AS total, SUM(count_records) AS sum_records
FROM imported_lines il
INNER JOIN (
SELECT id FROM imported_lines
WHERE client_id = 1
AND day >= '2017-07-01' AND day <= '2017-07-31'
AND name IN ('name1', 'name2', 'name3', ...)
) AS il_filter
ON il_filter.id = il.id
WHERE il.client_id = 1
GROUP BY origin_id, error, main_index, transaction_index, expressions_applied, name, day;
我意识到使用INNER JOIN
,EXPLAIN PARTITIONS
开始使用索引。同样使用WHERE il.client_id = 1
,查询会减少要查找的分区数。
感谢您的帮助!