我有一个表,该表包含150万行,有39列,包含大约2年的销售数据,并且每天都在增长。 在将它移到新服务器之前,我没有任何问题,现在我们的内存可能更少了。
查询目前需要很长时间。有人建议对导致大多数性能问题的大表进行分区,但是我有几个问题。
是否进行分区 需要很长时间来表演?我担心随着性能下降, 中途会发生一些事情,我会丢失数据。
我应该将其分割成几年还是几个月? (我们通常 看一个月内的数字,但有时我们要花几周或 年份)。我还应该对列进行分区吗? (我们有一些 我们很少或从未使用过的列,但我们可能想使用它们 稍后)
答案 0 :(得分:2)
在大多数情况下,最好使用索引,而不是使用分区作为查询优化的主要方法。
关于MySQL分区的第一件事是该规则:
已分区表的分区表达式中使用的所有列必须是该表可能具有的每个唯一键的一部分。
在此处详细了解此规则:Partitioning Keys, Primary Keys, and Unique Keys。
此规则使许多表不符合分区条件,因为您可能希望按不属于该表主键或唯一键的列进行分区。
要知道的第二件事是,分区仅在使用条件的情况下帮助查询,这些条件明确地使优化器推断出哪些分区保存了您感兴趣的数据。这称为分区修剪。如果运行查询可以在任何或所有分区中找到数据,则MySQL必须搜索所有分区,并且与具有常规的非分区表相比,您不会获得任何性能优势。
例如,如果按日期进行分区,但是随后运行查询以查询与特定用户帐户相关的数据,则它必须搜索所有分区。
实际上,在这样的查询中使用分区表可能甚至慢一点,因为MySQL必须顺序搜索每个分区。
您询问对表进行分区需要多长时间。转换为分区表需要ALTER TABLE
来重组数据,因此它花费的时间与添加列所需的时间相同。两种类型的更改都需要将数据复制到新的表空间。
答案 1 :(得分:1)
(我同意比尔的回答;我将以另一种方式处理该问题。)
什么时候可以分开我的桌子?
可能永远不会。
是否有可能改善其性能?
它更有可能稍微降低性能。
我有一个包含150万行的表
不够大,无法进行分区。
查询目前花费很长时间
通常是由于缺少良好的索引(可能是“复合”索引)导致的。 第二是查询的格式。请向我们展示一个缓慢的查询以及SHOW CREATE TABLE
。
大约2年的数据,并且每天都在增长
您最终将清除“旧”数据吗?如果是这样,PARTITION BY RANGE(TO_DAYS(..))
是个好主意。但是,它仅在清除过程中有帮助。这是因为DROP PARTITION
比<{1}快了很多。
我们现在的内存可能更少了。
如果您主要查看“最近”数据,则内存大小(cf DELETE...
) 可能无关紧要。这是由于缓存。但是,听起来好像是在进行表扫描,也许是不必要的。
我是否必须对当前的INSERT或SELECT进行更改
不。但是您可能可能需要更改innodb_buffer_pool_size
和辅助键中的列。
该分区需要花费很长时间吗?
慢-是的,因为它将复制整个表。注意:这意味着额外的磁盘空间,分区表将占用更多磁盘。
中途会发生某些事情,我会丢失数据。
不用担心。新表已创建,然后非常快速的PRIMARY KEY
将其交换到位。
经验法则:瞄准大约50个分区。随着“两年并不断增长”,一个可能的选择是“每月”。我应该将其分割成几年还是几个月?
我们通常查看一个月内的数字,但有时我们需要数周或数年
闻起来像典型的“数据仓库”数据集吗?使用每日统计信息构建并逐步扩充“摘要表”。使用该表,您可以快速获取每周/每月/每年的统计信息-可能快10倍。在任何日期范围内也一样。这对于“内存不足”也有很大帮助。
我还应该对列进行分区吗? (我们有一些我们很少使用或从未使用过的列,但我们可能想在以后使用它们)
您不应“永远”使用RENAME TABLE
;而是指定您实际需要的列。 “垂直分区”是您建议的术语。这有时是可行的。但是我们需要查看SELECT *
具有现实的列名才能进一步讨论。
有关分区的更多信息:http://mysql.rjweb.org/doc.php/partitionmaint
摘要表的更多信息:http://mysql.rjweb.org/doc.php/summarytables