Hành vi thực tế của mức độ tương thích 80 là gì?


47

Ai đó có thể cung cấp cho tôi cái nhìn sâu sắc hơn về tính năng chế độ tương thích? Đó là hành vi khác nhau hơn tôi mong đợi.

Theo như tôi hiểu các chế độ tương thích, đó là về tính khả dụng và hỗ trợ của các cấu trúc ngôn ngữ nhất định giữa các phiên bản khác nhau của SQL Server.

Nó không ảnh hưởng đến hoạt động bên trong của phiên bản công cụ cơ sở dữ liệu. Nó sẽ cố gắng ngăn chặn việc sử dụng các tính năng và cấu trúc chưa có sẵn trong các phiên bản trước.

Tôi vừa tạo một cơ sở dữ liệu mới với mức độ tương thích 80 trong SQL Server 2008 R2. Tạo một bảng với một cột int duy nhất và điền vào đó một vài hàng.

Sau đó thực hiện một câu lệnh chọn với một row_number()hàm.

Tôi nghĩ rằng, vì hàm row_number chỉ được giới thiệu vào năm 2005, nên điều này sẽ gây ra lỗi trong chế độ compat 80.

Nhưng tôi ngạc nhiên khi điều này làm việc tốt. Sau đó, chắc chắn, các quy tắc compat chỉ được đánh giá khi bạn 'lưu thứ gì đó'. Vì vậy, tôi đã tạo một Proc được lưu trữ cho câu lệnh row_number của mình.

Việc tạo Proc được lưu trữ đã diễn ra tốt đẹp và tôi hoàn toàn có thể thực hiện nó và thu được kết quả.

Ai đó có thể giúp tôi hiểu rõ hơn về hoạt động của chế độ tương thích? Sự hiểu biết của tôi rõ ràng là thiếu sót.

Câu trả lời:


66

Từ các tài liệu :

Đặt các hành vi cơ sở dữ liệu nhất định để tương thích với phiên bản SQL Server được chỉ định.
...
Mức độ tương thích chỉ cung cấp khả năng tương thích ngược một phần với các phiên bản SQL Server trước đó. Sử dụng cấp độ tương thích làm trợ giúp di chuyển tạm thời để khắc phục sự khác biệt của phiên bản trong các hành vi được kiểm soát bởi cài đặt cấp độ tương thích có liên quan.

Theo cách hiểu của tôi, chế độ tương thích là về hành vi và phân tích cú pháp, không dành cho những thứ như trình phân tích cú pháp nói, "Này, bạn không thể sử dụng ROW_NUMBER()!" Đôi khi, mức độ tương thích thấp hơn cho phép bạn tiếp tục thoát khỏi cú pháp không còn được hỗ trợ và đôi khi nó ngăn bạn sử dụng các cấu trúc cú pháp mới. Tài liệu liệt kê một số ví dụ rõ ràng, nhưng đây là một vài minh chứng:


Truyền các hàm dựng sẵn làm đối số hàm

Mã này hoạt động ở mức tương thích 90+:

SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);

Nhưng vào năm 80, nó mang lại:

Msg 102, Cấp 15, Trạng thái 1
Cú pháp không chính xác gần '('.

Vấn đề cụ thể ở đây là trong 80 bạn không được phép chuyển một hàm tích hợp vào một hàm. Nếu bạn muốn ở trong chế độ tương thích 80, bạn có thể giải quyết vấn đề này bằng cách nói:

DECLARE @db_id INT = DB_ID();

SELECT * 
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);

Truyền loại bảng cho hàm có giá trị bảng

Tương tự như trên, bạn có thể gặp lỗi cú pháp khi sử dụng TVP và cố gắng chuyển nó sang hàm có giá trị bảng. Điều này hoạt động ở cấp độ compat hiện đại:

CREATE TYPE dbo.foo AS TABLE(bar INT);
GO
CREATE FUNCTION dbo.whatever
(
  @foo dbo.foo READONLY
)
RETURNS TABLE
AS 
  RETURN (SELECT bar FROM @foo);
GO

DECLARE @foo dbo.foo;
INSERT @foo(bar) SELECT 1;
SELECT * FROM dbo.whatever(@foo);

Tuy nhiên, thay đổi mức độ tương thích thành 80 và chạy lại ba dòng cuối cùng; bạn nhận được thông báo lỗi này:

