Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Các thay đổi cột chỉ siêu dữ liệu mới trong SQL Server 2016

ALTER TABLE ... ALTER COLUMN lệnh rất mạnh mẽ. Bạn có thể sử dụng nó để thay đổi kiểu dữ liệu, độ dài, độ chính xác, tỷ lệ, khả năng vô hiệu, đối chiếu ... và nhiều thứ khác của cột.

Nó chắc chắn thuận tiện hơn so với lựa chọn thay thế:Tạo một bảng mới và di chuyển dữ liệu mỗi khi cần thay đổi. Tuy nhiên, chỉ có rất nhiều điều có thể được thực hiện để che giấu sự phức tạp tiềm ẩn. Cùng với một số lượng lớn các hạn chế về những gì thậm chí có thể có với lệnh này, luôn có câu hỏi về hiệu suất.

Cuối cùng, các bảng được lưu trữ dưới dạng một chuỗi byte với một số siêu dữ liệu ở nơi khác trong hệ thống để mô tả ý nghĩa của mỗi byte đó và cách chúng liên quan đến từng cột khác nhau của bảng. Khi chúng tôi yêu cầu SQL Server thay đổi một số khía cạnh trong định nghĩa của cột, nó cần phải kiểm tra xem dữ liệu hiện có có tương thích với định nghĩa mới hay không. Nó cũng cần xác định xem bố cục vật lý hiện tại có cần thay đổi hay không.

Tùy thuộc vào loại thay đổi và cấu hình của cơ sở dữ liệu, một ALTER COLUMN lệnh sẽ cần thực hiện một trong các hành động sau:

  1. Chỉ thay đổi siêu dữ liệu trong bảng hệ thống.
  2. Kiểm tra tính tương thích của tất cả dữ liệu hiện có, sau đó thay đổi siêu dữ liệu.
  3. Viết lại một số hoặc tất cả dữ liệu được lưu trữ để phù hợp với định nghĩa mới.

Tùy chọn 1 thể hiện trường hợp lý tưởng theo quan điểm hiệu suất. Nó chỉ yêu cầu một số thay đổi đối với bảng hệ thống và một số lượng ghi nhật ký tối thiểu. Thao tác sẽ vẫn yêu cầu sửa đổi giản đồ hạn chế Sch-M khóa, nhưng các thay đổi siêu dữ liệu sẽ tự hoàn thành rất nhanh, bất kể kích thước của bảng.

Thay đổi Chỉ siêu dữ liệu

Có một số trường hợp đặc biệt cần chú ý, nhưng như một bản tóm tắt chung, các hành động sau chỉ yêu cầu thay đổi siêu dữ liệu:

  • Đi từ NOT NULL thành NULL cho cùng một loại dữ liệu.
  • Tăng kích thước tối đa của varchar , nvarchar hoặc varbinary cột (ngoại trừ max ).

​​Cải tiến trong SQL Server 2016

Chủ đề của bài đăng này là các thay đổi bổ sung được bật chỉ dành cho siêu dữ liệu từ SQL Server 2016 trở đi . Không cần thay đổi cú pháp và không cần sửa đổi cài đặt cấu hình. Bạn nhận được những cải tiến không có giấy tờ này miễn phí.

Các khả năng mới nhắm mục tiêu một tập hợp con có độ dài cố định Loại dữ liệu. Các khả năng mới áp dụng cho các bảng lưu trữ hàng trong các trường hợp sau:

  • Nén phải được bật:
    • Trên tất cả các chỉ mục và phân vùng , bao gồm cả đống cơ sở hoặc chỉ mục nhóm.
    • Một trong hai ROW hoặc PAGE nén.
    • Chỉ mục và phân vùng có thể sử dụng hỗn hợp của các mức nén này. Điều quan trọng là không có chỉ mục hoặc phân vùng chưa được nén.
  • Thay đổi từ NULL thành NOT NULL không được phép .
  • Thay đổi kiểu số nguyên sau đây được hỗ trợ:
    • smallint thành integer hoặc bigint .
    • integer thành bigint .
    • smallmoney thành money (sử dụng biểu diễn số nguyên trong nội bộ).
  • Thay đổi kiểu chuỗi và nhị phân sau đây được hỗ trợ:
    • char(n) thành char(m) hoặc varchar(m)
    • nchar(n) thành nchar(m) hoặc nvarchar(m)
    • binary(n) thành binary(m) hoặc varbinary(m)
    • Tất cả những điều trên chỉ dành cho n < mm != max
    • Thay đổi đối chiếu không được phép

