Cách tốt nhất để tổng hợp, lưu trữ và sử dụng dữ liệu trong SQL Server (kích hoạt, công việc theo lịch trình, SSAS?)


7

Chúng tôi có một bảng với dữ liệu không gian và một số thuộc tính và cần tổng hợp nó để có thể sử dụng nó trong các truy vấn khác nhau. Chúng tôi có cơ chế thực hiện tổng hợp nhanh chóng thông qua các thủ tục được lưu trữ CLR nhưng tôi đã tự hỏi đâu là cách tốt nhất để lưu trữ dữ liệu tổng hợp này trong SQL Server 2008 R2 vì việc tổng hợp rất chậm.

Vì vậy, chúng tôi có bảng như thế này:

[TableId] [int] NOT NULL,
[FeatureId] [int] NOT NULL,
[MeasureFrom] [float] NOT NULL,
[MeasureTo] [float] NOT NULL,
[Value] [smallint] NOT NULL,
[Timestamp] [datetime2](7) NOT NULL

FeatureId, ĐoFrom và Đo lường Về cơ bản xác định một khoảng và Xếp hạng là giá trị của khoảng này. Lưu ý rằng FeatureId thực sự tham chiếu một dòng thực (hình dạng) từ một bảng khác. Hiện tại chúng tôi có khoảng 250 nghìn hàng trong bảng này với các khoảng thời gian chồng chéo và dấu thời gian khác nhau (hồ sơ lịch sử). Quá trình tổng hợp của chúng tôi cố gắng tìm Giá trị mới nhất trong tất cả các khoảng thời gian để nó cần cắt và nối các khoảng dựa trên dấu thời gian và giữ giá trị liên quan.

Vì truy vấn nhanh đang chậm và chiếm nhiều tài nguyên, chúng tôi nghĩ rằng chúng tôi có thể cần phải tạo một cơ sở dữ liệu khác lưu trữ kết quả của tổng hợp này. Bảng nguồn được cập nhật liên tục (nhưng không quá thường xuyên, một lần trong một vài ngày).

Điều gì sẽ là cách tốt nhất để tạo cơ sở dữ liệu này và giữ cho các giá trị tổng hợp được cập nhật? Tôi có thể nghĩ về việc sử dụng kích hoạt, hoặc nhiệm vụ theo lịch trình. Tôi không có kinh nghiệm với SSAS nhưng điều đó có phù hợp hơn không?

Chỉ cần lưu ý, chúng tôi có một vài bảng tương tự lưu trữ các giá trị hơi khác nhau (một số có nhiều cột Giá trị) và do đó là lý do cho một cơ sở dữ liệu riêng biệt thay vì một bảng khác trong cơ sở dữ liệu gốc.

Làm thế nào nhanh chóng việc truy vấn cơ sở dữ liệu riêng biệt này từ cơ sở dữ liệu ban đầu bằng cách sử dụng tham gia cơ sở dữ liệu chéo?

Đã chỉnh sửa: Để chứng minh "tập hợp" của chúng tôi làm gì, đây là một số dữ liệu mẫu:

FeatureId | MeasureFrom | MeasureTo | Value | Timestamp
1         | 1           | 20        | 2     | 2015-01-01
1         | 5           | 15        | 3     | 2015-01-02
1         | 9           | 10        | 8     | 2015-01-03

Và kết quả chúng ta đang nhận được:

FeatureId | MeasureFrom | MeasureTo | Value | Timestamp
1         | 1           | 5         | 2     | 2015-01-01
1         | 5           | 9         | 3     | 2015-01-02
1         | 9           | 10        | 8     | 2015-01-03
1         | 10          | 15        | 3     | 2015-01-02
1         | 15          | 20        | 2     | 2015-01-01

Như bạn có thể thấy, kết quả thực sự chứa nhiều hàng hơn dữ liệu gốc. Về cơ bản chúng ta cần Giá trị mới nhất tại bất kỳ điểm nào trong khu vực. Giá trị mới nhất được xác định dựa trên giá trị trong cột Dấu thời gian. Khi có một khoảng cách trong các khoảng, điều này sẽ lan truyền đến tập dữ liệu kết quả.