Msg 137, Cấp 16, Trạng thái 1, Dòng 19
Phải khai báo biến vô hướng "@foo".

Không thực sự có bất kỳ cách giải quyết tốt nào ngoài đỉnh đầu của tôi, ngoài việc nâng cấp cấp độ compat hoặc nhận kết quả theo một cách khác.


Sử dụng tên cột đủ điều kiện trong ỨNG DỤNG

Trong 90 chế độ tương thích trở lên, bạn có thể thực hiện việc này mà không gặp vấn đề gì:

SELECT * FROM sys.dm_exec_cached_plans AS p
  CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;

Tuy nhiên, trong chế độ tương thích 80, cột đủ điều kiện được trao cho hàm sẽ phát sinh lỗi cú pháp chung:

Msg 102, Cấp 15, Trạng thái 1
Cú pháp không chính xác gần '.'.


ĐẶT HÀNG theo một bí danh xảy ra khớp với tên cột

Xem xét truy vấn này:

SELECT name = REVERSE(name), realname = name 
FROM sys.all_objects AS o
ORDER BY o.name;

Trong chế độ tương thích 80, kết quả như sau:

001_ofni_epytatad_ps   sp_datatype_info_100
001_scitsitats_ps      sp_statistics_100
001_snmuloc_corps_ps   sp_sproc_columns_100
...

Trong chế độ tương thích 90, kết quả khá khác nhau:

snmuloc_lla      all_columns
stcejbo_lla      all_objects
sretemarap_lla   all_parameters
...

Nguyên nhân? Trong chế độ tương thích 80, tiền tố bảng bị bỏ qua hoàn toàn, do đó, nó được sắp xếp theo biểu thức được xác định bởi bí danh trong SELECTdanh sách. Trong các mức độ tương thích mới hơn, tiền tố của bảng được xem xét, vì vậy SQL Server sẽ thực sự sử dụng cột đó trong bảng (nếu nó được tìm thấy). Nếu ORDER BYkhông tìm thấy bí danh trong bảng, các mức tương thích mới hơn sẽ không tha thứ cho sự mơ hồ. Xem xét ví dụ này:

SELECT myname = REVERSE(name), realname = name 
FROM sys.all_objects AS o
ORDER BY o.myname;

Kết quả được sắp xếp theo mynamebiểu thức trong 80, vì một lần nữa tiền tố bảng bị bỏ qua, nhưng trong 90, nó tạo ra thông báo lỗi này:

Msg 207, Cấp 16, Bang 1, Dòng 3
Tên cột không hợp lệ 'myname'.

Điều này cũng được giải thích trong tài liệu :

Khi liên kết các tham chiếu cột trong ORDER BYdanh sách với các cột được xác định trong SELECTdanh sách, sự mơ hồ của cột bị bỏ qua và các tiền tố cột đôi khi bị bỏ qua. Điều này có thể khiến kết quả được đặt trở lại theo thứ tự không mong muốn.

Ví dụ: một ORDER BYmệnh đề có một cột hai phần ( <table_alias>.<column>) được sử dụng làm tham chiếu đến một cột trong danh sách CHỌN được chấp nhận, nhưng bí danh bảng bị bỏ qua. Hãy xem xét các truy vấn sau đây.

SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1

Khi được thực thi, tiền tố cột bị bỏ qua trong ORDER BY. Hoạt động sắp xếp không xảy ra trên cột nguồn được chỉ định ( x.c1) như mong đợi; thay vào đó nó xảy ra trên dẫn xuấtc1cột được xác định trong truy vấn. Kế hoạch thực hiện cho truy vấn này cho thấy rằng các giá trị cho cột dẫn xuất được tính toán trước và sau đó các giá trị được tính toán được sắp xếp.


ĐẶT HÀNG THEO một cái gì đó không có trong danh sách CHỌN

Trong chế độ tương thích 90, bạn không thể làm điều này:

SELECT name = COALESCE(a.name, '') FROM sys.objects AS a
UNION ALL
SELECT name = COALESCE(a.name, '') FROM sys.objects AS a
ORDER BY a.name;

Kết quả:

