Là CHỌN * ok trong Kích hoạt. Hay tôi đang yêu cầu rắc rối?


8

Tôi bị cuốn vào một cuộc tranh luận tại nơi làm việc và tôi cần một vài lời khuyên về những Cạm bẫy có thể xảy ra mà tôi có thể nhìn thấy.

Tưởng tượng một kịch bản trong đó Trình kích hoạt được sử dụng để sao chép Bản ghi đã xóa vào Bảng kiểm toán. Kích hoạt sử dụng CHỌN *. Mọi người chỉ và hét lên và cho chúng tôi biết điều này tệ như thế nào.

Tuy nhiên, nếu một sửa đổi được thực hiện cho Cấu trúc của Bảng chính và Bảng kiểm toán bị bỏ qua thì Trình kích hoạt sẽ tạo ra lỗi cho mọi người biết bảng Kiểm toán cũng cần sửa đổi.

Lỗi sẽ được bắt gặp trong quá trình thử nghiệm trên các máy chủ DEV của chúng tôi. Nhưng chúng tôi cần đảm bảo DEV phù hợp với sản xuất, vì vậy chúng tôi cho phép CHỌN * trong Hệ thống sản xuất (chỉ kích hoạt).

Vì vậy, Câu hỏi của tôi là: Tôi đang bị thúc đẩy loại bỏ CHỌN *, nhưng tôi không biết làm cách nào khác để đảm bảo chúng tôi tự động nắm bắt các Lỗi phát triển có tính chất này, có ý tưởng nào hay đây là cách thực hành tốt nhất?

Tôi đã đưa ra một ví dụ dưới đây:

--Create Test Table
CREATE TABLE dbo.Test(ID INT IDENTITY(1,1), Person VARCHAR(255))
--Create Test Audit Table
CREATE TABLE dbo.TestAudit(AuditID INT IDENTITY(1,1),ID INT, Person VARCHAR(255))

--Create Trigger on Test
CREATE TRIGGER [dbo].[trTestDelete] ON [dbo].[Test] AFTER DELETE
NOT FOR REPLICATION
AS
BEGIN
    SET NOCOUNT ON;
    INSERT  dbo.TestAudit([ID], [Person])
    SELECT  *
    FROM    deleted
END

--Insert Test Data into Test
INSERT INTO dbo.Test VALUES
('Scooby')
,('Fred')
,('Shaggy')

--Perform a delete
DELETE dbo.Test WHERE Person = 'Scooby'

CẬP NHẬT (câu hỏi viết lại):

Tôi là một DBA và cần đảm bảo Nhà phát triển không cung cấp các kịch bản Triển khai được suy nghĩ kém bằng cách đóng góp vào Tài liệu Thực hành Tốt nhất của chúng tôi. CHỌN * gây ra lỗi trong DEV khi Nhà phát triển bỏ qua Bảng kiểm toán (đây là mạng an toàn) để lỗi được phát hiện sớm trong quá trình phát triển. Nhưng đâu đó trong Hiến pháp SQL - bản sửa đổi thứ 2 ghi "Bạn sẽ không sử dụng CHỌN *". Vì vậy, bây giờ có một nỗ lực để thoát khỏi Mạng lưới an toàn.

Làm thế nào bạn sẽ thay thế Mạng lưới an toàn, hoặc tôi nên coi đây là cách thực hành tốt nhất cho Triggers?

CẬP NHẬT 2: (giải pháp)

Cảm ơn tất cả các ý kiến ​​đóng góp của bạn, tôi không chắc mình có câu trả lời rõ ràng không vì đây có vẻ là một chủ đề rất Xám. Nhưng gọi chung là bạn đã cung cấp các điểm thảo luận có thể giúp các nhà phát triển của chúng tôi tiến lên phía trước với việc xác định Thực tiễn tốt nhất của họ.