Mã này thực sự được viết bằng .NET và nó khá phức tạp. Thuật toán như sau: Nhận tất cả dữ liệu cho một tính năng quan tâm, sắp xếp các bản ghi theo dấu thời gian giảm dần, xử lý tất cả các bản ghi trong một vòng lặp. Lấy khoảng thời gian (Số đo từ, Số đo), cắt nó với kết quả mà bạn có, nếu bạn nhận được một phần mà bạn chưa có, hãy thêm nó vào kết quả. Tiếp tục với bản ghi tiếp theo. Dữ liệu đại diện cho các cuộc khảo sát được thực hiện thường xuyên để bạn càng đi đúng giờ, càng nhiều dữ liệu sẽ bị loại bỏ vì bạn sẽ có Giá trị mới hơn cho cùng một Khoảng thời gian.

Các cuộc khảo sát được đưa ra với Dấu thời gian ngẫu nhiên, vì vậy không phải lúc nào nó cũng là cuộc khảo sát mới nhất. Quá trình tương tự sau đó được lặp lại cho các tính năng khác vì bạn có thể quan tâm đến việc nhận giá trị cho một vài tính năng cùng một lúc. Và đây là kết quả mọi người sẽ truy vấn thường xuyên.

Lý tưởng nhất là chúng tôi muốn giữ kết quả tổng hợp càng gần với thời gian thực càng tốt.

Để giải thích thuật toán cần thiết hơn một chút, hãy xem liên kết được đăng bởi @dnoeth (trong phần bình luận bên dưới) http://sqlmag.com/sql-server/packing-inter đạn-p Warriorities . Nó giải quyết vấn đề tương tự với sự khác biệt của việc sử dụng các ưu tiên thay vì Dấu thời gian và giải pháp được mô tả sử dụng các tính năng từ SQL Server 2012.


2
một lần trong một vài ngày không được cập nhật liên tục :-) Có vẻ là một bản cập nhật hàng loạt, vì vậy tạo dữ liệu được tính toán trước là bước cuối cùng của đợt nên là cách tốt nhất. Btw, đó là một vấn đề tương tự như sqlmag.com/sql-server/packing-interinating-p Warriorities , nhưng giải pháp của Itzik phụ thuộc vào các tính năng không tồn tại trong SS2008 ...
vào

Là thứ tự quan trọng và tại sao? Bạn có khớp khoảng thời gian bị thiếu chỉ với các giá trị trước hoặc sau hoặc một trong hai giá trị đó không?
Julien Vavasseur

Vâng, thứ tự là quan trọng. Chúng tôi cần nhận được giá trị mới nhất dựa trên Dấu thời gian như được mô tả trong câu hỏi của tôi. Nếu có một khoảng cách (khoảng thiếu) thì khoảng cách đó cũng sẽ xuất hiện.
jandic

khoảng cách và khoảng thiếu là không có trong câu hỏi và tôi đã không tính đến nó. Có lẽ bạn có thể chỉnh sửa câu hỏi với yêu cầu mới này và thêm mẫu và đầu ra với một khoảng cách
Julien Vavasseur

@dnoeth: cảm ơn vì liên kết, điều này rất giống với giải pháp tôi đã viết bằng .NET ngoài việc có dấu thời gian thay vì các ưu tiên khiến mọi thứ trở nên phức tạp hơn
jandic

Câu trả lời:


3

Bảng tổng hợp có thể có thể ở cùng một DB. Tuy nhiên, bạn có thể tạo nó trên một nhóm và đĩa riêng biệt.

Cập nhật đầy đủ bảng tổng hợp mới

Một cách để làm điều đó bằng cách sử dụng SQL thuần túy và mẫu của bạn:

