Tôi có một bảng dữ liệu SQL với cấu trúc sau:
CREATE TABLE Data(
Id uniqueidentifier NOT NULL,
Date datetime NOT NULL,
Value decimal(20, 10) NULL,
RV timestamp NOT NULL,
CONSTRAINT PK_Data PRIMARY KEY CLUSTERED (Id, Date)
)
Số lượng Id khác nhau dao động từ 3000 đến 50000.
Kích thước của bảng thay đổi lên đến hơn một tỷ hàng.
Một Id có thể nằm giữa một vài hàng lên tới 5% của bảng.
Truy vấn được thực hiện nhiều nhất trên bảng này là:
SELECT Id, Date, Value, RV
FROM Data
WHERE Id = @Id
AND Date Between @StartDate AND @StopDate
Bây giờ tôi phải thực hiện truy xuất dữ liệu gia tăng trên một tập hợp con của Id, bao gồm các bản cập nhật.
Sau đó, tôi đã sử dụng một sơ đồ yêu cầu trong đó người gọi cung cấp một chuyển đổi hàng cụ thể, truy xuất một khối dữ liệu và sử dụng giá trị chuyển đổi tối đa của dữ liệu được trả về cho cuộc gọi tiếp theo.
Tôi đã viết thủ tục này:
CREATE TYPE guid_list_tbltype AS TABLE (Id uniqueidentifier not null primary key)
CREATE PROCEDURE GetData
@Ids guid_list_tbltype READONLY,
@Cursor rowversion,
@MaxRows int
AS
BEGIN
SELECT A.*
FROM (
SELECT
Data.Id,
Date,
Value,
RV,
ROW_NUMBER() OVER (ORDER BY RV) AS RN
FROM Data
inner join (SELECT Id FROM @Ids) Ids ON Ids.Id = Data.Id
WHERE RV > @Cursor
) A
WHERE RN <= @MaxRows
END
Trường hợp @MaxRows
sẽ nằm trong khoảng từ 500.000 đến 2.000.000 tùy thuộc vào mức độ khách hàng sẽ muốn dữ liệu của mình.
Tôi đã thử các cách tiếp cận khác nhau:
- Lập chỉ mục trên (Id, RV):
CREATE NONCLUSTERED INDEX IDX_IDRV ON Data(Id, RV) INCLUDE(Date, Value);
Sử dụng các chỉ số, truy vấn tìm kiếm các hàng nơi RV = @Cursor
cho mỗi Id
trong @Ids
, đọc các hàng sau sau đó hợp nhất kết quả và phân loại.
Hiệu quả sau đó phụ thuộc vào vị trí tương đối của @Cursor
giá trị.
Nếu nó ở gần cuối dữ liệu (được sắp xếp bởi RV) thì truy vấn là tức thời và nếu không truy vấn có thể mất đến vài phút (không bao giờ để nó chạy đến cuối).
vấn đề với cách tiếp cận này @Cursor
là ở gần cuối dữ liệu và việc sắp xếp không gây đau đớn (thậm chí không cần thiết nếu truy vấn trả về ít hàng hơn @MaxRows
) hoặc là phía sau và truy vấn phải sắp xếp @MaxRows * LEN(@Ids)
các hàng.
- Lập chỉ mục trên RV:
CREATE NONCLUSTERED INDEX IDX_RV ON Data(RV) INCLUDE(Id, Date, Value);
Sử dụng chỉ mục, truy vấn tìm kiếm hàng trong RV = @Cursor
đó sau đó đọc mọi hàng loại bỏ Id không được yêu cầu cho đến khi đạt được @MaxRows
.
Hiệu quả sau đó phụ thuộc vào% Id được yêu cầu ( LEN(@Ids) / COUNT(DISTINCT Id)
) và phân phối của chúng.
Id được yêu cầu nhiều hơn có nghĩa là các hàng bị loại bỏ ít hơn có nghĩa là các lần đọc hiệu quả hơn, Id được yêu cầu ít hơn có nghĩa là các hàng bị loại bỏ nhiều hơn có nghĩa là nhiều lượt đọc hơn cho cùng một lượng hàng kết quả.
Vấn đề với cách tiếp cận này là nếu Id được yêu cầu chỉ chứa một vài thành phần, thì có thể phải đọc toàn bộ chỉ mục để có được các hàng mong muốn.
- Sử dụng chỉ mục được lọc hoặc chế độ xem được lập chỉ mục
CREATE NONCLUSTERED INDEX IDX_RVClient1 ON Data(Id, RV) INCLUDE(Date, Value)
WHERE Id IN (/* list of Ids for specific client*/);
Hoặc là
CREATE VIEW vDataClient1 WITH SCHEMABINDING
AS
SELECT
Id,
Date,
Value,
RV
FROM dbo.Data
WHERE Id IN (/* list of Ids for specific client*/)
CREATE UNIQUE CLUSTERED INDEX IDX_IDRV ON vDataClient1(Id, Rv);
Phương pháp này cho phép lập kế hoạch thực hiện truy vấn và lập chỉ mục hiệu quả hoàn hảo nhưng có nhược điểm: 1. Thực tế, tôi sẽ phải triển khai SQL động để tạo chỉ mục hoặc dạng xem và sửa đổi quy trình yêu cầu để sử dụng chỉ mục hoặc dạng xem đúng. 2. Tôi sẽ phải duy trì một chỉ mục hoặc chế độ xem của khách hàng hiện tại, bao gồm cả lưu trữ. 3. Mỗi khi khách hàng phải sửa đổi danh sách Id được yêu cầu của mình, tôi sẽ phải bỏ chỉ mục hoặc xem và tạo lại nó.
Tôi dường như không thể tìm thấy một phương pháp phù hợp với nhu cầu của mình.
Tôi đang tìm kiếm ý tưởng tốt hơn để thực hiện truy xuất dữ liệu gia tăng. Những ý tưởng đó có thể ngụ ý làm lại lược đồ yêu cầu hoặc lược đồ cơ sở dữ liệu mặc dù tôi thích cách tiếp cận lập chỉ mục tốt hơn nếu có.
Value
cột. @crokusek: Không đặt hàng bằng RV, ID thay vì RV chỉ tăng khối lượng công việc sắp xếp mà không có bất kỳ lợi ích nào, tôi không hiểu lý do đằng sau nhận xét của bạn. Từ những gì tôi đã đọc, RV phải là duy nhất trừ khi chèn dữ liệu cụ thể vào cột đó, ứng dụng không có.