Gần đây tôi đã thảo luận về một số tính năng mà Microsoft khuyên bạn không nên sử dụng và tôi nghĩ rằng bạn cũng nên quên sự tồn tại của nó. Có trường hợp một đồng nghiệp liên tục quảng bá chế độ xem tương thích ngược không được dùng nữa sys.sysprocesses
thay vì các chế độ xem quản lý động (DMV) mới hơn và một trường hợp khác trong đó một đồng nghiệp khác đã gỡ một máy chủ sản xuất bằng cách sử dụng SQL Server Profiler.
Lần chạy mới nhất của tôi với những thứ mà tôi hay quên nhất là một thủ tục được lưu trữ mới với ntext
tham số. Tôi đã kiểm tra và chắc chắn rằng kiểu dữ liệu khớp với lược đồ cho bảng bên dưới. Tâm trí tôi bắt đầu chạy đua về những kiểu dữ liệu cũ hơn này để giải thích lý do tại sao chúng ta thực sự không nên sử dụng chúng nữa:
- hình ảnh
- ntext
- text
Các loại này nằm trong danh sách không được dùng nữa vì nhiều lý do và đã giữ vị trí vĩnh viễn trong danh sách đó kể từ khi được thay thế bằng max
nhập lại trong SQL Server 2005. Một số điểm khó khăn sau đây bao gồm:
- bạn không thể sử dụng nhiều hàm chuỗi, như
LEFT()
,RTRIM()
,UPPER()
, và hầu hết các toán tử so sánh; - bạn cần sử dụng các chức năng như
TEXTPTR
,WRITETEXT
vàUPDATETEXT
để sửa đổi; - bạn không thể sử dụng các kiểu làm biến cục bộ;
- bạn không thể tham chiếu các cột trong
DISTINCT
,GROUP BY
,ORDER BY
, hoặc dưới dạng một cột được bao gồm (không phải bạn muốn làm bất kỳ cột nào trong số này); - các giá trị nhỏ hơn có thể vừa trong hàng chỉ có thể làm như vậy với
text in row
tùy chọn.
Đó không phải là một danh sách đầy đủ; có những khác biệt khác mà bạn có thể coi là quan trọng hơn hoặc ít hơn. Lý do cấp bách nhất đối với tôi là bạn không thể xây dựng lại chỉ mục nhóm trực tuyến nếu bảng chứa một trong những kiểu dữ liệu này.
Hãy tạo một cơ sở dữ liệu đơn giản với một vài bảng:
CREATE DATABASE BadIdeas; GO USE BadIdeas; GO CREATE TABLE dbo.t1(id bigint IDENTITY PRIMARY KEY, msg nvarchar(max)); CREATE TABLE dbo.t2(id bigint IDENTITY PRIMARY KEY, msg ntext);
Bây giờ, hãy thử thực hiện các thao tác trực tuyến trên bảng:
ALTER TABLE dbo.t1 REBUILD WITH (ONLINE = ON); GO ALTER TABLE dbo.t2 REBUILD WITH (ONLINE = ON);
Trong khi câu lệnh đầu tiên thành công, câu lệnh thứ hai trả về một thông báo lỗi như sau:
Msg 2725, Level 16, State 2Không thể thực hiện thao tác trực tuyến cho chỉ mục 'PK__t2__3213E83FEEA1E0AD' vì chỉ mục chứa cột 'msg' của kiểu dữ liệu văn bản, ntext, hình ảnh hoặc FILESTREAM. Đối với chỉ mục không phân cụm, cột có thể là cột bao gồm của chỉ mục. Đối với chỉ mục được phân nhóm, cột có thể là bất kỳ cột nào của bảng. Nếu DROP_EXISTING được sử dụng, cột có thể là một phần của chỉ mục mới hoặc cũ. Hoạt động phải được thực hiện ngoại tuyến.
Trong tình huống một lần, thông báo lỗi đủ dễ dàng để xử lý:bạn bỏ qua bảng hoặc, nếu bảng hoàn toàn phải được xây dựng lại, bạn sẽ làm việc với các nhóm của mình để lên lịch ngừng hoạt động. Khi bạn đang tự động hóa giải pháp duy trì chỉ mục hoặc triển khai cài đặt nén mới trên môi trường của mình, việc làm cho giải pháp của bạn xử lý trạng thái hiện tại hoặc tương lai sẽ là một vấn đề khó khăn hơn một chút.
Làm gì?
Bạn có thể bắt đầu thay thế các cột này bằng các cột hiện đại hơn của chúng. Đây là một truy vấn để giúp bạn theo dõi chúng bằng cách sử dụng sys.columns
chế độ xem danh mục, nhưng bạn đang ở trong riêng mình đối với bất kỳ tham chiếu rõ ràng nào có thể tồn tại trong mã ứng dụng của bạn:
SELECT [Schema] = s.name, [Object] = o.name, [Column] = c.name, [Data Type] = TYPE_NAME(c.user_type_id) + CASE WHEN c.system_type_id <> c.user_type_id THEN N' (' + TYPE_NAME(c.system_type_id) + N')' ELSE N'' END FROM sys.columns AS c INNER JOIN sys.objects AS o ON c.[object_id] = o.[object_id] INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] WHERE c.system_type_id IN (34, 35, 99) ORDER BY [Schema], [Object], [Column];
Đầu ra:
Có thể bạn muốn đi vào SSMS và thay đổi kiểu dữ liệu của các cột này theo cách thủ công, nhưng cũng có thể có những tác động khác. Ví dụ:các cột có thể có các ràng buộc mặc định được liên kết với chúng. Và bạn có thể đã lưu trữ các thủ tục với các tham số cần được cập nhật song song:
CREATE PROCEDURE dbo.sp1 @p1 ntext AS PRINT 1; GO
Để tìm tất cả các trường hợp này, bạn có thể điều chỉnh truy vấn trên để tìm kiếm dựa trên sys.parameters
xem danh mục thay vào đó:
SELECT [Schema] = s.name, [Object] = o.name, [Parameter] = p.name, [Data Type] = TYPE_NAME(p.user_type_id) + CASE WHEN p.system_type_id <> p.user_type_id THEN N' (' + TYPE_NAME(p.system_type_id) + N')' ELSE N'' END FROM sys.objects AS o INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] INNER JOIN sys.parameters AS p ON p.[object_id] = o.[object_id] WHERE p.system_type_id IN (34, 35, 99) ORDER BY [Schema], [Object], [Parameter];
Đầu ra:
Nếu bạn cần trả lại dữ liệu này trên tất cả các cơ sở dữ liệu, bạn có thể lấy sp_ineachdb
, một quy trình tôi đã viết (và ghi lại ở đây và ở đây) để khắc phục một số hạn chế trong sp_MSforeachdb
lỗi, không có tài liệu và không được hỗ trợ . Sau đó, bạn có thể làm điều này:
EXEC master.dbo.sp_ineachdb @command = N'SELECT [Database] = DB_NAME(), [Schema] = s.name, [Object] = o.name, [Column] = c.name, [Data Type] = TYPE_NAME(c.user_type_id) + CASE WHEN c.system_type_id <> c.user_type_id THEN N'' ('' + TYPE_NAME(c.system_type_id) + N'')'' ELSE N'''' END FROM sys.columns AS c INNER JOIN sys.objects AS o ON c.[object_id] = o.[object_id] INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] WHERE c.system_type_id IN (34, 35, 99) ORDER BY [Schema], [Object], [Column]; SELECT [Database] = DB_NAME(), [Schema] = s.name, [Object] = o.name, [Parameter] = p.name, [Data Type] = TYPE_NAME(p.user_type_id) + CASE WHEN p.system_type_id <> p.user_type_id THEN N'' ('' + TYPE_NAME(p.system_type_id) + N'')'' ELSE N'''' END FROM sys.objects AS o INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] INNER JOIN sys.parameters AS p ON p.[object_id] = o.[object_id] WHERE p.system_type_id IN (34, 35, 99) ORDER BY [Schema], [Object], [Parameter];';
Một lưu ý phụ thú vị ở đây:nếu bạn chạy điều đó trên tất cả cơ sở dữ liệu, bạn sẽ phát hiện ra rằng, ngay cả trong SQL Server 2019, Microsoft vẫn đang sử dụng một số kiểu cũ này.
Bạn có thể tự động hóa hơn nữa bằng cách chạy nó từ PowerShell hoặc bất kỳ công cụ tự động hóa nào bạn sử dụng để quản lý nhiều phiên bản của SQL Server.
Tất nhiên, đó chỉ là sự khởi đầu - nó chỉ tạo ra một danh sách. Bạn có thể mở rộng thêm nó để tạo phiên bản nháp của ALTER TABLE
các lệnh bạn cần cập nhật tất cả các bảng, nhưng các lệnh đó cần được xem lại trước khi thực thi và bạn vẫn cần tự sửa đổi các thủ tục (tạo ALTER PROCEDURE
các lệnh chỉ có các tên kiểu tham số được thay thế một cách chính xác không phải là một bài tập dễ dàng). Đây là một ví dụ tạo ALTER TABLE
các lệnh, có tính đến khả năng vô hiệu nhưng không có các biến chứng khác như các ràng buộc mặc định:
SELECT N'ALTER TABLE ' + QUOTENAME(s.name) + N'.' + QUOTENAME(o.name) + N' ALTER COLUMN ' + QUOTENAME(c.name) + N' ' + CASE c.system_type_id WHEN 34 THEN N'varbinary' WHEN 35 THEN N'varchar' WHEN 99 THEN N'nvarchar' END + N'(max)' + CASE c.is_nullable WHEN 0 THEN N' NOT' ELSE N'' END + N' NULL;' FROM sys.columns AS c INNER JOIN sys.objects AS o ON c.[object_id] = o.[object_id] INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] WHERE c.system_type_id IN (34, 35, 99);
Đầu ra:
ALTER TABLE [dbo]. [T2] ALTER COLUMN [msg] nvarchar (max) NULL;
Và trong trường hợp bạn đang tự hỏi, không, bạn không thể thực hiện thao tác một lần này với WITH (ONLINE = ON)
rõ ràng tùy chọn:
Không thể thực hiện thao tác ALTER COLUMN trực tuyến cho bảng 't2' vì cột 'msg' hiện đã hoặc đang được thay đổi thành một kiểu dữ liệu không được hỗ trợ:text, ntext, image, CLR type hoặc TẬP HỒ SƠ. Hoạt động phải được thực hiện ngoại tuyến.
Kết luận
Hy vọng rằng điều này cung cấp một số thông tin cơ bản về lý do tại sao bạn muốn loại bỏ các kiểu không dùng nữa này và một điểm bắt đầu để thực sự thực hiện các thay đổi. Microsoft đã học được một cách khó khăn rằng không có nhiều chức năng mà họ có thể tách ra khỏi sản phẩm, vì vậy tôi không lo ngại rằng những thứ này sẽ thực sự không còn tồn tại trong cuộc đời tôi. Nhưng nỗi sợ bị loại bỏ không phải là động lực duy nhất của bạn.