我们有一个相当未优化的表,其定义如下:
CREATE TABLE `Usage` (
`TxnDate` varchar(30) DEFAULT NULL,
`TxnID` decimal(13,2) NOT NULL,
`UserID2015` varchar(20) DEFAULT NULL,
`UserRMN` decimal(13,0) DEFAULT NULL,
`CustomerNo` decimal(13,0) DEFAULT NULL,
`OperatorName` varchar(50) DEFAULT NULL,
`AggregatorName` varchar(30) DEFAULT NULL,
`TransAmount` decimal(10,2) DEFAULT NULL,
`MMPLTxnID` decimal(13,0) DEFAULT NULL,
`ProductType` varchar(30) DEFAULT NULL,
`YearMonthRMN` varchar(50) DEFAULT NULL,
PRIMARY KEY (`TxnID`),
UNIQUE KEY `TxnID` (`TxnID`) USING BTREE,
KEY `TxnDate` (`TxnDate`),
KEY `OperatorName` (`OperatorName`),
KEY `AggregatorName` (`AggregatorName`),
KEY `MMPLTxnID` (`MMPLTxnID`),
KEY `ProductType` (`ProductType`),
KEY `UserRMN` (`UserRMN`),
KEY `YearMonthRMN` (`YearMonthRMN`) USING BTREE,
KEY `CustomerNo` (`CustomerNo`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
该表有170万条记录。
我想删除主键,而是添加一个自动编号主键。到目前为止,指数下降了2小时。
为什么删除索引需要这么长时间,是否有任何排序?
我如何估计放弃指数的时间?
当我添加自动编号时,我是否需要估计对表格进行排序的时间,或者对于新的自动编号索引是否需要这样做?
答案 0 :(得分:3)
你不只是丢弃索引,而是丢弃主键。
通常,InnoDB表存储为基于主键的聚簇索引,因此通过删除主键,它必须创建一个新表,该表使用辅助唯一键或其自身生成的密钥用于其聚簇索引。
我已经完成了大量的MySQL咨询,以及“需要花多少时间?”的问题。是一个常见的问题。
在服务器上构建新的聚簇索引需要花费很长时间。这很难预测。这取决于几个因素,例如服务器的CPU速度,存储速度以及其他负载同时发生的频率,以及CPU和I / O带宽的竞争。
换句话说,根据我的经验,我们无法预测需要多长时间。
您的表将使用TxnID
重建为新的聚簇索引,这与主键完全相同。但显然MySQL服务器并不认为这种特殊情况可以使用可以使用in in alter alter的快捷方式。
您的表还有八个其他二级索引,其中五个是varchars。它必须在表重组期间构建这些索引。除了聚集索引之外,构建这些索引还有很多I / O.那很可能是花了那么多时间。
添加新的自动增量主键时,您将完成类似的过程。如果您删除了旧的主键并在一个ALTER TABLE语句中创建了新的自动增量主键,则可以节省一些时间。
答案 1 :(得分:2)
(我同意Bill的回答;这里有更多评论。)
我会终止这个过程并重新考虑AUTO_INCREMENT
中是否有任何的好处。
我试图超越问题而不是“真实”的问题。在这种情况下,它似乎是一个尚未说出来的东西,需要AUTO_INCREMENT
;请详细说明。
您当前的PRIMARY KEY
是6个字节。如果INT
,则新PK将为4个字节,如果为BIGINT
,则为8个字节。因此,磁盘空间利用率只会微不足道地节省或损失。
TxnID
的任何查找都会因为通过AI而放慢速度。由于TxnID
是UNIQUE
且非空,它似乎是最佳的“自然”PK。
PK 是唯一键,因此UNIQUE(TxnID)
完全是多余的; DROPping
它可以节省空间而不会丢失任何东西。这是我的主要建议(只看模式)。
当我看到基本上每列都为NULL
的表格时,我怀疑设计师没有对列的无效性做出有意识的决定。
DECIMAL(13,2)
将是很多美元或欧元,但作为PK,这是非常不寻常的。怎么了?
latin1
?没有全球化的计划?
很多单列索引? WHERE a=1 AND b=2
需要复合INDEX(a,b)
。
回到估计时间......
如果ALTER
重建了8-9个索引,那么 应该通过磁盘排序来做它能做的事情。这涉及使用基于磁盘的高效排序将内容写入磁盘,该排序涉及一些RAM,然后读取排序结果以重新创建索引。排序是O(log N),从而使其成为非线性的。这使得很难预测所花费的时间。一些较新版本的MariaDB 尝试估计剩余时间,但我不相信。
辅助索引包括作为索引的列以及PK的任何其他列。 表中的每个索引将占用大约5-10GB的磁盘空间。这个可以帮助您转换为IOP或其他任何东西。但请注意(假设您没有太多RAM),在重建索引的排序过程中,5-10GB将被重读几次(几次?)。
执行多个ALTERs
时,请在单个ALTER
语句中执行这些操作。这样,所有工作(特别是重建二级索引)只需要完成一次。
您还没有说出您使用的是哪个版本。旧版本提供一个选择:“复制”:创建新表;复制数据;重建索引;改名。新版本可以处理辅助索引“INPLACE”。注意:对PRIMARY KEY
的更改需要复制方法。
答案 2 :(得分:0)
对任何有兴趣的人:
这是在Amazon Aurora上运行的,存储了30GB的数据。我找不到有关如何为此配置IOPS的任何信息,但我预计在最坏的情况下将始终提供90IOPS。写10GB进出需要大约4个小时。
我在运行alter table之前将实例升级到db.r3.8xlarge。
然后跑
alter table `Usage` drop primary key, add id bigint auto_increment primary key