Cách nhanh nhất để thanh lọc dữ liệu là gì?


18

Kịch bản:

Chúng tôi có hai bảng Tbl1& Tbl2trên Máy chủ thuê bao. Điều Tbl1này đang được nhân rộng từ Nhà xuất bảnServer A và nó có hai kích hoạt - chèn và cập nhật. Các kích hoạt đang chèn và cập nhật dữ liệu vào Tbl2.

Bây giờ, chúng tôi phải thanh lọc (khoảng 900 triệu bản ghi) từ Tbl2đó có tổng số hơn 1000 triệu bản ghi. Dưới đây là phân phối dữ liệu trong một tháng đến một phút.

  • Một tháng - 14986826 hàng
  • Một ngày - 483446 hàng
  • Một giờ - 20143 hàng
  • Một phút - 335 hàng

Những gì tôi đang tìm kiếm;

Cách nhanh nhất để thanh lọc dữ liệu mà không có bất kỳ vấn đề sản xuất, tính nhất quán dữ liệu và có thể không có thời gian chết. Vì vậy, tôi đang suy nghĩ để làm theo các bước dưới đây nhưng bị mắc kẹt :(

Các bước:

  1. BCP Ra dữ liệu cần thiết từ bảng Tbl2 hiện có (khoảng 100 triệu bản ghi, có thể mất khoảng 30 phút).
    • Giả sử tôi bắt đầu thực hiện hoạt động vào 1Fab2018 10:00 PM, nó kết thúc lúc 1Fab2018 10:30 PM. Đến khi hoạt động được hoàn thành, bảng Tbl2 sẽ nhận được các bản ghi mới trở thành delta
  2. Tạo một bảng mới trong cơ sở dữ liệu với tên Tbl3
  3. BCP trong dữ liệu đã xuất vào bảng Tbl3 mới được tạo (khoảng 100 triệu bản ghi, có thể mất khoảng 30 phút)
  4. Dừng công việc nhân rộng
  5. Khi BCP-in hoàn tất, hãy sử dụng tập lệnh tsql để chèn dữ liệu delta mới.

  6. Thách thức là - Làm thế nào để đối phó với tuyên bố cập nhật delta delta?

  7. Bắt đầu nhân rộng

Câu hỏi bổ sung:

Cách tốt nhất để đối phó với kịch bản là gì?

Câu trả lời:


26

Vì bạn đang xóa 90% các hàng, tôi khuyên bạn nên sao chép các hàng bạn cần giữ vào một bảng mới có cùng cấu trúc, sau đó sử dụng ALTER TABLE ... SWITCHđể thay thế bảng hiện có bằng bảng mới, sau đó chỉ cần bỏ bảng cũ. Xem trang Microsoft Docs này để biết cú pháp.

Một giường thử nghiệm đơn giản, không có bản sao cho thấy nguyên tắc chung:

Trước tiên, chúng tôi sẽ tạo cơ sở dữ liệu cho thử nghiệm của chúng tôi:

USE master;
IF (SELECT 1 FROM sys.databases d WHERE d.name = 'SwitchTest') IS NOT NULL
BEGIN
    ALTER DATABASE SwitchTest SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    DROP DATABASE SwitchTest;
END
CREATE DATABASE SwitchTest;
ALTER DATABASE SwitchTest SET RECOVERY FULL;
BACKUP DATABASE SwitchTest TO DISK = 'NUL:';
GO

Ở đây, chúng tôi tạo một vài bảng, với một bộ kích hoạt để di chuyển các hàng từ bảng "A" sang "B", gần đúng với thiết lập của bạn.

USE SwitchTest;
GO
CREATE TABLE dbo.A
(
    i int NOT NULL 
        CONSTRAINT PK_A
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , d varchar(300) NOT NULL
    , rowdate datetime NOT NULL
) ON [PRIMARY]
WITH (DATA_COMPRESSION = PAGE);

CREATE TABLE dbo.B
(
    i int NOT NULL 
        CONSTRAINT PK_B
        PRIMARY KEY CLUSTERED
    , d varchar(300) NOT NULL
    , rowdate datetime NOT NULL
) ON [PRIMARY]
WITH (DATA_COMPRESSION = PAGE);

GO
CREATE TRIGGER t_a
ON dbo.A
AFTER INSERT, UPDATE
AS
BEGIN
    SET NOCOUNT ON;
    DELETE
    FROM dbo.B
    FROM dbo.B b
        INNER JOIN deleted d ON b.i = d.i
    INSERT INTO dbo.B (i, d, rowdate)
    SELECT i.i
        , i.d
        , i.rowdate
    FROM inserted i;
END
GO

Ở đây, chúng tôi chèn 1.000.000 hàng vào "A" và vì kích hoạt, những hàng đó cũng sẽ được chèn vào "B".

;WITH src AS (
    SELECT i.n
    FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9))i(n)
)
INSERT INTO dbo.A (d, rowdate)
SELECT d = CRYPT_GEN_RANDOM(300), DATEADD(SECOND, s6.n + (s5.n * 100000) + (s4.n * 10000) + (s3.n * 1000) + (s2.n * 100) + (s1.n * 10), '2017-01-01T00:00:00.000')
FROM src s1
    CROSS JOIN src s2
    CROSS JOIN src s3
    CROSS JOIN src s4
    CROSS JOIN src s5
    CROSS JOIN src s6;