Cảm ơn Daevinsự đóng góp của bạn, câu trả lời của bạn cung cấp nền tảng cho một số cơ chế thử nghiệm mà Nhà phát triển của chúng tôi có thể thực hiện. +1

Cảm ơn CM_Dayton, các đề xuất của bạn góp phần thực hành tốt nhất có thể có lợi cho bất kỳ ai đang làm lệch hướng Kiểm toán kích hoạt. +1

Cảm ơn ypercuberất nhiều, bạn đã đưa ra nhiều suy nghĩ xung quanh các vấn đề liên quan đến các bảng trải qua các hình thức thay đổi định nghĩa khác nhau. +1

Tóm lại là:

Is Select * ok in a tigger? Vâng, đó là một khu vực màu xám, đừng mù quáng tuân theo hệ tư tưởng "Chọn * là xấu".

Am I asking for Trouble? Có, chúng tôi làm nhiều hơn là chỉ thêm các cột mới vào bảng.


bạn tự trả lời trong câu hỏi chọn * sẽ ngắt nếu bảng nguồn bị thay đổi. Để đảm bảo dev và prod giống nhau, hãy sử dụng một số hình thức kiểm soát nguồn.
Bob Klimes

Câu hỏi hơi rộng hơn, tần suất bạn xóa các bản ghi và tổng số phần trăm của bảng là bao nhiêu? một thay thế cho các kích hoạt sẽ là có một cờ bit đánh dấu các hàng là đã xóa và một công việc tác nhân chạy theo lịch trình để di chuyển chúng đến một bảng nhật ký. Bạn có thể xây dựng vào kiểm tra công việc tác nhân để xem lược đồ bảng có khớp hay không và công việc sẽ đơn giản thất bại nếu có vấn đề với bước đó cho đến khi nó được sửa.
Tanner

