背景信息:我们运行一个电子商务网站,并试图找出处理非常频繁使用且必然包含大量记录的表的“历史”数据的最佳方法(即.订单、客户等)。
我特别关注两个具体场景:
- 数据库迁移
- 选择
数据库迁移
在数据库迁移的情况下,我们开始发现有时需要运行一些锁定整个表的 ALTER TABLE,如果表有这么多记录,这可能需要一段时间。当然,表上的所有操作都会暂停,直到迁移完成,这意味着我们的结账可能会因为我们将 VARCHAR(15)
更改为 VARCHAR(256) 而失败
.
从 MySQL 5.6 开始,很多操作都是“INPLACE ”完成的,这意味着(从 what I understood )它们不会创建全表锁:这还可以,但仍然不完美 - 如果我们需要更改列的类型(无法就地执行)并且我们真的不想处于维护模式几分钟?
我的 super 贫民窟想法是简单地复制表(将其复制过来),然后在复制的表上执行迁移,停止写入原始表(即锁定它),将未同步的数据复制到复制一份并交换它们。我认为percona tool for zero-downtime migrations做了类似的事情,所以也许这是“最好的”方法?
意见?
选择
对于SELECT
,由于大多数旧数据很少被访问,所以我想到了range-partitioning按日期(例如 2015 年之前/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
。如果您已经设置了复制,那么您可以玩
更改
从站,然后进行故障转移的游戏。 (是的,Percona 工具在这方面很方便。)不要在函数内“隐藏”列;优化器看不到它们:
年份(创建时间)>= 2015 年。 --> WHERE 创建时间 >= '2015-01-01'
仅划分为 2 个分区不太可能提供任何性能优势。
对某个日期(例如,
TO_DAYS()
)进行PARTITION BY RANGE
是合理的(并且通常这样做)最终清除(通过DROP PARTITION)旧数据的目的。DROP
比大型DELETE
更快且侵入性更小,仅此功能就证明了分区的合理性。您提到的修剪很少会加快查询速度(除非索引很差)。 More discussion of sliding time series
关于mysql - 表增长后优化 MySQL 操作的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31100552/