我的桌子有超过1.5亿条记录。目前的类型是:
id (Primary Key, Bigint)
idResult (Foreign key, Bigint null)
idItem (Foreign Key, Bigint null)
Number_1 (Bigint null)
Number_2 (Bigint null)
IsActive (Bigint null)
Number_1和Number_2永远不会大于10. IsActive显然是一个布尔值。并且这些列中的任何一列都不能在代码库中的任何其他位置为空。我还想将外键字段更改为int,但这是另一个故事。这张桌子是在我开始之前几年建造的,我们正在经历一些成长的痛苦。
我正在寻找转换这些列的最佳方法(以及其他几个表上的其他表,尽管这是一个主要攻击者),并回收该磁盘空间。我已经尝试了Alter Table
,但是,有些预料到,这是行不通的。我不记得具体的错误,但我认为它与相关表格的大小有关。
现在我正在考虑手动删除并重新创建表,但我正在努力找出一种更好的方法,除了使用Select TOP 10000 * FROM dbo.TABLENAME WHERE id > 0
之外,只需多次递增where子句。
我查看了Switch To
,但这要求目标表的数据类型与源表匹配,这就是我要解决的问题!
有什么建议吗?我看错了吗?
答案 0 :(得分:3)
首先,谢谢你这样做。这是一个明显的胜利,许多人看不到很多价值,但这将是值得的:)。让世界变得更加健康。
关于IsActive
是一个布尔值。我的猜测是你想把它变成BIT
字段。这可能是要走的路,但有时最好与TINYINT
一起使用,因为有可能将意义扩展到2个以上的状态。在这种情况下,它真的变得更StatusID
。通常,这是一种简单的开始,如活跃 / 非活动,但稍后可能已删除和/或其他。从大小调整的角度来看,TINYINT
总是1个字节。另一方面,BIT
为1个字节,最多可包含8个BIT
字段。意思是,一个BIT
字段是1个字节,2个BIT
字段也是一个字节,依此类推,最多8个BIT
字段存储在一个字节中。因此,当表格只有1个BIT
字段时,选择TINYINT
而不是BIT
,就不会节省空间。需要考虑的事情。
正如您所看到的,对一个大表做一个ALTER TABLE有点多了。一个选项,虽然不是很好,但是添加NOT NULL
字段 - Number_1new
- 具有DEFAULT
值(由于默认值,这将是即时的,至少从SQL 2012)其中没有人会自然拥有(例如255),然后在循环中慢慢迁移值,如:
UPDATE TOP (5000) tab
SET tab.Number_1new = tab.Number_1
FROM [table] tab
WHERE tab.Number_1new = 255;
完成后,请执行:
sp_rename 'table.Number_1', 'Number_1old', 'COLUMN';
sp_rename 'table.Number_1new', 'Number_1', 'COLUMN';
当然,最好将它包装在TRANSACTION中,并包含在TRY / CATCH中。当相关代码更新并且所有内容都经过测试且数据看起来不错时,您可以删除Number_1old
列。
但是,我找到的最好方法是创建一个新表,慢慢转换数据,然后同时交换表和代码。我详细介绍了有关SQL Server Central的文章中的步骤:Restructure 100 Million Row (or more) Tables in Seconds. SRSLY!(需要免费注册)。为了防止该文章出现问题,以下是基本步骤:
AFTER UPDATE, DELETE
以保持同步更改(但无需担心新行)INSERT INTO [tableNew] (Columns) SELECT TOP (n) Columns FROM [table] WHERE ?? ORDER BY ??
WHERE table.[id] > @MaxIdInTableNew ORDER BY table.[id]
INT
的两个FK的PK参考),那么现在在INT
处填写这些字段,并且只需要#&# 39; t添加FK,直到将其他表迁移到将INT字段作为其PK。您不希望再次重建此表只是为了对FK字段进行更改。答案 1 :(得分:1)
不要放弃
创建一个包含正确列类型的表,然后插入循环
或者您可以一次完成一列。
Update table
set Number_1tiny = Number_1
where Number_1 is not null
and Number_1tiny <> Number_1