table 增长后优化 MySQL 操作的最佳方法
Best way to optimize MySQL operations after a table grows
背景信息:我们 运行 是一个电子商务网站,正试图找出处理 table 所使用的 "historical" 数据的最佳方式非常频繁且绑定太多记录(即订单、客户等)。
我特别关注 2 个特定场景:
- 数据库迁移
- SELECT
数据库迁移
在数据库迁移的情况下,我们开始看到我们有时需要 运行 一些 ALTER TABLE 锁定整个 table 并且,如果 table 有这么多记录,这可能需要一段时间。当然,在迁移完成之前,table 上的所有操作都将暂停,这意味着我们的结帐可能会因为我们将 VARCHAR(15)
更改为 VARCHAR(256)
.[=20 而停止=]
从 MySQL 5.6 开始,完成了很多操作“INPLACE" which means (from what I understood) 他们不会创建一个完整的-table 锁:这还不错,但仍然不完美 - - 如果我们需要更改列的类型(不能执行 INPLACE)并且我们真的不想在几分钟内处于维护模式怎么办?
我的绝妙想法是简单地复制 table(复制过来),然后在复制的 table 上执行迁移,停止写入原始 table(即锁定它),将未同步的数据复制到复制的数据并交换它们。我认为 percona tool for zero-downtime migrations 做了类似的事情所以也许这就是 "best" 方法?
意见?
SELECT
对于SELECTs
,由于大部分旧数据很少被访问,我想range-partitioning按日期(例如2015年之前/ post-2015年)然后将我们的大部分查询更改为获取内容 WHERE YEAR(created_at) >= 2015
.
如果用户想要他的完整历史数据,那么我们会动态删除该条件。这以某种方式确保数据是 well-partitioned.
还有其他想法吗?您认为分区可能值得吗?
- 直到 5.7.1 才能快速做到这一点:
VARCHAR size may be increased using an in-place ALTER TABLE, as in
this example:
ALTER TABLE t1 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(255);
参见 pt-online-schema-change
。
如果您已经设置了复制,那么您可以玩ALTERing
从属游戏,然后进行故障转移。 (是的,Percona 工具在这方面很方便。)
不要在函数中 'hide' 列;优化器看不到它们:
年份(created_at) >= 2015。
-->
其中 created_at >= '2015-01-01'
仅划分为 2 个分区不太可能提供任何性能优势。
它 对某些日期(例如,TO_DAYS()
)的 PARTITION BY RANGE
是合理的(并且通常这样做)最终清除(通过 DROP PARTITION
)旧数据。 DROP
比大的 DELETE
快得多,侵入性也小得多,仅凭该功能就可以证明分区是合理的。您提到的修剪很少会加快查询速度(除非索引很差)。 More discussion of sliding time series
背景信息:我们 运行 是一个电子商务网站,正试图找出处理 table 所使用的 "historical" 数据的最佳方式非常频繁且绑定太多记录(即订单、客户等)。
我特别关注 2 个特定场景:
- 数据库迁移
- SELECT
数据库迁移
在数据库迁移的情况下,我们开始看到我们有时需要 运行 一些 ALTER TABLE 锁定整个 table 并且,如果 table 有这么多记录,这可能需要一段时间。当然,在迁移完成之前,table 上的所有操作都将暂停,这意味着我们的结帐可能会因为我们将 VARCHAR(15)
更改为 VARCHAR(256)
.[=20 而停止=]
从 MySQL 5.6 开始,完成了很多操作“INPLACE" which means (from what I understood) 他们不会创建一个完整的-table 锁:这还不错,但仍然不完美 - - 如果我们需要更改列的类型(不能执行 INPLACE)并且我们真的不想在几分钟内处于维护模式怎么办?
我的绝妙想法是简单地复制 table(复制过来),然后在复制的 table 上执行迁移,停止写入原始 table(即锁定它),将未同步的数据复制到复制的数据并交换它们。我认为 percona tool for zero-downtime migrations 做了类似的事情所以也许这就是 "best" 方法?
意见?
SELECT
对于SELECTs
,由于大部分旧数据很少被访问,我想range-partitioning按日期(例如2015年之前/ post-2015年)然后将我们的大部分查询更改为获取内容 WHERE YEAR(created_at) >= 2015
.
如果用户想要他的完整历史数据,那么我们会动态删除该条件。这以某种方式确保数据是 well-partitioned.
还有其他想法吗?您认为分区可能值得吗?
- 直到 5.7.1 才能快速做到这一点:
VARCHAR size may be increased using an in-place ALTER TABLE, as in this example:
ALTER TABLE t1 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(255);
参见
pt-online-schema-change
。如果您已经设置了复制,那么您可以玩
ALTERing
从属游戏,然后进行故障转移。 (是的,Percona 工具在这方面很方便。)不要在函数中 'hide' 列;优化器看不到它们:
年份(created_at) >= 2015。 --> 其中 created_at >= '2015-01-01'
仅划分为 2 个分区不太可能提供任何性能优势。
它 对某些日期(例如,
TO_DAYS()
)的PARTITION BY RANGE
是合理的(并且通常这样做)最终清除(通过DROP PARTITION
)旧数据。DROP
比大的DELETE
快得多,侵入性也小得多,仅凭该功能就可以证明分区是合理的。您提到的修剪很少会加快查询速度(除非索引很差)。 More discussion of sliding time series