WITH list ([Type], [FeatureId], [Measure], [Value], [Timestamp], [ID]) as (
    SELECT *
        , ROW_NUMBER() OVER(PARTITION BY [FeatureId] ORDER BY [Measure]) 
    FROM (
        SELECT 0, [FeatureId], [MeasureFrom], [Value], [Timestamp] FROM data
        UNION ALL
        SELECT 1, [FeatureId], [MeasureTo], [Value], [Timestamp] FROM data
    ) l([Type], [FeatureId], [Measure], [Value], [Timestamp])
)
SELECT l1.FeatureId, [MeasureFrom] = l1.Measure, [MeasureTo] = l2.Measure
    , [Value] = CASE WHEN l1.Type = 0 THEN l1.Value ELSE l2.Value END
    , [Timestamp] = CASE WHEN l1.Type = 0 THEN l1.Timestamp ELSE l2.Timestamp END
FROM list l1
INNER JOIN list l2 ON l1.FeatureId = l2.FeatureId AND l1.ID+1 = l2.ID
;

Với mẫu thực sự nhỏ này, tôi không chắc nó đáp ứng tất cả các nhu cầu của bạn. Nó có thể giúp thêm một mẫu lớn hơn với nhiều dữ liệu hơn.

Nó quét 4 bảng. Vì bạn có 250k hàng, nó có thể không hoạt động tốt như vậy. Có thể tốt hơn để chạy nó trong lô X FeatureIds liên tiếp.

Điều này có thể được thực hiện bằng cách sử dụng một công việc và gói SSIS với một bản cập nhật đơn lẻ hoặc cập nhật hàng loạt. Bạn sẽ phải cắt bớt bảng tổng hợp trước.

Kích hoạt trên mỗi hàng mới trong bảng chính

Đối với các hàng mới, sử dụng kích hoạt, truy vấn này có thể được sử dụng:

WITH new([FeatureId], [MeasureFrom], [MeasureTo], [Value], [Timestamp]) as (
--    SELECT 1, 1, 20, 2, '2015-01-01'
--  SELECT 1, 5, 15, 3, '2015-01-02'
    SELECT 1, 9, 10, 8, '2015-01-03'
), gap([FeatureId], mn, mx) as (
    SELECT n.[FeatureId], mn.mn, mx.mx
    FROM new n
    CROSS APPLY (SELECT mn = MAX([MeasureFrom]) FROM data3 WHERE [FeatureId] = n.[FeatureId] AND [MeasureFrom] < n.MeasureFrom) mn
    CROSS APPLY (SELECT mx = MIN([MeasureTo]) FROM data3 WHERE [FeatureId] = n.[FeatureId] AND [MeasureTo] > n.MeasureTo) mx
), list (x,[FeatureId], [Measure], [Value], [Timestamp], [ID]) as (
    SELECT *
        , ROW_NUMBER() OVER(PARTITION BY [FeatureId] ORDER BY [Measure]) 
    FROM (
        SELECT 0, d.[FeatureId], d.[MeasureFrom], d.[Value], d.[Timestamp] 
        FROM data3 d
        INNER JOIN gap g ON d.[FeatureId] = g.[FeatureId] AND (d.MeasureFrom >= g.mn AND d.MeasureFrom < g.mx)
        UNION ALL
        SELECT 1, d.[FeatureId], d.[MeasureTo], d.[Value], d.[Timestamp] 
        FROM data3 d
        INNER JOIN gap g ON d.[FeatureId] = g.[FeatureId] AND d.MeasureTo = g.mx
        UNION ALL
        SELECT 2, [FeatureId], [MeasureFrom], [Value], [Timestamp] FROM new
        UNION ALL
        SELECT 3, [FeatureId], [MeasureTo], [Value], [Timestamp] FROM new
    ) l(x, [FeatureId], [Measure], [Value], [Timestamp])
) 
MERGE data3 AS target
USING (
    SELECT l1.FeatureId, [MeasureFrom] = l1.Measure, [MeasureTo] = l2.Measure
        , [Value] = COALESCE(d.[Value], l1.[Value])
        , [Timestamp] = COALESCE(d.[Timestamp], l1.[Timestamp])
    FROM list l1
    INNER JOIN list l2 ON l1.FeatureId = l2.FeatureId AND l1.ID+1 = l2.ID
    LEFT JOIN data3 d ON d.MeasureFrom = l1.Measure OR d.MeasureTo = l2.Measure
) as source(FeatureId, [MeasureFrom], [MeasureTo], [Value], [Timestamp])
ON (target.FeatureId = source.FeatureId AND target.[MeasureFrom] = source.[MeasureFrom])
WHEN MATCHED THEN
    UPDATE SET target.[MeasureTo] = source.[MeasureTo]