Msg 104, Cấp 16, Trạng thái 1
ĐẶT HÀNG theo các mục phải xuất hiện trong danh sách chọn nếu câu lệnh chứa toán tử UNION, INTERSECT hoặc EXCEPT.

Tuy nhiên, trong 80, bạn vẫn có thể sử dụng cú pháp này.


Cũ, bên ngoài icky tham gia

Chế độ 80 cũng cho phép bạn sử dụng cú pháp nối ngoài cũ, không dùng nữa ( *=/=*):

SELECT o.name, c.name
FROM sys.objects AS o, sys.columns AS c
WHERE o.[object_id] *= c.[object_id];

Trong SQL Server 2008/2008 R2, nếu bạn ở độ tuổi 90 trở lên, bạn sẽ nhận được thông báo dài dòng này:

Msg 4147, Cấp 15, Trạng thái 1
Truy vấn sử dụng các toán tử nối ngoài không ANSI (" *=" hoặc " =*"). Để chạy truy vấn này mà không cần sửa đổi, vui lòng đặt mức độ tương thích cho cơ sở dữ liệu hiện tại thành 80, bằng cách sử dụng tùy chọn SET COMPATITALITY_LEVEL của ALTER DATABASE. Chúng tôi khuyên bạn nên viết lại truy vấn bằng cách sử dụng các toán tử nối ngoài ANSI (LEFT OUTER THAM GIA, RIGHT OUTER THAM GIA). Trong các phiên bản tương lai của SQL Server, các toán tử tham gia không ANSI sẽ không được hỗ trợ ngay cả trong các chế độ tương thích ngược.

Trong SQL Server 2012, đây không còn là cú pháp hợp lệ nữa và mang lại kết quả như sau:

Msg 102, Cấp 15, Trạng thái 1, Dòng 3
Cú pháp không chính xác gần '* ='.

Tất nhiên trong SQL Server 2012, bạn không còn có thể giải quyết vấn đề này bằng mức độ tương thích, vì 80 không còn được hỗ trợ. Nếu bạn nâng cấp cơ sở dữ liệu ở chế độ 80 compat (bằng cách nâng cấp tại chỗ, tách / đính kèm, sao lưu / khôi phục, vận chuyển nhật ký, phản chiếu, v.v.), nó sẽ tự động được nâng cấp lên 90 cho bạn.


Gợi ý bảng mà không CÓ

Trong chế độ 80 compat, bạn có thể sử dụng như sau và gợi ý bảng sẽ được quan sát:

SELECT * FROM dbo.whatever NOLOCK; 

Trong 90+, đó NOLOCKkhông còn là gợi ý bảng nữa, đó là bí danh. Nếu không, điều này sẽ làm việc:

SELECT * FROM dbo.whatever AS w NOLOCK;

Nhưng nó không:

Msg 1018, Cấp 15, Trạng thái 1
Cú pháp không chính xác gần 'NOLOCK'. Nếu điều này được dự định là một phần của gợi ý bảng, thì từ khóa A và dấu ngoặc đơn hiện đang được yêu cầu. Xem Sách SQL Server trực tuyến để biết cú pháp thích hợp.

Bây giờ, để chứng minh rằng hành vi không được quan sát trong ví dụ đầu tiên khi ở chế độ 90 compat, hãy sử dụng AdventureWorks (đảm bảo rằng nó ở mức độ tương thích cao hơn) và chạy như sau:

BEGIN TRANSACTION;
SELECT TOP (1) * FROM Sales.SalesOrderHeader UPDLOCK;
SELECT * FROM sys.dm_tran_locks 
  WHERE request_session_id = @@SPID
  AND resource_type IN ('KEY', 'OBJECT'); -- how many rows here? 0
COMMIT TRANSACTION;

BEGIN TRANSACTION;
SELECT TOP (1) * FROM Sales.SalesOrderHeader WITH (UPDLOCK);
SELECT * FROM sys.dm_tran_locks
  WHERE request_session_id = @@SPID
  AND resource_type IN ('KEY', 'OBJECT'); -- how many rows here? 2
COMMIT TRANSACTION;

Điều này đặc biệt có vấn đề vì hành vi thay đổi mà không có thông báo lỗi hoặc thậm chí là lỗi. Và đó cũng là điều mà trình cố vấn nâng cấp và các công cụ khác thậm chí có thể không phát hiện ra, vì đối với tất cả những gì nó biết, đó là bí danh bảng.


