Có sự khác biệt nào giữa NUMERIC và DECIMAL không?


47

Tôi biết rằng các kiểu dữ liệu NUMERIC và DECIMAL trong SQL Server hoạt động giống nhau: cú pháp tạo chúng giống nhau, các phạm vi giá trị bạn có thể lưu trữ trong chúng là như nhau, v.v.

Tuy nhiên, tài liệu MSDN mô tả mối quan hệ giữa hai như sau:

số là chức năng tương đương với số thập phân.

Thông thường, khi tôi thấy vòng loại " tương đương về chức năng ", điều đó có nghĩa là hai thứ không hoàn toàn giống nhau, nhưng chúng là hai loại khác nhau không thể phân biệt được với bên ngoài .

Điều này có đúng không? Có sự khác biệt nào giữa SỐ và KHAI THÁC chỉ xảy ra để hành xử giống nhau đối với người quan sát bên ngoài không? Hoặc chúng có thực sự tương đương nhau không, ví dụ như NUMERIC chỉ là một từ đồng nghĩa kế thừa cho DECIMAL?


1
Bạn có thể tìm thấy sự khác biệt trong hỗ trợ bên ngoài SQL Server, ví dụ tôi chỉ nhận thấy sự khác biệt kỳ lạ này trong SSIS .
Aaron Bertrand

Câu trả lời:


56

Chúng thực sự tương đương, nhưng chúng là các loại độc lập, và không phải là từ đồng nghĩa về mặt kỹ thuật , như ROWVERSIONTIMESTAMP- mặc dù chúng có thể được gọi là từ đồng nghĩa trong tài liệu cùng một lúc . Đó là một ý nghĩa hơi khác của từ đồng nghĩa (ví dụ: chúng không thể phân biệt được ngoại trừ trong tên, không phải là một bí danh cho người khác). Mỉa mai phải không?

Những gì tôi diễn giải từ các từ trong MSDN thực sự là:

Những loại này giống hệt nhau, chúng chỉ có tên khác nhau.

Khác với các type_idgiá trị, mọi thứ ở đây đều giống hệt nhau:

SELECT * FROM sys.types WHERE name IN (N'numeric', N'decimal');

Tôi hoàn toàn không có kiến ​​thức về bất kỳ sự khác biệt về hành vi nào giữa hai người và quay trở lại SQL Server 6.5, luôn coi họ là 100% có thể hoán đổi cho nhau.

cho DECIMAL (18,2) và NUMERIC (18,2)? Gán cái này cho cái kia về mặt kỹ thuật là "chuyển đổi"?

Chỉ khi bạn làm như vậy rõ ràng. Bạn có thể chứng minh điều này một cách dễ dàng bằng cách tạo một bảng và sau đó kiểm tra kế hoạch truy vấn cho các truy vấn thực hiện rõ ràng hoặc - bạn có thể mong đợi - chuyển đổi ngầm định. Đây là một bảng đơn giản:

CREATE TABLE [dbo].[NumDec]
(
    [num] [numeric](18, 0) NULL,
    [dec] [decimal](18, 0) NULL
);

Bây giờ hãy chạy các truy vấn này và nắm bắt kế hoạch:

DECLARE @num NUMERIC(18,0);
DECLARE @dec DECIMAL(18,0);

SELECT 
  CONVERT(DECIMAL(18,0), [num]), -- conversion
  CONVERT(NUMERIC(18,0), [dec])  -- conversion
FROM dbo.NumDec
UNION ALL SELECT [num],[dec] 
  FROM dbo.NumDec WHERE [num] = @dec  -- no conversion
UNION ALL SELECT [num],[dec] 
  FROM dbo.NumDec WHERE [dec] = @num; -- no conversion

Như được hiển thị trong SQL Sentry Plan Explorer *, kế hoạch không thực sự thú vị:

nhập mô tả hình ảnh ở đây

Nhưng tab Biểu thức chắc chắn là:

nhập mô tả hình ảnh ở đây

Như tôi đã nhận xét ở trên, chúng tôi có các chuyển đổi rõ ràng nơi chúng tôi đã yêu cầu chúng, nhưng không có chuyển đổi rõ ràng nơi chúng tôi có thể đã mong đợi chúng. Có vẻ như trình tối ưu hóa cũng coi chúng là có thể hoán đổi cho nhau.

Đi trước và thử kiểm tra này, quá (dữ liệu và chỉ mục).

