mysql select查询非集群环境下分区表的优化

Posted

技术标签:

【中文标题】mysql select查询非集群环境下分区表的优化【英文标题】:mysql select query optimization of partitioned table in non-cluster environment 【发布时间】:2018-07-10 23:26:13 【问题描述】:

我在一个包含 1.23 亿条记录的分区表上进行了选择查询,这需要 10 多分钟才能获取数据。我的查询看起来像'select * from tableName where column1='1.1.1.1' order by timestamp desc'; 表已在 column1 上建立索引。

任何帮助表示赞赏。

(来自 cmets)

CREATE TABLE mytable (
    column1 varchar(256) NOT NULL, 
    column2 varchar(100) NOT NULL, 
    column3 smallint(5) unsigned NOT NULL, 
    column4 smallint(5) unsigned NOT NULL, 
    timestamp bigint(20) unsigned NOT NULL, 
    KEY mytable_idx (column2,timestamp,column3,column4), 
    KEY ip_addr_index (column1), 
    KEY ts_idx (timestamp)
    )  /*!50100 PARTITION BY RANGE ((TIMESTAMP))
           (PARTITION p1498800000 VALUES  LESS THAN (1498800000) ENGINE = InnoDB,
            PARTITION p1500000000 VALUES  LESS THAN (1500000000) ENGINE = InnoDB,
            PARTITION p1501200000 VALUES  LESS THAN (1501200000) ENGINE = InnoDB,
            PARTITION p1502400000 VALUES  LESS THAN (1502400000) ENGINE = InnoDB,
            PARTITION p1503600000 VALUES  LESS THAN (1503600000) ENGINE = InnoDB,
            PARTITION p1504800000 VALUES  LESS THAN (1504800000) ENGINE = InnoDB,
            PARTITION p1506000000 VALUES  LESS THAN (1506000000) ENGINE = InnoDB
                          ) */

【问题讨论】:

查询中实际需要哪些列? 如何对表进行分区? 奇怪的分区大小——看起来不到 2 周?? 【参考方案1】:

对于这个查询:

select *
from tableName
where column1 = '1.1.1.1'
order by timestamp desc;

您想要在(column1, timestamp desc) 上建立索引。注意:在早期版本的 mysql 中,desc 可能会被忽略。

【讨论】:

实际上这个表有 3 个索引,一个在时间戳上,第二个在 column1 上,第三个在时间戳上,column2,column3 & 我正在使用 mysql 5.7 @srinivas 。 . .这些都不等同于这个答案中提到的索引。【参考方案2】:

PARTITIONing 本身并不提供速度。请提供SHOW CREATE TABLE,以便我们讨论在您的情况下,分区是否真的损害性能。

INDEX(column1, timestamp)  -- In this order

无论表是否分区都是最优的。特别是,该索引对于非分区也同样适用。 (Gordon 对DESC 的评论对性能没有影响,无论是旧版本还是新版本。)

拥有 1.23 亿行,您应该关注数据类型。如果你有

column1 VARCHAR(15) CHARACTER SET utf8

那么 ipv4_address 可以从最多 17 个字节提高到正好 4 个字节:

BINARY(4)

INSERTSELECT 上进行适当的转换。进行该更改还将允许进行 CDR 和其他范围测试,而 VARCHAR 则无法实现这些测试。您需要处理 IPv6 吗?我讨论了here

有多少行匹配1.1.1.1?有TEXT 列吗? PRIMARY KEY 是什么?哪个引擎?这些问题中的每一个都可能对“10 分钟”产生影响。

了解“复合”索引何时优于单列索引非常重要。更多讨论:http://mysql.rjweb.org/doc.php/index_cookbook_mysql

创建后

替换这个

KEY ip_addr_index (column1)

KEY ip_addr_index (column1, timestamp)

在需要之前不要创建多个未来的分区。始终有一个LESS THAN (MAXVALUE) 分区以防万一。

IPv4 可以使用VARCHAR(15);打包后 IPv6 适合 (39) 或 `BINARY(16)。

对于一个查询,必须完成 7 个查询(每个分区一个);结果放在一起,然后排序。没有分区,它变成一个查询,没有排序(因为索引已经排序)。所以,(我相信)分区会减慢查询速度

在讨论 1.23 亿行的性能时,我需要一口气查看所有主要查询以便提供建议。优化一个查询很可能会取消优化另一个查询。

似乎没有理由将BIGINT 用于TIMESTAMPINT UNSIGNED 将为每行数据节省 4 个字节,并为索引节省更多。也许总共节省了 2GB 的磁盘空间。这转化为 some 查询的一些加速。

如果timestamp 总是在“范围”中使用,那么这个索引(column2,timestamp,column3,column4)很可能在一个低效的顺序中。请提供受益于该索引的查询,以便我进一步详细说明。

【讨论】:

从 show create table CREATE TABLE mytable ( column1 varchar(256) NOT NULL, column2 varchar(100) NOT NULL, column3smallint(5) unsigned NOT NULL 中输出, column4 smallint(5) unsigned NOT NULL, timestamp bigint(20) unsigned NOT NULL, KEY mytable_idx (column2,timestamp,column3,column4), KEY ip_addr_index ( column1), 关键ts_idx (timestamp)) /*!50100 PARTITION BY RANGE ((TIMESTAMP)) (PARTITION p1498800000 VALUES LESS THAN (1498800000) ENGINE = InnoDB, PARTITION p1500000000 VALUES LESS THAN (1500000000) LENGINE = InnoDB, PARTITION 5020000000 (1501200000)发动机= InnoDB,分区P1502400000值小于(1502400000)引擎= InnoDB,分区P1503600000值小于(1503600000)发动机= InnoDB,分区P1504800000值小于(1504800000)引擎= InnoDB,分区P15060000的值小于(1506000000 ) 引擎 = InnoDB) */ | 谢谢。我添加了更多建议。 PS,here 更多关于分区。

以上是关于mysql select查询非集群环境下分区表的优化的主要内容,如果未能解决你的问题,请参考以下文章

Eureka非分区集群部署

MySQL查询计划输出列的含义

数据库select查询语句进阶

mysql中,如何向测试人员介绍连接查询和子查询的优劣势?

MySql采用range分区可提升查询效率

CentOS 7下升级MySQL5.7.23的一个坑