Chuyển đổi liên quan đến các loại ngày / giờ mới

Các loại ngày / giờ mới được giới thiệu trong SQL Server 2008 (ví dụ datedatetime2) hỗ trợ phạm vi lớn hơn nhiều so với bản gốc datetimesmalldatetime). Chuyển đổi rõ ràng các giá trị ngoài phạm vi được hỗ trợ sẽ không thành công cho dù mức độ tương thích là gì, ví dụ:

SELECT CONVERT(SMALLDATETIME, '00010101');

Sản lượng:

Msg 242, Cấp 16, Trạng thái 3
Việc chuyển đổi loại dữ liệu varchar thành loại dữ liệu thời gian nhỏ dẫn đến một giá trị ngoài phạm vi.

Tuy nhiên, chuyển đổi ngầm sẽ tự giải quyết ở các cấp độ tương thích mới hơn. Ví dụ: điều này sẽ hoạt động trong hơn 100:

SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');

Nhưng vào năm 80 (và cả năm 90), nó cũng gây ra lỗi tương tự như trên:

Msg 242, Cấp 16, Trạng thái 3
Việc chuyển đổi loại dữ liệu varchar thành loại dữ liệu datetime dẫn đến giá trị ngoài phạm vi.


Điều khoản dự phòng cho các điều khoản kích hoạt

Đây là một kịch bản tối nghĩa xuất hiện ở đây . Trong chế độ tương thích 80, điều này sẽ thành công:

CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;

Trong 90 khả năng tương thích và cao hơn, điều này không còn phân tích cú pháp nữa và thay vào đó bạn nhận được thông báo lỗi sau:

Msg 1034, Cấp 15, Trạng thái 1, Quy trình tx
Lỗi cú pháp: Đặc tả trùng lặp của hành động "CẬP NHẬT" trong khai báo kích hoạt.


PIVOT / UNPIVOT

Một số dạng cú pháp sẽ không hoạt động dưới 80 (nhưng chỉ hoạt động tốt trong 90+):

SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;

Sản lượng này:

Msg 156, Cấp 15, Trạng thái 1
Cú pháp không chính xác gần từ khóa 'cho'.

Đối với một số cách giải quyết, bao gồm CROSS APPLY, xem những câu trả lời này .


Các chức năng tích hợp mới

Hãy thử sử dụng các chức năng mới như TRY_CONVERT()trong cơ sở dữ liệu với mức độ tương thích <110. Đơn giản là chúng không được nhận ra ở đó.

SELECT TRY_CONVERT(INT, 1);

Kết quả:

Msg 195, Cấp 15, Trạng thái 10
'TRY_CONVERT' không phải là tên hàm tích hợp được công nhận.


sự giới thiệu

Chỉ sử dụng chế độ tương thích 80 nếu bạn thực sự cần nó. Vì nó sẽ không còn có sẵn trong phiên bản tiếp theo sau 2008 R2, điều cuối cùng bạn muốn làm là viết mã ở cấp độ compat này, dựa vào các hành vi bạn thấy và sau đó có cả đống vỡ khi bạn không thể sử dụng mức độ compat đó. Hãy suy nghĩ về phía trước và đừng cố vẽ mình vào một góc bằng cách mua thời gian để tiếp tục sử dụng cú pháp cũ, không dùng nữa.


1
Rõ ràng đó là một câu trả lời tốt hơn của tôi!
Max Vernon

Cảm ơn bạn rất nhiều vì câu trả lời công phu này, Aaron! Và để sửa chữa nhiều lỗi chính tả của tôi.
souplex

1
Ghi chú tương thích SQL Server 2014 được tìm thấy tại đây: msdn.microsoft.com/en-us/l Library / bb510680 (v = sql.120) .aspx
Josh Gallagher

9

Mức độ tương thích chỉ có mặt để cho phép di chuyển có kiểm soát từ phiên bản SQL Server trước đó. Compat Level 90 không loại trừ việc sử dụng các tính năng mới, nó đơn giản có nghĩa là các khía cạnh nhất định của cơ sở dữ liệu được giữ lại theo cách tương thích với cách SQL Server 2005 hoạt động.

Xem http://msdn.microsoft.com/en-us/l Library / bb510680.aspx để biết thêm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.