CREATE TABLE [dbo].[NumDec2]
(
    [num] [numeric](18, 2) NULL,
    [dec] [decimal](18, 2) NULL
);

INSERT dbo.NumDec2([num],[dec])
SELECT [object_id] + 0.12, [object_id] + 0.12
  FROM sys.all_columns;

CREATE INDEX [ix_num] ON dbo.NumDec2([num]);
CREATE INDEX [ix_dec] ON dbo.NumDec2([dec]);

Bây giờ hãy chạy truy vấn này:

DECLARE @num NUMERIC(18,2) = -1291334356.88,
        @dec NUMERIC(18,2) = -1291334356.88;

SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = @num
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = @dec;

Gói không có chuyển đổi (trên thực tế, tab Biểu thức trống):

nhập mô tả hình ảnh ở đây

Ngay cả những điều này không dẫn đến bất kỳ chuyển đổi bất ngờ. Tất nhiên bạn thấy nó trên RHS trong vị ngữ, nhưng trong mọi trường hợp, không có bất kỳ chuyển đổi nào phải xảy ra đối với dữ liệu cột để tạo điều kiện cho việc tìm kiếm (ít hơn một lần quét).

SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(DECIMAL(18,2), @num)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(DECIMAL(18,2), @dec)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(NUMERIC(18,2), @num)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(NUMERIC(18,2), @dec)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(DECIMAL(18,2), @num)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(DECIMAL(18,2), @dec)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(NUMERIC(18,2), @num)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(NUMERIC(18,2), @dec);

Cá nhân, tôi thích sử dụng thuật ngữ này DECIMALchỉ vì nó chính xác và mô tả hơn nhiều. BITlà "số" quá.

* Disclaimer: I work for SQL Sentry.

Tôi biết rằng SQL coi, ví dụ như DECIMAL (18,2) và DECIMAL (18,0) là "các loại khác nhau"; điều này có nghĩa tương tự với DECIMAL (18,2) và NUMERIC (18,2) không? Gán cái này cho cái kia về mặt kỹ thuật là "chuyển đổi"?
KutuluMike

@MichaelEdenfield Cập nhật câu trả lời của tôi cho câu hỏi mới của bạn.
Aaron Bertrand

1
Tôi biết đây là một câu trả lời cũ nhưng tôi chỉ tìm thấy một trường hợp khi nghĩ rằng số và số thập phân là từ đồng nghĩa khiến SQL Server phát sinh lỗi. Chỉ cần nghĩ rằng tôi nên để lại một bình luận ở đây trong trường hợp người khác có thể được hưởng lợi từ nó.
Zohar Peled

@AaronBertrand Tôi đã bình chọn cho câu trả lời của bạn vì nó hữu ích. Cả hai loại trông giống hệt nhau vì vậy nếu đó là trường hợp, tại sao chúng được đặt tên khác nhau? Có lý do lịch sử nào không?
Ivanzinho

@Ivanzinho Tôi không chắc câu hỏi của bạn có khoa trương không, có rất nhiều lý thuyết (cả trên trang này và câu trả lời bạn liên kết), nhưng nếu bạn muốn có câu trả lời dứt khoát, có lẽ bạn sẽ không gặp may. Bạn cần theo dõi các kỹ sư ban đầu đã triển khai cả hai loại trong SQL Server và dựa vào bộ nhớ của họ về cả việc triển khai đó và giải thích tiêu chuẩn của họ tại thời điểm đó.
Aaron Bertrand

15

Tuy nhiên, chúng giống hệt nhau trong thực tế (từ tiêu chuẩn SQL 2003):

21) NUMERIC chỉ định loại dữ liệu chính xác bằng số, với độ chính xác thập phân và tỷ lệ được chỉ định bởi precisionscale.

22) DECIMAL chỉ định loại dữ liệu chính xác bằng số, với tỷ lệ thập phân được chỉ định bởi độ chính xác thập phân được xác địnhscalethực hiện bằng hoặc lớn hơn giá trị của chỉ định precision.


5
Câu hỏi cơ bản sau đó (và tôi tin rằng câu trả lời là không), SQL Server có triển khai độ chính xác của DECIMAL khác với NUMERIC không. Những gì tiêu chuẩn nói có thể được thực hiện ít liên quan hơn nhiều so với những gì thực sự được thực hiện.
Aaron Bertrand

5
Cảm ơn. Đây là một câu trả lời tuyệt vời cho câu hỏi tiếp theo về lý do tại sao có hai loại với tên khác nhau nhưng hành vi giống hệt nhau.
Gabe
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.