我有一个MySQL表,里面有大约2000万行数据。
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| b_id | int(11) | YES | MUL | NULL | |
| order | bigint(20) | YES | MUL | NULL | |
| date | date | YES | | NULL | |
| time | time | YES | | NULL | |
| channel | varchar(8) | YES | MUL | NULL | |
| data | varchar(60) | YES | | NULL | |
| date_system | date | YES | MUL | NULL | |
| time_system | time | YES | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
我在(b_id,频道,日期)上有一个非唯一索引来加速查询,如:
select date, left(time,2) as hour, round(data,1) as data
from data_lines
where channel='1'
and b_id='300'
and date >='2013-04-19'
and date <='2013-04-26'
group by date,hour
问题是我的插入有时会重叠,所以我想使用'ON DUPLICATE KEY UPDATE',但是这需要一个唯一的索引。所以我在(b_id,channel,date,time)上创建了一个唯一索引,因为这是确定是否存在double值的四个主要特征。插入现在工作正常,但我的选择查询是不可接受的慢。
我不太清楚为什么我的选择因为添加了新索引而变慢了:
对于记录(order,date_system和time_system),索引或选择中根本不使用,但确实包含数据。插件从C和Python运行,并从PHP中选择。
按要求提供解释查询:
mysql> explain select date, left(time,2) as hour, round(data,1) as data
from data_lines
where channel='1'
and b_id='300'
and date >='2013-04-19'
and date <='2013-04-26'
group by date,hour;
+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+
| 1 | SIMPLE | data_lines| ref | update_index,b_id,comp_index | comp_index | 16 | const,const | 3548 | Using where; Using temporary; Using filesort |
+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+
update_index是我的唯一索引(b_id,channel,date,time),comp_index是我的非唯一索引(b_id,channel,date)。
索引是:
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| data_lines| 0 | PRIMARY | 1 | id | A | 17918898 | NULL | NULL | | BTREE | | |
| data_lines| 0 | id_UNIQUE | 1 | id | A | 17918898 | NULL | NULL | | BTREE | | |
| data_lines| 0 | update_index | 1 | channel | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 0 | update_index | 2 | b_id | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 0 | update_index | 3 | date | A | 44244 | NULL | NULL | YES | BTREE | | |
| data_lines| 0 | update_index | 4 | time | A | 17918898 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | box_id | 1 | b_id | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | idx | 1 | order | A | 17918898 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | comp_index | 1 | b_id | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | comp_index | 2 | channel | A | 6624 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | comp_index | 3 | date | A | 165915 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | date_system | 1 | date_system | A | 17 | NULL | NULL | YES | BTREE | | |
| data_lines| 1 | mac | 1 | mac | A | 17 | NULL | NULL | YES | BTREE | | |
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
答案 0 :(得分:2)
尝试在查询中明确指定USE INDEX(update_index)
。
优化器在选择索引时做出了错误的选择,因为查询变慢了。
希望这能解决你的问题.. :)
答案 1 :(得分:0)
PRIMARY KEY
是UNIQUE KEY
,因此请摆脱无用的UNIQUE(id)
。NULL
吗?如果没有,请将它们NOT NULL
。 (这在升级UNIQUE
索引之前很重要。)DROP
comp_index
。它不会对4列INSERT
的{{1}}或SELECT
提供额外的好处。unique_index
吗?如果不是,请将4-col唯一索引提升为id
。这一步很可能加快速度,因为现在它不会在索引和数据之间来回反复(获得PRIMARY KEY
)。当做很多data
时,在一个语句中执行它们 - 它会快得多。
ALTERs
或者,为了更加谨慎:ALTER TABLE ...
DROP COLUMN id,
DROP PRIMARY KEY,
DROP INDEX `id_UNIQUE`,
DROP INDEX comp_index,
ADD PRIMARY KEY(channel, b_id, date, time),
ALTER COLUMN ... NOT NULL,
...
ENGINE=InnoDB;
修改后的表格,然后CREATE
填充它。然后测试。最终INSERT...SELECT
将其放置到位。
将RENAME TABLE
和date
分成两列而不是只有一个time
通常是个不错的主意。但我不会推动它,因为它可能不会影响这个问题。