Những thay đổi này chỉ có thể là siêu dữ liệu vì bố cục dữ liệu nhị phân bên dưới không thay đổi khi Trình mô tả cột định dạng hàng được sử dụng (do đó cần phải nén). Không có nén, kho lưu trữ hàng sử dụng FixedVar ban đầu biểu diễn, không thể đáp ứng các thay đổi kiểu dữ liệu có độ dài cố định này nếu không viết lại bố cục vật lý.

Bạn có thể nhận thấy rằng tinyint bị bỏ qua khỏi danh sách kiểu số nguyên. Điều này là do nó chưa được ký, trong khi các kiểu số nguyên khác đều được ký, vì vậy không thể thực hiện thay đổi chỉ siêu dữ liệu. Ví dụ:giá trị 255 có thể vừa với một byte cho tinyint , nhưng yêu cầu hai byte ở bất kỳ định dạng đã ký nào. Các định dạng đã ký có thể giữ từ -128 đến +127 trong một byte khi nén.

Ví dụ về Số nguyên

Một ứng dụng rất hữu ích của cải tiến này là thay đổi kiểu dữ liệu của cột bằng IDENTITY tài sản.

Giả sử chúng ta có bảng heap sau bằng cách sử dụng nén hàng (nén trang cũng sẽ hoạt động):

DROP TABLE IF EXISTS dbo.Test;
GO
CREATE TABLE dbo.Test
(
    id integer IDENTITY NOT NULL,
    some_value integer NOT NULL
)
WITH (DATA_COMPRESSION = ROW);

Hãy thêm 5 triệu hàng dữ liệu. Điều này đủ để làm cho nó rõ ràng (từ quan điểm hiệu suất) cho dù việc thay đổi kiểu dữ liệu cột có phải là một hoạt động chỉ siêu dữ liệu hay không:

WITH Numbers AS
(
    SELECT 
        n = ROW_NUMBER() OVER (ORDER BY @@SPID) 
    FROM sys.all_columns AS AC1
    CROSS JOIN sys.all_columns AS AC2
    ORDER BY n
    OFFSET 0 ROWS
    FETCH FIRST 5 * 1000 * 1000 ROWS ONLY
)
INSERT dbo.Test
    WITH (TABLOCKX)
(
    some_value
)
SELECT
    N.n
FROM Numbers AS N;

Tiếp theo, chúng tôi sẽ gửi lại IDENTITY để làm cho nó có vẻ như chúng ta gần như sắp hết các giá trị sẽ phù hợp với một số nguyên integer :

DBCC CHECKIDENT
(
    N'dbo.Test',
    RESEED,
    2147483646
);

Chúng tôi có thể thêm một hàng thành công:

INSERT dbo.Test
    (some_value)
VALUES
    (123456);

Nhưng đang cố thêm một hàng khác:

INSERT dbo.Test
    (some_value)
VALUES
    (7890);

Kết quả là một thông báo lỗi:

Msg 8115, Mức 16, Trạng thái 1, Dòng 1
Lỗi tràn số học khi chuyển đổi IDENTITY thành kiểu dữ liệu int.

Chúng tôi có thể khắc phục điều đó bằng cách chuyển đổi cột thành bigint :

ALTER TABLE dbo.Test
ALTER COLUMN id bigint NOT NULL;

Nhờ những cải tiến trong SQL Server 2016, lệnh này thay đổi chỉ siêu dữ liệu và hoàn thành ngay lập tức. INSERT trước hiện đã hoàn tất thành công câu lệnh (câu lệnh gây ra lỗi tràn số học).

