繁体   English   中英

MySQL 对分区表的请求缓慢

[英]MySQL slow request on partitionned table

我面临着一个完全的谜团。

我已经创建了一个表来存储 meterolocal 数据。 自 1979 年以来,我每小时有一个值,每 0.25 个纬度和经度。 这使我在数据库中拥有数十亿行。 根据多项建议,我对表进行了分区。 我选择按年划分。 这是它的样子:

 CREATE TABLE `MyTable` (
  `latitude_100` SMALLINT NOT NULL, -- Smallint is 2 bytes, where float is 4. So we take latitude * 100
  `longitude_100` SMALLINT NOT NULL, -- Same logic here
  `time` DATETIME NOT NULL,
  `final` TINYINT UNSIGNED NOT NULL,
  `value` DOUBLE NOT NULL,
  PRIMARY KEY (`latitude_100` ASC, `longitude_100` ASC, `time` ASC)
)
PARTITION BY HASH(YEAR(time)) PARTITIONS 45 ; -- This will work until 2023 included

为了测试,我只注入了2015年到2021年的表数据。

问题:该表中的所有 SELECT 都非常长。

更糟糕的是,它们有时长得愚蠢。 例如:

SELECT time, latitude_100, longitude_100, value 
FROM MyTable 
WHERE  latitude_100 BETWEEN 500 AND 2000 
AND longitude_100 BETWEEN 11600 AND 12800 AND 
YEAR(time) = 1990 ;

请记住,没有 1990 年的数据。通过查看正确的分区,MySQL 应该立即看到它,不是吗?

MySQL 解释说它会查看所有分区,我不明白为什么:

EXPLAIN SELECT time, latitude_100, longitude_100, value 
FROM MyTable 
WHERE  latitude_100 BETWEEN 500 AND 2000 
AND longitude_100 BETWEEN 11600 AND 12800 AND 
YEAR(time) = 1990 ;
# id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, SIMPLE, MyTable, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,p31,p32,p33,p34,p35,p36,p37,p38,p39,p40,p41,p42,p43,p44, range, PRIMARY, PRIMARY, 4, , 118295536, 11.11, Using where

当我做

SELECT * FROM information_schema.partitions WHERE TABLE_SCHEMA='MySchema' AND TABLE_NAME = 'MyTable' AND PARTITION_NAME IS NOT NULL

我可以看到只有6个分区有数据,其他都是空的。

最后我想尝试以不同的方式制定 WHERE,以便利用索引:

SELECT time, latitude_100, longitude_100, value 
FROM MyTable
WHERE  latitude_100 BETWEEN 500 AND 2000 
AND longitude_100 BETWEEN 11600 AND 12800 AND
time BETWEEN "1990-01-01 00:00:00" AND "1990-12-31 23:00:00" AND 
YEAR(time) = 1990 ;

但这并不能加速执行。 只有 EXPLAIN 有点不同(但不是在分区读取方面):

# id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, SIMPLE, MyTable, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,p31,p32,p33,p34,p35,p36,p37,p38,p39,p40,p41,p42,p43,p44, range, PRIMARY, PRIMARY, 9, , 118295536, 1.23, Using where

我做错了什么? 为什么MySQL不想配合分区呢?

非常感谢你 !

[编辑] 在技术方面,数据库托管在 AWS RDS 上。 它由“db.t4g.large”实例和用户 MySQL 8.0.27 提供支持

不要使用PARTITION BY HASH 简单地说,HASH 在使用日期范围(如您所用)时将无法进行任何修剪。 优化器不够聪明,无法看到您的范围适合单个分区,此外, HASH可能不必要地将两个不同的年份归为同一个分区。 相反,使用PARTITION BY RANGE

我知道RANGE(TO_DAYS(time))有效; 也许RANGE(YEAR(time))可能有效,具体取决于您使用的 MySQL 的版本; 检查细节。

小时:通过一些日期算法,您可以将 5 字节的DATETIME缩减为 3 字节的MEDIUMINT (需要对PARTITION BY RANGE进行适当的更改。)

不够:由于您仅使用 7 年的数据进行测试,因此我的分区建议只能提供 7 倍的帮助。

双倍的? 你在测量什么? DOUBLE占用 8 个字节,并为您提供大约 16 个有效数字。 即使是FLOAT (4 字节,7 位数字)也可能有点矫枉过正。 对于温度 (°C),请考虑DECIMAL(2)TINYINT (-128..+127) 或DECIMAL(4,2) 它们分别是 1,1,2 字节。 极端记录:-89..+57。 注意:°F 在任何INTDECIMAL编码中都需要多一个字节。 (我猜如果温度超过 99°C,那么太靠近火山或野火的仪器将无法传输数据。)

缩小DOUBLE会将数据集大小缩小大约 1/3——值得付出努力。

如果您最终得到大约 400GB 的行,数据类型的大小就非常重要。

所以,让我们深入挖掘......请提供

  • 内存量
  • SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
  • 您可能会运行的任何其他SELECTs ,包括恰好一年以外的WHERE子句。
  • 你7年用了多少磁盘空间? 如果使用 MyISAM,我预计大约有 1.2TB; 如果使用 InnoDB,3TB。
  • 样本 Select 中的经纬度范围相对较小。 这是典型的吗? 如果是这样,我们也许可以利用它。

ENGINE——因为我认为这主要是一个只读数据集,所以 MyISAM 更好的情况可能很少见。 见上面的估计; 乘以 6 得到 43 年的估计值。

用法——你将如何处理SELECT的结果? 如果那是“唯一”的查询,那么有更紧凑的方式来存储数据。 但是它们对于 Insert 和 Select 会更复杂。但是,速度的提高可能是值得的。 在进一步建议之前,我需要查看各种选择。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM