修改表結構的內幕ide
並不是全部的ALTER TABLE變更在ALTER TABLE命令使用時都須要SQL Server去更改每一行。日誌
SQL Server能夠以三種基本方式去執行ALTER TABLE命令server
1. 它可能只須要更改元數據索引
2. 它可能須要檢查全部現有數據, 以確保它與更改兼容, 但只須要對元數據進行更改。事務
3. 它可能須要在物理上改變每一行。資源
在不少狀況下,SQL Server只能更改元數據(主要經過sys.columns來查看數據)來反映新結構。it
特別是,當刪除列、添加一個null值的列,可變長度列的長度提高,一個不可空的列變動爲可空時,都不會改變原有的數據。io
當刪除列時數據不會被觸及,意味着該列的磁盤空間不會被回收。當表的行大小接近或超過其限制時, 你可能須要手工回收已刪除列的磁盤空間。table
你能夠經過建立或ALTER INDEX重建表的聚族索引去回收空間,見第7章,或者經過ALTER TABLE重建表,見第8章。class
某些表結構變動須要檢查數據但修改。例如,當你把可空的列變動爲不可空時,SQL Server必須首先確認該列的數據中沒有空值。
一個可變長的列被縮短時,全部存在的數據必須被檢查,若是有任何的數據長度大於新限制,ALTER TABLE命令都會執行失敗。值得注意的是,變動一個大表是須要時間的。
改變一個固定長度的列爲更短的類型,例如int變爲smallint,或者char(10)變爲char(8),也是須要檢查全部的數據都能存儲到新的類型中。
可是,即便新數據類型佔用更少的字節,物理頁上的數據也不會被修改。
若是你建立一個表有int列,每行4字節,那麼全部行都會使用完整的4個字節。在表的int類型修改成smallint類型後,你插入數據是會受新類型的範圍限制,
可是這些數據還是4個字節,是否是smallint的2個字節,你能夠經過dbcc page命令驗證。
char(10)變爲char(8)與以前的相似,數據依然使用10字節存儲,可是插入是受8字節長度限制。直至重建表以後,char(10)纔會真正變爲char(8)。
對錶結構的其餘更改要求 SQL server 在物理上更改每一行;當它進行更改時, 它必須將適當的記錄寫入事務日誌, 所以對於大型表來講, 這些更改可能很是耗費資源。
此類型更改的一個示例是將列的數據類型更改成具備不一樣內部存儲表示形式的新類型。
修改表結構的另外一個負面影響出如今列被修改成提高長度。在這種狀況下, 舊列實際上沒有被替換;而是將新列添加到表中, DBCC 頁顯示舊數據仍然存在。
您能夠自行瀏覽此狀況的頁面轉儲, 但您能夠經過使用清單6-5 前面所示的列詳細信息查詢來查看列偏移量來看到某些意外行爲。
首先, 建立一個具備全部固定長度列的表, 包括第一個位置中的 smallint:
CREATE TABLE change
(col1 smallint, col2 char(10), col3 char(5));
如今查看列偏移量:
SELECT c.name AS column_name, column_id, max_inrow_length, pc.system_type_id, leaf_offset
FROM sys.system_internals_partition_columns pc
JOIN sys.partitions p
ON p.partition_id = pc.partition_id
JOIN sys.columns c
ON column_id = partition_column_id
AND c.object_id = p.object_id
WHERE p.object_id=object_id('change');
RESULTS:
column_name column_id max_inrow_length system_type_id leaf_offset
------------- ----------- ------------------ -------------- -----------
col1 1 2 52 4
col2 2 10 175 6
col3 3 5 175 16
如今把 smallint 改成 int:
ALTER TABLE change
ALTER COLUMN col1 int;
最後, 再次運行清單6-5 中的列詳細信息查詢, 以查看 col1 如今在該行中開始的時間較晚,
而且在行標題信息以後沒有任何列在偏移量4處開始。
即便在表中放置任何數據以前, 因爲更改表而建立的新列也會發生:
column_name column_id max_inrow_length system_type_id leaf_offset
------------- ----------- ------------------ ---------------- -----------
col1 1 4 56 21
col2 2 10 175 6
col3 3 5 175 16
SQL server 在不實際刪除舊列時的行爲的另外一個缺點是, 行大小如今受到了更嚴格的限制。行大小如今包括舊列, 它再也不可用或可見 (除非使用 DBCC PAGE)。
例如, 若是建立的表具備一對大的固定長度字符列,
以下所示, 則能夠將 char (2000) 列更改成 char (3000):
CREATE TABLE bigchange
(col1 smallint, col2 char(2000), col3 char(1000));
ALTER TABLE bigchange
ALTER COLUMN col2 char(3000);
此時, 因爲3000字節列、1000字節列和 smallint, 行長度應僅超過4000個字節。可是, 若是嘗試添加另外一個3000字節的列, 則會失敗:
ALTER TABLE bigchange
ADD col4 char(3000);
Msg 1701, Level 16, State 1, Line 1
Creating or altering table 'bigchange' failed because the minimum row size
would be 9009, including 7 bytes of internal overhead. This exceeds the
maximum allowable table row size of 8060 bytes.
可是, 僅建立具備兩個3000字節列和1000字節列的表不會致使任何問題:
CREATE TABLE nochange
(col1 smallint, col2 char(3000), col3 char(1000), col4 char(3000));