Khả năng mới này không giải quyết được tất cả các vấn đề xung quanh việc thay đổi loại cột với IDENTITY bất động sản. Chúng tôi sẽ vẫn cần xóa và tạo lại bất kỳ chỉ mục nào trên cột, tạo lại bất kỳ khóa ngoại tham chiếu nào, v.v. Điều đó hơi nằm ngoài phạm vi của bài đăng này (mặc dù Aaron Bertrand đã viết về nó trước đây). Có thể thay đổi loại dưới dạng hoạt động chỉ siêu dữ liệu chắc chắn không ảnh hưởng gì. Với việc lập kế hoạch cẩn thận, các bước cần thiết khác có thể được thực hiện hiệu quả nhất có thể, chẳng hạn như sử dụng ghi nhật ký tối thiểu hoặc ONLINE hoạt động.

Cẩn thận với cú pháp

Đảm bảo luôn luôn chỉ định NULL hoặc NOT NULL khi thay đổi kiểu dữ liệu với ALTER COLUMN . Ví dụ, chúng tôi cũng muốn thay đổi kiểu dữ liệu của some_value trong bảng kiểm tra của chúng tôi từ integer NOT NULL thành bigint NOT NULL .

Khi chúng tôi viết lệnh, chúng tôi bỏ qua NULL hoặc NOT NULL vòng loại:

ALTER TABLE dbo.Test
ALTER COLUMN some_value bigint;

Lệnh này hoàn tất thành công dưới dạng thay đổi chỉ siêu dữ liệu, nhưng cũng xóa NOT NULL hạn chế. Cột bây giờ là bigint NULL , đó không phải là những gì chúng tôi dự định. Hành vi này đã được ghi lại, nhưng rất dễ bị bỏ qua.

Chúng tôi có thể cố gắng sửa chữa lỗi của mình bằng:

ALTER TABLE dbo.Test
ALTER COLUMN some_value bigint NOT NULL;

Đây không một thay đổi chỉ siêu dữ liệu. Chúng tôi không được phép thay đổi từ NULL thành NOT NULL (xem lại bảng trước đó nếu bạn cần cập nhật các điều kiện). SQL Server sẽ cần phải kiểm tra tất cả các giá trị hiện có để đảm bảo không có giá trị nào. Sau đó, nó sẽ viết lại mọi hàng về mặt vật lý của cái bàn. Cũng như bản thân nó chậm, những hành động này tạo ra rất nhiều nhật ký giao dịch, có thể có tác dụng phụ.

Xin lưu ý thêm, lỗi tương tự này không thể xảy ra đối với các cột có IDENTITY bất động sản. Nếu chúng ta viết ALTER COLUMN câu lệnh không có NULL hoặc NOT NULL trong trường hợp đó, công cụ giả định một cách hữu ích rằng chúng tôi có ý NOT NULL bởi vì thuộc tính nhận dạng không được phép trên các cột có thể rỗng. Tốt hơn hết là không nên dựa vào hành vi này.

Luôn chỉ định NULL hoặc NOT NULL với ALTER COLUMN .

Đối chiếu

Cần đặc biệt cẩn thận khi thay đổi cột chuỗi có đối chiếu không khớp với giá trị mặc định cho cơ sở dữ liệu.

Ví dụ:giả sử chúng ta có một bảng với đối chiếu phân biệt chữ hoa chữ thường và trọng âm (giả sử mặc định của cơ sở dữ liệu là khác):

DROP TABLE IF EXISTS dbo.Test2;
GO
CREATE TABLE dbo.Test2
(
    id integer IDENTITY NOT NULL,
    some_string char(8) COLLATE Latin1_General_100_CS_AS NOT NULL
)
WITH (DATA_COMPRESSION = ROW);

Thêm 5 triệu hàng dữ liệu:

WITH Numbers AS
(
    SELECT 
        n = ROW_NUMBER() OVER (ORDER BY @@SPID) 
    FROM sys.all_columns AS AC1
    CROSS JOIN sys.all_columns AS AC2
    ORDER BY n
    OFFSET 0 ROWS
    FETCH FIRST 5 * 1000 * 1000 ROWS ONLY
)
INSERT dbo.Test2
    WITH (TABLOCKX)
