Kịch bản
Ngày xửa ngày xưa, có một cơ sở dữ liệu Staging tại một công ty nhỏ đang tham gia vào quy trình ETL, hoạt động như một danh mục nhận các định dạng khác nhau của các tệp từ một số nguồn của bên thứ ba. E được xử lý thông qua các gói DTS, với một vài cấu trúc điều khiển để kiểm tra hoặc kiểm soát, nhưng được coi là "Đủ tốt" và cho tất cả các ý định và mục đích, nó đã được.
Dữ liệu được cung cấp bởi phần E được dành cho tiêu dùng bởi một ứng dụng đơn lẻ, được phát triển và quản lý bởi một số ít lập trình viên trẻ và có khả năng. Mặc dù thiếu kinh nghiệm hoặc kiến thức về các kỹ thuật lưu trữ dữ liệu thời đó, họ đã đặt ra và tạo ra các quy trình T và L của riêng họ từ mã ứng dụng. Rực rỡ, những kỹ sư phần mềm non trẻ này đã phát minh ra thứ mà người ngoài có thể gọi là "bánh xe kém lý tưởng", nhưng với "Mức độ đủ tốt" như một mức độ dịch vụ hiện tại, họ có thể cung cấp một khung hoạt động.
Trong một thời gian, tất cả đều tốt trong vương quốc kết hợp chặt chẽ, với danh mục Staging đang ăn mừng dữ liệu của hàng tá bên thứ ba, lần lượt được ứng dụng cho ăn. Khi ứng dụng phát triển, sự thèm ăn của nó cũng tăng theo, nhưng với các nhà phát triển hiệp sĩ trắng khéo léo đứng theo dõi hệ thống, những sự thèm ăn này đã được giải quyết nhanh chóng và trong nhiều trường hợp, thậm chí là tốt.
Nhưng thời kỳ hoàng kim không thể kéo dài mãi mãi, dĩ nhiên. Với sự thịnh vượng được cấp bởi ứng dụng thành công, doanh nghiệp ngày càng phát triển. Khi nó phát triển, môi trường và ứng dụng Staging buộc phải phát triển cùng với nó. Đối với tất cả sự cảnh giác của họ, chỉ một số ít các nhà phát triển anh hùng không thể theo kịp việc duy trì hệ thống mở rộng hiện nay và người tiêu dùng đã được hưởng dữ liệu của họ. Không còn là vấn đề họ cần hoặc thậm chí muốn, nhưng dân chúng cảm thấy rằng họ chỉ đơn giản xứng đáng với điều đó, đòi hỏi nhiều hơn nữa.
Được trang bị ít hơn nhiều so với các kho chứa đầy swag, doanh nghiệp đã tiếp cận thị trường, thuê các nhà phát triển và quản trị viên để giúp hỗ trợ hệ thống ngày càng phát triển. Lính đánh thuê của mọi ethos đổ xô đến công ty, nhưng với sự tăng trưởng này đã phát triển rất ít theo cách hướng dẫn chuyên gia có sẵn. Các nhà phát triển và quản trị viên mới đấu tranh để hiểu được sự phức tạp của bộ sản xuất tại nhà, cho đến khi sự thất vọng dẫn đến tất cả chiến tranh. Mỗi bộ phận bắt đầu cố gắng giải quyết mọi vấn đề một mình, làm nhiều việc để chống lại nhau hơn là làm việc với nhau. Một dự án hoặc sáng kiến sẽ được thực hiện theo nhiều cách khác nhau, mỗi cách hơi khác so với kế tiếp. Sự căng thẳng của tất cả đã chứng tỏ là quá nhiều đối với một số hiệp sĩ trắng và khi họ ngã xuống, đế chế sụp đổ. Chẳng mấy chốc, hệ thống đã bị xáo trộn,
Mặc dù đã chuyển đổi các lĩnh vực hứa hẹn thành mã spaghetti đẫm máu, công ty vẫn chịu đựng. Rốt cuộc, đó là "Đủ tốt."
Các thách thức
Một vài thay đổi chế độ và thuê mướn sau đó, tôi thấy mình đang làm việc cho công ty. Đã nhiều năm kể từ các cuộc chiến lớn, nhưng thiệt hại gây ra vẫn rất rõ ràng. Tôi đã quản lý để giải quyết một số điểm yếu trong phần E của hệ thống và thêm một số bảng điều khiển trong khi dưới vỏ bọc nâng cấp các gói DTS lên SSIS, hiện đang được một số chuyên gia lưu trữ dữ liệu thực tế sử dụng khi chúng tạo ra bình thường và ghi lại sự thay thế T và L.
Rào cản đầu tiên là nhập dữ liệu từ các tệp của bên thứ ba theo cách không cắt bớt các giá trị hoặc thay đổi các loại dữ liệu gốc, nhưng cũng bao gồm một số phím điều khiển để tải lại và thanh trừng. Đây là tất cả tốt và tốt, nhưng các ứng dụng cần thiết để có thể truy cập các bảng mới này một cách liền mạch, minh bạch. Gói DTS có thể điền vào bảng, sau đó ứng dụng sẽ đọc trực tiếp. Việc nâng cấp SSIS cần phải được thực hiện song song vì lý do QA, nhưng các gói mới này bao gồm các khóa điều khiển khác nhau và cũng tận dụng sơ đồ phân vùng, chưa kể các thay đổi siêu dữ liệu thực tế có thể đủ để đảm bảo một bảng mới hoàn toàn, vì vậy bảng mới đã được sử dụng cho các gói SSIS mới.
Với việc nhập dữ liệu đáng tin cậy hiện đang hoạt động và được sử dụng bởi nhóm kho, thử thách thực sự là phục vụ dữ liệu mới cho các ứng dụng truy cập trực tiếp vào môi trường Staging, với tác động tối thiểu (còn gọi là "Không") đối với mã ứng dụng. Đối với điều này, tôi đã được bầu vào quan điểm sử dụng, đổi tên một bảng như dbo.DailyTransaction
để dbo.DailyTranscation_LEGACY
và tái sử dụng các dbo.DailyTransaction
tên đối tượng cho một cái nhìn, mà hiệu quả chỉ Selects tất cả mọi thứ từ bây giờLEGACY
bảng chỉ định. Do việc tải lại các năm dữ liệu trong các bảng này không phải là một lựa chọn theo quan điểm của doanh nghiệp, vì các bảng được phân vùng và phân vùng SSIS mới được đưa vào sản xuất, việc nhập DTS cũ bị tắt và các ứng dụng cần phải có khả năng truy cập dữ liệu mới trong các bảng mới là tốt. Tại thời điểm này, các khung nhìn được cập nhật để chọn dữ liệu từ các bảng mới ( dbo.DailyTransactionComplete
ví dụ: chẳng hạn) khi có sẵn và chọn từ các bảng kế thừa khi không có.
Trong thực tế, một cái gì đó như sau đây đang được thực hiện:
CREATE VIEW dbo.DailyTransaction
AS SELECT DailyTransaction_PK, FileDate, Foo
FROM dbo.DailyTransactionComplete
UNION ALL
SELECT DailyTransaction_PK, FileDate, Foo
FROM dbo.DailyTransaction_LEGACY l
WHERE NOT EXISTS ( SELECT 1
FROM dbo.DailyTransactionComplete t
WHERE t.FileDate = l.FileDate );
Mặc dù về mặt logic, điều này hoàn toàn không hoạt động tốt trong một số trường hợp tổng hợp, thường dẫn đến một kế hoạch thực hiện thực hiện quét chỉ mục đầy đủ đối với dữ liệu trong bảng kế thừa. Điều này có thể tốt cho vài chục triệu hồ sơ, nhưng không nhiều cho vài chục trăm triệu hồ sơ. Vì thực tế sau này, tôi đã phải dùng đến ... "sáng tạo", dẫn tôi đến việc tạo ra một cái nhìn được lập chỉ mục.
Đây là trường hợp ít thử nghiệm tôi đã thiết lập, bao gồm các FileDate
phím điều khiển đã được chuyển đến các tương thích Data Warehouse DateCode_FK
cổng cho minh họa cách hoàn toàn chút tôi quan tâm đến các truy vấn đối với các bảng mới là sargable trong thời gian tới:
USE tempdb;
GO
SET NOCOUNT ON;
GO
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'DailyTransaction_LEGACY'
AND type = 'U' )
BEGIN
--DROP TABLE dbo.DailyTransaction_LEGACY;
CREATE TABLE dbo.DailyTransaction_LEGACY
(
DailyTransaction_PK BIGINT IDENTITY( 1, 1 ) NOT NULL,
FileDate DATETIME NOT NULL,
Foo INT NOT NULL
);
INSERT INTO dbo.DailyTransaction_LEGACY ( FileDate, Foo )
SELECT DATEADD( DAY, ( 1 - ROW_NUMBER()
OVER( ORDER BY so1.object_id ) - 800 ) % 1000,
CONVERT( DATE, GETDATE() ) ),
so1.object_id % 1000 + so2.object_id % 1000
FROM sys.all_objects so1
CROSS JOIN sys.all_objects so2;
ALTER TABLE dbo.DailyTransaction_LEGACY
ADD CONSTRAINT PK__DailyTrainsaction
PRIMARY KEY CLUSTERED ( DailyTransaction_PK )
WITH ( DATA_COMPRESSION = PAGE, FILLFACTOR = 100 );
END;
GO
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'DailyTransactionComplete'
AND type = 'U' )
BEGIN
--DROP TABLE dbo.DailyTransactionComplete;
CREATE TABLE dbo.DailyTransactionComplete
(
DailyTransaction_PK BIGINT IDENTITY( 1, 1 ) NOT NULL,
DateCode_FK INTEGER NOT NULL,
Foo INTEGER NOT NULL
);
INSERT INTO dbo.DailyTransactionComplete ( DateCode_FK, Foo )
SELECT TOP 100000
CONVERT( INTEGER, CONVERT( VARCHAR( 8 ), DATEADD( DAY,
( 1 - ROW_NUMBER() OVER( ORDER BY so1.object_id ) ) % 100,
GETDATE() ), 112 ) ),
so1.object_id % 1000
FROM sys.all_objects so1
CROSS JOIN sys.all_objects so2;
ALTER TABLE dbo.DailyTransactionComplete
ADD CONSTRAINT PK__DailyTransaction
PRIMARY KEY CLUSTERED ( DateCode_FK, DailyTransaction_PK )
WITH ( DATA_COMPRESSION = PAGE, FILLFACTOR = 100 );
END;
GO
Trên hộp cát cục bộ của tôi, ở trên giúp tôi có một bảng kế thừa với khoảng 4,4 triệu hàng và một bảng mới chứa 0,1 triệu hàng, với một số giá trị DateCode_FK
/ chồng chéo FileDate
.
Bảng MAX( FileDate )
so với bảng kế thừa không có chỉ mục bổ sung nào chạy về những gì tôi mong đợi.
SET STATISTICS IO, TIME ON;
DECLARE @ConsumeOutput DATETIME;
SELECT @ConsumeOutput = MAX( FileDate )
FROM dbo.DailyTransaction_LEGACY;
SET STATISTICS IO, TIME OFF;
GO
Bảng 'DailyTransaction_LEGACY'. Quét số 1, đọc logic 9228, đọc vật lý 0, đọc trước 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.
Thời gian thực hiện máy chủ SQL: Thời gian CPU = 889 ms, thời gian trôi qua = 886 ms.
Tung một chỉ số đơn giản trên bàn làm cho mọi thứ tốt hơn nhiều. Vẫn là quét, nhưng quét một bản ghi thay vì 4,4 triệu bản ghi. Tôi rất tuyệt với điều đó.
CREATE NONCLUSTERED INDEX IX__DailyTransaction__FileDate
ON dbo.DailyTransaction_LEGACY ( FileDate );
SET STATISTICS IO, TIME ON;
DECLARE @ConsumeOutput DATETIME;
SELECT @ConsumeOutput = MAX( FileDate )
FROM dbo.DailyTransaction_LEGACY;
SET STATISTICS IO, TIME OFF;
GO
Thời gian phân tích và biên dịch SQL Server: Thời gian CPU = 0 ms, thời gian trôi qua = 1 ms. Bảng 'DailyTransaction_LEGACY'. Quét số 1, đọc logic 3, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.
Thời gian thực thi máy chủ SQL: Thời gian CPU = 0 ms, thời gian trôi qua = 0 ms.
Và bây giờ, tạo chế độ xem để các nhà phát triển không phải thay đổi bất kỳ mã nào vì đó rõ ràng sẽ là ngày tận thế như chúng ta biết. Một thảm họa của các loại.
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'DailyTransaction'
AND type = 'V' )
BEGIN
EXEC( 'CREATE VIEW dbo.DailyTransaction AS SELECT x = 1;' );
END;
GO
ALTER VIEW dbo.DailyTransaction
AS SELECT DailyTransaction_PK, FileDate = CONVERT(
DATETIME, CONVERT( VARCHAR( 8 ), DateCode_FK ), 112 ), Foo
FROM dbo.DailyTransactionComplete
UNION ALL
SELECT DailyTransaction_PK, FileDate, Foo
FROM dbo.DailyTransaction_LEGACY l
WHERE NOT EXISTS ( SELECT 1
FROM dbo.DailyTransactionComplete t
WHERE CONVERT( DATETIME, CONVERT( VARCHAR( 8 ),
t.DateCode_FK ), 112 ) = l.FileDate );
GO
Đúng, truy vấn phụ rất tệ, nhưng đây không phải là vấn đề và có lẽ tôi chỉ đơn giản là tạo một cột được tính toán bền bỉ và ném một chỉ mục cho mục đích đó khi vấn đề thực sự được giải quyết. Vì vậy, không có thêm ado,
Vấn đề
SET STATISTICS IO, TIME ON;
DECLARE @ConsumeOutput1 DATETIME;
SELECT @ConsumeOutput1 = MAX( FileDate )
FROM dbo.DailyTransaction;
SET STATISTICS IO, TIME OFF;
GO
Thời gian phân tích và biên dịch SQL Server: Thời gian CPU = 0 ms, thời gian trôi qua = 4 ms. Bảng 'DailyTransaction_LEGACY'. Quét số 1, đọc logic 11972, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc trước 0. Bảng 'Bàn làm việc'. Quét số 0, đọc logic 0, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc trước 0. Bảng 'Workfile'. Quét số 0, đọc logic 0, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý 0, đọc đọc trước 0, đọc bảng "DailyTransactionComplete '. Quét số 2, đọc logic 620, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.
Thời gian thực thi máy chủ SQL: Thời gian CPU = 983 ms, thời gian trôi qua = 983 ms.
Ồ tôi hiểu rồi, Sql Server đang cố nói với tôi rằng những gì tôi đang làm là ngu ngốc. Trong khi tôi phần lớn đồng ý, điều đó không thay đổi tình trạng khó khăn của tôi. Điều này thực sự hoạt động rực rỡ cho các truy vấn nơi FileDate
trên dbo.DailyTransaction
xem được bao gồm trong các vị, nhưng trong khi MAX
kế hoạch là đủ xấu, các TOP
kế hoạch gửi toàn bộ điều chạy về phía nam. Nam thực.
SET STATISTICS IO, TIME ON;
SELECT TOP 10 FileDate
FROM dbo.DailyTransaction
GROUP BY FileDate
ORDER BY FileDate DESC
SET STATISTICS IO, TIME OFF;
GO
Bảng 'DailyTransactionComplete'. Quét số 2, đọc logic 1800110, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc trước 0. Bảng 'DailyTransaction_LEGACY'. Quét số 1, đọc logic 1254, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc trước 0. Bảng 'Worktable'. Quét số 0, đọc logic 0, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc trước 0. Bảng 'Workfile'. Quét số 0, đọc logic 0, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.
Thời gian thực thi của máy chủ SQL: Thời gian CPU = 109559 ms, thời gian đã trôi qua = 109664 ms.
Tôi đã đề cập đến việc "sáng tạo" trước đó, có lẽ là sai lệch. Điều tôi muốn nói là "ngu ngốc hơn", vì vậy những nỗ lực của tôi để làm cho chế độ xem này hoạt động trong các hoạt động tổng hợp là tạo các khung nhìn trên dbo.DailyTransactionComplete
và dbo.DailyTransaction_LEGACY
các bảng, liên kết lược đồ và lập chỉ mục cho khung nhìn sau, sau đó sử dụng các khung nhìn đó trong một khung nhìn khác với một NOEXPAND
gợi ý trên quan điểm di sản. Mặc dù hiện tại nó ít nhiều hoạt động cho những gì nó cần làm, tôi thấy toàn bộ "giải pháp" khá khó chịu, lên đến đỉnh điểm với những điều sau:
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'v_DailyTransactionComplete'
AND type = 'V' )
BEGIN
EXEC( 'CREATE VIEW dbo.v_DailyTransactionComplete AS SELECT x = 1;' );
END;
GO
ALTER VIEW dbo.v_DailyTransactionComplete
AS SELECT DailyTransaction_PK, FileDate = CONVERT( DATETIME,
CONVERT( VARCHAR( 8 ), DateCode_FK ), 112 ),
Foo
FROM dbo.DailyTransactionComplete;
GO
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'v_DailyTransaction_LEGACY'
AND type = 'V' )
BEGIN
EXEC( 'CREATE VIEW dbo.v_DailyTransaction_LEGACY AS SELECT x = 1;' );
END;
GO
ALTER VIEW dbo.v_DailyTransaction_LEGACY
WITH SCHEMABINDING
AS SELECT l.DailyTransaction_PK,
l.FileDate,
l.Foo,
CountBig = COUNT_BIG( * )
FROM dbo.DailyTransaction_LEGACY l
INNER JOIN dbo.DailyTransactionComplete n
ON l.FileDate <> CONVERT( DATETIME, CONVERT( VARCHAR( 8 ),
n.DateCode_FK ), 112 )
GROUP BY l.DailyTransaction_PK,
l.FileDate,
l.Foo;
GO
CREATE UNIQUE CLUSTERED INDEX CI__v_DailyTransaction_LEGACY
ON dbo.v_DailyTransaction_LEGACY ( FileDate, DailyTransaction_PK )
WITH ( DATA_COMPRESSION = PAGE, FILLFACTOR = 80 );
GO
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'DailyTransaction'
AND type = 'V' )
BEGIN
EXEC( 'CREATE VIEW dbo.DailyTransaction AS SELECT x = 1;' );
END;
GO
ALTER VIEW dbo.DailyTransaction
AS SELECT DailyTransaction_PK, FileDate, Foo
FROM dbo.v_DailyTransactionComplete
UNION ALL
SELECT DailyTransaction_PK, FileDate, Foo
FROM dbo.v_DailyTransaction_LEGACY WITH ( NOEXPAND );
GO
Việc buộc trình tối ưu hóa sử dụng chỉ mục được cung cấp bởi chế độ xem được lập chỉ mục sẽ khiến các vấn đề MAX
và TOP
vấn đề biến mất, nhưng phải có một cách tốt hơn để đạt được những gì tôi đang cố gắng thực hiện ở đây. Hoàn toàn bất kỳ đề nghị / la mắng sẽ được rất nhiều đánh giá cao !!
SET STATISTICS IO, TIME ON;
DECLARE @ConsumeOutput1 DATETIME;
SELECT @ConsumeOutput1 = MAX( FileDate )
FROM dbo.DailyTransaction;
SET STATISTICS IO, TIME OFF;
GO
Bảng 'v_DailyTransaction_LEGACY'. Quét số 1, đọc logic 3, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc trước 0. Bảng 'DailyTransactionComplete'. Quét số 1, đọc logic 310, đọc vật lý 0, đọc trước 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.
Thời gian thực thi máy chủ SQL: Thời gian CPU = 31 ms, thời gian trôi qua = 36 ms.
SET STATISTICS IO, TIME ON;
DECLARE @ConsumeOutput1 DATETIME;
SELECT TOP 10 @ConsumeOutput1 = FileDate
FROM dbo.DailyTransaction
GROUP BY FileDate
ORDER BY FileDate DESC
SET STATISTICS IO, TIME OFF;
GO
Bảng 'v_DailyTransaction_LEGACY'. Quét số 1, đọc logic 101, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc trước 0. Bảng 'Worktable'. Quét số 0, đọc logic 0, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc trước 0. Bảng 'Workfile'. Quét số 0, đọc logic 0, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý 0, đọc đọc trước 0, đọc bảng "DailyTransactionComplete '. Quét số 1, đọc logic 310, đọc vật lý 0, đọc trước 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.
Thời gian thực thi máy chủ SQL: Thời gian CPU = 63 ms, thời gian trôi qua = 66 ms.
TL; DR:
Giúp tôi hiểu những gì tôi cần làm để thực hiện các truy vấn tổng hợp trên chế độ xem đầu tiên tôi đã đề cập chạy trong khoảng thời gian hợp lý với việc sử dụng tài nguyên I / O hợp lý.