4

我有一个 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, channel, date) 上有一个非唯一索引来加快查询速度,例如:

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) 上创建了一个唯一索引,因为这是确定是否存在双精度值的四个主要特征。插入现在工作正常,但是我的选择查询速度慢得令人无法接受。

我不太清楚为什么自从添加新索引后我的选择变得更慢了:

  • 时间是否如此独特以至于索引变得非常大->并且很慢?
  • 我应该删除非唯一索引以加快速度吗?
  • 是我不好查询吗?
  • 欢迎其他想法!

因为记录(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      |         |               |
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4

2 回答 2

3

USE INDEX(update_index)尝试在查询中明确指定。

优化器在选择索引时选择错误,因此查询变慢。

希望这能解决你的问题.. :)

于 2013-04-26T07:46:04.527 回答
0
  • 既然aPRIMARY KEY是a UNIQUE KEY,就去掉没用的UNIQUE(id)
  • 我们谈论的任何专栏都有NULL吗?如果没有,请制作它们NOT NULL。(这在升级UNIQUE索引之前很重要。)
  • 除非您需要它进行其他查询,否则DROP comp_index. 与 4-column 相比,它没有提供额外的好处(对你的INSERTor ) 。SELECTunique_index
  • id在其他地方使用吗?如果不是,则将 4-col 唯一索引提升为PRIMARY KEY. 此步骤可能会加快速度,因为现在它不会在索引和数据之间来回弹跳(获取data)。
  • 剩下 4 个其他索引;看看你是否真的需要它们。(我建议这样做是因为上一步会使二级索引变得更庞大。)
  • 如果您使用的是 MyISAM,请更改为 InnoDB。

当做很多时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将and拆分time为两列而不是单独的列通常是一个坏主意datetime。但我不会推动它,因为它可能不会对这个问题产生太大影响。

于 2017-05-11T05:12:22.540 回答