(
    some_string
)
SELECT
    CONVERT(char(8), N.n) COLLATE Latin1_General_100_CS_AS
FROM Numbers AS N;

Nhân đôi độ dài của cột chuỗi bằng lệnh sau:

ALTER TABLE dbo.Test2
ALTER COLUMN some_string char(16) NOT NULL;

Chúng tôi nhớ chỉ định NOT NULL , nhưng quên về đối chiếu không mặc định. SQL Server giả định rằng chúng tôi muốn thay đổi đối chiếu thành mặc định của cơ sở dữ liệu (Latin1_General_CI_AS cho cơ sở dữ liệu thử nghiệm của tôi). Việc thay đổi đối chiếu ngăn hoạt động chỉ ở chế độ siêu dữ liệu và do đó, hoạt động sẽ chạy trong vài phút, tạo ra đống nhật ký.

Tạo lại bảng và dữ liệu bằng cách sử dụng tập lệnh trước, sau đó thử ALTER COLUMN lệnh một lần nữa, nhưng chỉ định đối chiếu không mặc định hiện có như một phần của lệnh:

ALTER TABLE dbo.Test2
ALTER COLUMN some_string 
    char(16) COLLATE Latin1_General_100_CS_AS NOT NULL;

Thay đổi hiện hoàn tất ngay lập tức, dưới dạng hoạt động chỉ siêu dữ liệu. Như với NULLNOT NULL cú pháp, nó trả tiền để được rõ ràng để tránh tai nạn. Đây là lời khuyên tốt nói chung, không chỉ cho ALTER COLUMN .

Nén

Xin lưu ý rằng việc nén cần phải được chỉ định rõ ràng cho từng chỉ mục và riêng cho bảng cơ sở nếu đó là một đống. Đây là một ví dụ khác trong đó việc sử dụng cú pháp hoặc phím tắt viết tắt có thể ngăn cản kết quả mong muốn.

Ví dụ:bảng sau không chỉ định nén rõ ràng cho khóa chính hoặc định nghĩa chỉ mục nội dòng:

CREATE TABLE dbo.Test
(
    id integer IDENTITY NOT NULL PRIMARY KEY,
    some_value integer NOT NULL
        INDEX [IX dbo.Test some_value]
)
WITH (DATA_COMPRESSION = PAGE);

PRIMARY KEY sẽ được gán tên, mặc định là CLUSTERED và là PAGE bị nén. Chỉ mục nội dòng sẽ là NONCLUSTERED và hoàn toàn không bị nén. Bảng này sẽ không được bật cho bất kỳ tối ưu hóa mới nào vì không phải tất cả các chỉ mục và phân vùng đều được nén.

Một định nghĩa bảng tốt hơn và rõ ràng hơn sẽ là:

CREATE TABLE dbo.Test
(
    id integer IDENTITY NOT NULL
        CONSTRAINT [PK dbo.Test id]
        PRIMARY KEY CLUSTERED
        WITH (DATA_COMPRESSION = PAGE),
    some_value integer NOT NULL
        INDEX [IX dbo.Test some_value]
        NONCLUSTERED
        WITH (DATA_COMPRESSION = ROW)        
);

Bảng này sẽ đủ điều kiện cho các tối ưu hóa mới vì tất cả các chỉ mục và phân vùng đều được nén. Như đã lưu ý trước đây, trộn các kiểu nén là tốt.

Có nhiều cách để viết CREATE TABLE này tuyên bố một cách rõ ràng, do đó, có một yếu tố sở thích cá nhân. Điểm rút ra quan trọng là luôn rõ ràng về những gì bạn muốn. Điều này áp dụng cho CREATE INDEX riêng biệt cũng như các câu lệnh.

Sự kiện mở rộng và Cờ theo dõi

Có một sự kiện mở rộng dành riêng cho ALTER COLUMN chỉ siêu dữ liệu mới các hoạt động được hỗ trợ trong SQL Server 2016 trở đi.

