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)
在INSERT
和SELECT
上进行适当的转换。进行该更改还将允许进行 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
用于TIMESTAMP
。 INT UNSIGNED
将为每行数据节省 4 个字节,并为索引节省更多。也许总共节省了 2GB 的磁盘空间。这转化为 some 查询的一些加速。
如果timestamp
总是在“范围”中使用,那么这个索引(column2,timestamp,column3,column4)
很可能在一个低效的顺序中。请提供受益于该索引的查询,以便我进一步详细说明。
【讨论】:
从 show create table CREATE TABLEmytable
( 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
), 关键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查询非集群环境下分区表的优化的主要内容,如果未能解决你的问题,请参考以下文章