WHEN NOT MATCHED BY target THEN
    INSERT (FeatureId, [MeasureFrom], [MeasureTo], [Value], [Timestamp])
    VALUES (source.FeatureId, source.[MeasureFrom], source.[MeasureTo], source.[Value], source.[Timestamp])
;

Bạn phải thay thế CTE mới bằng các giá trị của hàng được chèn mới trong trình kích hoạt và sử dụng nó để hợp nhất với bảng tổng hợp.

Cập nhật theo lịch trình của các hàng mới được thêm vào

Nếu bạn có thể tìm cách đưa danh sách tất cả các hàng mới được thêm vào bảng chính kể từ lần cập nhật cuối cùng của bảng tổng hợp, bạn có thể lên lịch công việc mỗi x phút hoặc giờ và chỉ cập nhật những gì cần thiết dựa trên những gì gần đây thêm.

Truy vấn kích hoạt sẽ hoạt động tốt với các cập nhật theo lịch trình.

Điều này có thể được chạy như một công việc được lên lịch và trong gói SSIS.


Tóm tắt tốt về các tùy chọn nhưng bản trình diễn không phản ánh cột Dấu thời gian nên kết quả không chứa các giá trị mới nhất
jandic

bạn có thể thêm một mẫu lớn hơn và đầu ra? với mẫu nhỏ này nó hoạt động tốt. Dù sao tôi cũng thay đổi một vài thứ vì tôi tìm thấy một vấn đề nhỏ
Julien Vavasseur

1

Đọc / tham gia từ nhiều cơ sở dữ liệu dường như không thể nhanh hơn việc để dữ liệu trong một bảng trong cơ sở dữ liệu chính, trừ khi cơ sở dữ liệu thứ hai nằm trên một đĩa vật lý riêng biệt. Hãy nhớ rằng hầu hết thời gian "chi phí" là trong đĩa IO; Vì vậy, để tăng tốc mọi thứ trong trường hợp này, bạn nên tìm cách giảm hoặc phân phối IO đĩa. Tạo các chỉ mục, phân vùng các bảng thành các đĩa khác nhau hoặc di chuyển bảng tổng hợp của bạn sang một đĩa khác hoặc cơ sở dữ liệu khác sẽ thực hiện việc này.

Có vẻ như bạn đang nghiêng về việc di chuyển hoặc lưu trữ mọi thứ theo lịch trình; SSAS có thể thực hiện được điều này (tôi không biết) nhưng có thể khó tìm được ai đó giỏi về SSAS. Mặt khác, bạn có thể dễ dàng lên lịch công việc thông qua SSIS (đây có thể là ý bạn; SSAS là Dịch vụ phân tích và hoạt động với các hình khối; SSIS là Dịch vụ tích hợp và nhiều hơn để chuyển đổi và di chuyển dữ liệu giữa các nguồn, ví dụ như bảng trích xuất hoặc xem nội dung vào tệp CSV hoặc Excel.)


tốt, đối với một nhiệm vụ theo lịch trình, tôi đã nghĩ đến việc sử dụng SSIS hoặc tương tự nhưng tôi đã tự hỏi liệu SSAS sẽ không phù hợp hơn. Chúng tôi muốn tránh sử dụng các kích hoạt vì điều đó sẽ làm chậm quá trình tải dữ liệu (vì quá trình "tổng hợp" mất một thời gian) và một tác vụ theo lịch trình sẽ đưa ra một số độ trễ giữa khi dữ liệu được tải và sau đó dữ liệu "tổng hợp" có sẵn. Tôi chưa bao giờ sử dụng SSAS Tôi đang hỏi ý kiến ​​của ai đó biết nó. Lý tưởng nhất là chúng tôi muốn giữ kết quả tổng hợp càng gần với thời gian thực càng tốt.
jandic
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.