MySql - 添加列以选择会降低性能

问题描述 投票:0回答:5

我有一个有几百万行数据的表。我在 id 上有一个主键,在 col2、col3、col4 和 my_date(称为 comp_indx)上有一个复合唯一键。示例数据显示在这里...

id   col2 col3 col4 my_date             col5 col6 col7
1    1    1    1    2020-01-03 02:00:00 a    1    a
2    1    2    1    2020-01-03 01:00:00 b    2    1
3    1    3    1    2020-01-03 03:00:00 c    3    b
4    2    1    1    2020-02-03 01:00:00 d    4    2
5    2    2    1    2020-02-03 02:00:00 e    5    c
6    2    3    1    2020-02-03 03:00:00 f    6    3
7    3    1    1    2020-03-03 03:00:00 g    7    d
8    3    2    1    2020-03-03 02:00:00 h    8    4
9    3    3    1    2020-03-03 01:00:00 i    9    e

如果我执行以下查询...

SELECT col2, col3, max(my_date)
FROM table
where col4=1 and my_date <= '2001-01-27'
group by col2, col3

...查询非常高效,运行解释命令显示...

select_type type  key       key_len rows Extra
----------- ----- --------- ------- ---- -------------------------------------
SIMPLE      range comp_indx 11      669  Using where; Using index for group-by

但是,如果我运行类似的命令(只请求更多的列——没有一个是索引的一部分),例如……

SELECT col2, col3, max(my_date), col5, col7
FROM table
where col4=1 and my_date <= '2001-01-27'
group by col2, col3

...然后性能立即下降,如果我再次运行 explain 命令,我会...

select_type type  key       key_len rows     Extra
----------- ----- --------- ------- -------  -----------
SIMPLE      index comp_indx 11      5004953  Using where

我可以看到类型已经从范围变为索引,并且我可以看到索引不再用于分组依据。

我试图理解为什么会这样,更重要的是,我该如何解决这个问题?

顺便说一句,表定义是...

CREATE TABLE `my_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `col2` smallint(6) NOT NULL,
  `col3` smallint(6) NOT NULL,
  `col4` smallint(6) NOT NULL,
  `my_date` datetime NOT NULL,
  `col5` char(1) NOT NULL,
  `col6` char(1) NOT NULL,
  `col7` char(1) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `comp_indx` (`col2`,`col3`,`col4`,`my_date`)
) ENGINE=InnoDB;
mysql performance select indexing using
5个回答
1
投票

添加以下索引

alter table my_table add key cl4_dt_cl2_cl3 (col4,my_date,col2,col3);

此外,如果启用了sql_mode only_full_group_by,则以下查询无效

SELECT col2, col3, max(my_date), col5, col7
FROM table
where col4=1 and my_date <= '2001-01-27'
group by col2, col3

0
投票

我现在已经通过在同一张表上使用 2 个选择和一个连接来解决我的性能问题,例如...

SELECT *
FROM (
    SELECT col2, col3, max(my_date) as max_date
    FROM table
    where col4=1 and my_date <= '2001-01-27'
    group by col2, col3
) aaa
join
(
    SELECT col2, col3, my_date, col5, col6, col7
    FROM table
    where col4=1
) bbb
on (aaa.col2=bbb.col2 and aaa.col3=bbb.col3 and aaa.max_date=bbb.my_date);

0
投票

您可能需要添加此覆盖索引以使第二个查询更快:

create index comp2_index on my_table(col2, col3, col4, my_date, col5, col7);

0
投票

您的原始查询:

SELECT col2, col3, max(my_date), col5, col7
FROM table
where col4=1 and my_date <= '2001-01-27'
group by col2, col3

col5, col7 也应该添加到 group by 子句中,对吧?


0
投票

如果您不需要

id
任何东西,那么这将加快查询速度,无论您需要获取额外的列(col5/6/7)。

CREATE TABLE `my_table` (
  `col2` smallint(6) NOT NULL,
  `col3` smallint(6) NOT NULL,
  `col4` smallint(6) NOT NULL,
  `my_date` datetime NOT NULL,
  `col5` char(1) NOT NULL,
  `col6` char(1) NOT NULL,
  `col7` char(1) NOT NULL,
  PRIMARY KEY (col4,my_date,col2,col3)  -- in this order
) ENGINE=InnoDB;

如果你确实需要

id
因为它被其他表引用,那么添加

  `id` int(11) NOT NULL AUTO_INCREMENT,
  INDEX(id)  -- This is sufficient to keep auto_inc happy

我建议的 PK 是 11 字节(对比 4 字节 INT)。任何次级都将包含这 11 个字节。但是,不会重复 PK 和二级索引之间的任何公共列。例如

INDEX(col2, col7)
将有效
INDEX(col2, col7, col4, my_date, col3)
.

请记住,PK 确定行的“参考位置”。任何以

col4
开头的二级索引几乎都是无用的,因为 PK 以此开头。 (当然,这取决于基数等)

© www.soinside.com 2019 - 2024. All rights reserved.