Sự kiện mở rộng là compressed_alter_column_is_md_only trong Gỡ lỗi kênh. Các trường sự kiện của nó là object_id , column_idis_md_only (true / false).

Sự kiện này chỉ cho biết nếu một thao tác chỉ là siêu dữ liệu do các khả năng mới của SQL Server 2016. Các thay đổi cột chỉ dành cho siêu dữ liệu trước năm 2016 sẽ hiển thị is_md_only = false mặc dù vẫn chỉ là siêu dữ liệu.

Các sự kiện mở rộng khác hữu ích để theo dõi ALTER COLUMN hoạt động bao gồm metadata_ddl_alter_columnalter_column_event , cả trong Analytic kênh.

Bạn có cần phải tắt các khả năng mới của SQL Server 2016 vì bất kỳ lý do gì, cờ theo dõi toàn cầu (hoặc khởi động) 3618 không có tài liệu có thể được sử dụng. Cờ theo dõi này không hiệu quả khi được sử dụng ở cấp phiên. Không có cách nào để chỉ định cờ theo dõi cấp truy vấn với ALTER COLUMN lệnh.

Kết luận

Có thể thay đổi một số kiểu dữ liệu số nguyên có độ dài cố định bằng thay đổi chỉ siêu dữ liệu là một cải tiến sản phẩm rất đáng hoan nghênh. Nó yêu cầu bảng đã được nén hoàn toàn, nhưng dù sao thì đó cũng đang trở thành một điều phổ biến. Điều này đặc biệt đúng vì tính năng nén được bật trong tất cả các phiên bản bắt đầu với SQL Server 2016 Gói Dịch vụ 1.

Các cột kiểu chuỗi có độ dài cố định có lẽ ít phổ biến hơn nhiều. Một số điều này có thể là do những cân nhắc hơi lạc hậu như sử dụng dung lượng. Khi được nén, các cột chuỗi có độ dài cố định không lưu trữ các khoảng trống ở cuối, làm cho chúng hiệu quả như các cột chuỗi có độ dài thay đổi theo quan điểm lưu trữ. Việc cắt bớt không gian để thao tác hoặc hiển thị có thể gây khó chịu, nhưng nếu dữ liệu thường chiếm hầu hết độ dài tối đa, thì các loại độ dài cố định có thể có những lợi thế quan trọng, đặc biệt là liên quan đến việc cấp bộ nhớ cho những thứ như sắp xếp và băm.

Không phải tất cả đều là tin tốt khi tính năng nén được bật. Tôi đã đề cập trước đó rằng SQL Server đôi khi có thể thực hiện thay đổi chỉ siêu dữ liệu sau khi kiểm tra rằng tất cả các giá trị hiện có sẽ chuyển đổi thành công sang kiểu mới. Đây là trường hợp khi sử dụng ALTER COLUMN để thay đổi từ integer thành smallint Ví dụ. Rất tiếc, các thao tác này hiện không chỉ dành cho siêu dữ liệu dành cho các đối tượng nén.

Lời cảm ơn

Đặc biệt cảm ơn Panagiotis Antonopoulos (Kỹ sư phần mềm chính) và Mirek Sztajno (Người quản lý chương trình cấp cao) từ nhóm sản phẩm SQL Server để được hỗ trợ và hướng dẫn trong quá trình nghiên cứu và viết bài này.

Không có chi tiết nào được đưa ra trong tác phẩm này nên được coi là tài liệu chính thức của Microsoft hoặc tuyên bố sản phẩm.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Thủ tục đã lưu trữ xuất dữ liệu thành tệp csv chỉ xuất sang một tệp

  2. Cách thực hiện một truy vấn chuyển qua CHÈN trong SQL Server

  3. Làm cách nào để bạn sao chép bản ghi trong bảng SQL nhưng hoán đổi id duy nhất của hàng mới?

  4. Máy chủ SQL tương đương với GROUP_CONCAT ()

  5. Giới thiệu các biểu thức bảng phổ biến trong SQL Server