Xóa nhật ký giao dịch, để tránh hết phòng. KHÔNG CHẠY cái này trong sản xuất vì nó sẽ gửi dữ liệu nhật ký giao dịch đến thiết bị "NUL".

BACKUP LOG SwitchTest TO DISK = 'NUL:';
GO

Mã này tạo ra một giao dịch để đảm bảo không có bảng nào bị ảnh hưởng có thể được ghi trong khi chúng tôi đang di chuyển các hàng:

BEGIN TRANSACTION
EXEC sys.sp_getapplock @Resource = N'TableSwitcher', @LockMode = 'Exclusive', @LockOwner = 'Transaction', @LockTimeout = '1000', @DbPrincipal = N'dbo';
BEGIN TRY
    -- create a table to hold the rows we want to keep
    CREATE TABLE dbo.C
    (
        i int NOT NULL 
            CONSTRAINT PK_C
            PRIMARY KEY CLUSTERED
        , d varchar(300) NOT NULL
        , rowdate datetime NOT NULL
    ) ON [PRIMARY]
    WITH (DATA_COMPRESSION = PAGE);

    --copy the rows we want to keep into "C"
    INSERT INTO dbo.C (i, d, rowdate)
    SELECT b.i
        , b.d
        , b.rowdate
    FROM dbo.B
    WHERE b.rowdate >= '2017-01-11T10:00:00';

    --truncate the entire "B" table
    TRUNCATE TABLE dbo.B;

    --"switch" table "C" into "B"
    ALTER TABLE dbo.C SWITCH TO dbo.B;

    --drop table "C", since we no longer need it
    DROP TABLE dbo.C;

    --shows the count of rows in "B" which were retained.
    SELECT COUNT(1)
    FROM dbo.B
    WHERE b.rowdate >= '2017-01-11T10:00:00';

   --look for rows in "B" that should no longer exist.
    SELECT COUNT(1)
    FROM dbo.B
    WHERE b.rowdate < '2017-01-11T10:00:00';

    --release the applock and commit the transaction
    EXEC sys.sp_releaseapplock @Resource = N'TableSwitcher', @LockOwner = 'Transaction', @DbPrincipal = N'dbo';
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    DECLARE @message nvarchar(1000) = ERROR_MESSAGE();
    DECLARE @severity int = ERROR_SEVERITY();
    DECLARE @state int = ERROR_STATE();
    RAISERROR (@message, @severity, @state);
    EXEC sys.sp_releaseapplock @Resource = N'TableSwitcher', @LockOwner = 'Transaction', @DbPrincipal = N'dbo';
    ROLLBACK TRANSACTION;
END CATCH
GO

Các sp_getapplocksp_releaseapplockngăn chặn nhiều trường hợp của mã này chạy cùng một lúc. Điều này sẽ hữu ích nếu bạn cho phép mã này được sử dụng lại thông qua GUI.

(Lưu ý rằng khóa ứng dụng chỉ hiệu quả nếu mọi quá trình truy cập vào tài nguyên cụ tương tự của nhãn hiệu tài nguyên khóa luận một cách rõ ràng - không có kỳ diệu mà "khóa" các bảng trong cùng một cách mà SQL Server sẽ tự động khóa hàng, các trang, vv trong một thao tác chèn / cập nhật.)

Bây giờ, chúng tôi kiểm tra quá trình chèn các hàng vào "A", để đảm bảo chúng được chèn vào "B" bằng trình kích hoạt.

INSERT INTO dbo.A (d, rowdate)
VALUES ('testRow', GETDATE());

SELECT *
FROM dbo.B
WHERE B.d = 'testRow'
+ --------- + --------- + ------------------------- +
| tôi | d | chèo thuyền |
+ --------- + --------- + ------------------------- +
| 1000001 | kiểm tra | 2018-04-13 03: 49: 53.343 |
+ --------- + --------- + ------------------------- +
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.