Tôi thường đồng ý với việc SELECT *lười biếng, nhưng vì bạn có lý do chính đáng để sử dụng nó nên nó có màu xám hơn màu đen và trắng. Những gì bạn nên thử là một cái gì đó như thế này , nhưng điều chỉnh nó để không chỉ có cùng số cột, mà tên cột và kiểu dữ liệu giống nhau (vì ai đó có thể thay đổi loại dữ liệu và vẫn gây ra sự cố trong db không thường bị bắt với SELECT *'mạng lưới an toàn' của bạn .
Daevin

3
Tôi thích ý tưởng sử dụng SELECT *như một mạng lưới an toàn nhưng nó sẽ không bắt được tất cả các trường hợp. Ví dụ: nếu bạn thả một cột và thêm nó một lần nữa. Điều này sẽ thay đổi thứ tự của các cột và (trừ khi tất cả các cột cùng loại), các phần chèn vào bảng kiểm toán sẽ không thành công hoặc dẫn đến mất dữ liệu do chuyển đổi loại ẩn.
ypercubeᵀᴹ

2
Tôi cũng tự hỏi làm thế nào thiết kế kiểm toán của bạn sẽ hoạt động khi một cột được thả từ một bảng. Bạn cũng bỏ cột từ bảng kiểm toán (và mất tất cả dữ liệu kiểm toán trước đó)?
ypercubeᵀᴹ

Câu trả lời:


10

Thông thường, nó được coi là lập trình "lười biếng".

Vì bạn đặc biệt chèn hai giá trị vào TestAuditbảng của mình ở đây, tôi sẽ cẩn thận để đảm bảo rằng lựa chọn của bạn cũng nhận được chính xác hai giá trị. Bởi vì, vì một số lý do, Testbảng đó có hoặc đã từng có cột thứ ba, kích hoạt này sẽ thất bại.

Không liên quan trực tiếp đến câu hỏi của bạn nhưng nếu bạn đang thiết lập bảng kiểm toán, tôi cũng sẽ thêm một số cột bổ sung vào TestAuditbảng của mình để ...

  • theo dõi hành động bạn đang kiểm toán (xóa trong trường hợp này, so với chèn hoặc cập nhật)
  • cột ngày / giờ để theo dõi khi sự kiện kiểm toán xảy ra
  • cột ID người dùng để theo dõi ai đã thực hiện hành động bạn đang kiểm toán.

Vì vậy, kết quả trong một truy vấn như:

INSERT dbo.TestAudit([ID], [Person], [AuditAction], [ChangedOn], [ChangedBy])
SELECT [ID], [Person], 
   'Delete', -- or a 'D' or a numeric lookup to an audit actions table...
   GetDate(), -- or SYSDATETIME() for greater precision
   SYSTEM_USER -- or some other value for WHO made the deletion
FROM deleted

Bằng cách đó, bạn sẽ nhận được các cột chính xác mà bạn cần và bạn đang kiểm tra xem cái gì / khi nào / tại sao / ai là sự kiện kiểm toán.


"ID người dùng" Cái này rất khó kiểm toán. Thông thường, tài khoản cơ sở dữ liệu không tương ứng với người dùng thực tế. Thường xuyên hơn, chúng tương ứng với một ứng dụng web hoặc một loại thành phần khác, với một bộ thông tin xác thực được sử dụng bởi thành phần đó. (Và đôi khi, các thành phần cũng sẽ chia sẻ thông tin đăng nhập.) Vì vậy, thông tin đăng nhập cơ sở dữ liệu khá vô dụng khi là định danh của ai đã làm gì, trừ khi bạn chỉ quan tâm đến thành phần nào đã làm điều đó. Nhưng việc truyền dữ liệu ứng dụng xác định "ai" không thực sự dễ dàng với chức năng kích hoạt, theo như tôi biết.
jpmc26

xem cập nhật cho câu hỏi.
bình tĩnh

Một vấn đề khác có thể xảy ra với CHỌN * nói chung (mặc dù có thể không có trong ví dụ của bạn) là nếu các cột của bảng bên dưới không theo thứ tự như các cột chèn của bạn thì việc chèn sẽ thất bại.
CaM

3

Tôi đã nhận xét điều này về câu hỏi của bạn, nhưng tôi cho rằng tôi đang cố gắng trình bày một giải pháp mã.

Tôi thường đồng ý với SELECT *việc lười biếng, nhưng vì bạn có lý do chính đáng để sử dụng nó nên nó có màu xám hơn màu đen và trắng.

Những gì bạn nên (theo ý kiến ​​của tôi) cố gắng làm là một cái gì đó như thế này , nhưng điều chỉnh nó để đảm bảo tên cột và kiểu dữ liệu giống nhau (vì ai đó có thể thay đổi loại dữ liệu và vẫn gây ra sự cố trong db không được bắt gặp với SELECT *sự an toàn của bạn mạng lưới'.

Bạn thậm chí có thể tạo một chức năng cho phép bạn nhanh chóng kiểm tra xem phiên bản Kiểm toán của bảng có khớp với phiên bản không kiểm toán hay không:

-- The lengths are, I believe, max values for the corresponding db objects. If I'm wrong, someone please correct me
CREATE FUNCTION TableMappingComparer(
    @TableCatalog VARCHAR(85) = NULL,
    @TableSchema VARCHAR(32) = NULL,
    @TableName VARCHAR(128) = NULL) RETURNS BIT
AS
BEGIN
    DECLARE @ReturnValue BIT = NULL;
    DECLARE @VaryingColumns INT = NULL;

    IF (@TableCatalog IS NOT NULL
            AND @TableSchema IS NOT NULL
            AND @TableName IS NOT NULL)
        SELECT @VaryingColumns = COUNT(COLUMN_NAME)
            FROM (SELECT COLUMN_NAME,
                        DATA_TYPE -- Add more columns that you want to ensure are identical
                    FROM INFORMATION_SCHEMA.COLUMNS
                    WHERE TABLE_CATALOG = @TableCatalog
                        AND TABLE_SCHEMA = @TableSchema
                        AND TABLE_NAME = @TableName
                EXCEPT
                    SELECT COLUMN_NAME,
                            DATA_TYPE -- Add more columns that you want to ensure are identical
                        FROM INFORMATION_SCHEMA.COLUMNS
                        WHERE (TABLE_CATALOG = @TableCatalog
                            AND TABLE_SCHEMA = @TableSchema
                            AND TABLE_NAME = @TableName + 'Audit')
                            AND (COLUMN_NAME != 'exclude your audit table specific columns')) adt;
    IF @VaryingColumns = 0
        SET @ReturnValue = 1
    ELSE IF @VaryingColumns > 0
        SET @ReturnValue = 0

    RETURN @ReturnValue;
END;

Các SELECT ... EXCEPT SELECT ...Auditsẽ cho bạn thấy những gì các cột trong bảng không nằm trong bảng kiểm toán. Bạn thậm chí có thể thay đổi hàm để trả về tên của các cột không giống nhau thay vì chỉ là chúng có ánh xạ hay không, hoặc thậm chí đưa ra một ngoại lệ.

Sau đó bạn có thể chạy này trước khi chuyển từ DEVtới PRODUCTIONmáy chủ cho mỗi bảng trong db, sử dụng một con trỏ trên:

SELECT TABLE_NAME
    FROM INFORMATION_SCHEMA.TABLES
    WHERE NOT (TABLE_NAME LIKE '%Audit')

1
xem cập nhật cho câu hỏi
tạm thời

Rất vui vì tôi có thể giúp. Tín dụng cho bạn để đọc tất cả các câu trả lời và đưa chúng trở lại nhóm của bạn để được gợi ý; khả năng thích ứng và sẵn sàng cải thiện là cách các bộ phận công nghệ giữ cho các công ty hoạt động và hoạt động trơn tru! : D
Daevin

0

Câu lệnh sẽ kích hoạt trình kích hoạt sẽ thất bại và trình kích hoạt sẽ thất bại. Sẽ tốt hơn nếu ghi lại dấu vết kích hoạt và kiểm toán để bạn biết sửa đổi truy vấn để thêm các cột thay vì chỉ định *.

Ít nhất bạn nên sửa đổi trình kích hoạt để nó có thể thất bại trong khi ghi lỗi vào bảng và có thể đặt cảnh báo trên bảng mà trình kích hoạt đang ghi lại lỗi.

Điều này cũng cho thấy, bạn có thể đặt một kích hoạt hoặc cảnh báo khi ai đó thay đổi bảng và thêm nhiều cột hoặc xóa các cột, để thông báo cho bạn để thêm kích hoạt.

Hiệu suất khôn ngoan Tôi tin rằng * không thay đổi bất cứ điều gì, nó chỉ làm tăng khả năng thất bại khi mọi thứ thay đổi và cũng có thể gây ra độ trễ mạng khi bạn lấy thêm thông tin qua mạng khi bạn cần. Có một thời gian và địa điểm cho *, nhưng tôi cảm thấy như được mô tả ở trên, bạn có các giải pháp và công cụ tốt hơn để thử thay thế.


0

Nếu cấu trúc bảng gốc hoặc bảng kiểm toán của bạn thay đổi hoàn toàn, bạn đảm bảo rằng bạn sẽ gặp vấn đề với lựa chọn * của mình.

INSERT INTO [AuditTable]
(Col1,Col2,Col3)
SELECT * 
FROM [OrigTable] or [deleted];

Nếu một trong hai thay đổi, kích hoạt sẽ lỗi.

Bạn có thể làm:

INSERT INTO [AuditTable]
SELECT * 
FROM [OrigTable];

Nhưng như CM_Dayton nói, đó là lập trình lười biếng và mở ra cơ hội cho những mâu thuẫn khác. Để kịch bản này hoạt động, bạn phải chắc chắn rằng bạn đang cập nhật cấu trúc của cả hai bảng cùng một lúc.

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.