Tăng tốc Count (*) trên các bảng lớn


8

Chúng tôi đang sử dụng Ứng dụng nhà cung cấp chạy trên SQL Server Enterprise và ứng dụng này khá khó chịu khi thực hiện các COUNTbáo cáo trên bảng Mục trong khi xử lý hầu hết các tài liệu tài chính (đơn đặt hàng, hóa đơn, v.v.).

Ví dụ SELECT COUNT('A') FROM [dbo].[Items] T0

Tôi chắc chắn rằng bình thường sẽ ổn, nhưng có hơn 6 triệu hồ sơ và phải mất ~ 400ms để đếm tất cả. Điều này có thể chiếm một phần đáng kể của thời gian xử lý tổng thể.

Bảng đã có Chỉ mục NonClustered cực kỳ hẹp (tinyint, cộng với Khóa cụm) trên đó là thứ mà SQL đang sử dụng khi quét Bảng, vì vậy tôi không nghĩ chúng ta có thể làm gì tốt hơn trong vấn đề đó.

Có một vài giải pháp tôi biết, mà chúng tôi muốn tránh nếu có thể:

Chúng ta có bất kỳ lựa chọn nào khác để tăng tốc độ này không?

Đây là một Gist hiển thị thiết lập: https://gist.github.com/elvishfiend/5094f120b14f8ecfb325623edcb5f3eb


Có thể bạn không thể thay đổi nó vì đây là ứng dụng Nhà cung cấp, nhưng Aaron có một bài đăng trên blog về việc đếm các hàng trong bảng: sqlperformance.com/2014/10/t-sql-queries/ Lỗi
Greg

Câu trả lời:


14

Chế độ xem được lập chỉ mục phải nằm trong số các tùy chọn nhanh nhất, với chi phí bảo trì thấp nhất, khi được triển khai tối ưu .

Các sửa đổi được tăng dần (deltas) như tôi giải thích chi tiết trong Bảo trì chế độ xem được lập chỉ mục trong các kế hoạch thực hiện (một bản tường thuật đầy đủ không được thực hiện trên mỗi bản cập nhật bảng cơ sở); tuy nhiên, bạn cần đảm bảo rằng các phần cập nhật delta của kế hoạch thực hiện có các phương thức truy cập hiệu quả (giống như bất kỳ truy vấn nào).

Nó thường khá đơn giản để xác định một chỉ mục bị thiếu trong INSERT/UPDATE/DELETEkế hoạch thực hiện. Có lẽ bạn có thể thêm một kế hoạch thực hiện hậu thực tế (thực tế) minh họa cho câu hỏi của bạn.

Kết hợp tự động văn bản truy vấn với chế độ xem được lập chỉ mục chỉ có sẵn trong Phiên bản doanh nghiệp (và tương đương). Trong các phiên bản khác, bạn phải sử dụng WITH (NOEXPAND)gợi ý bảng. Cũng có những lý do tốt để sử dụng NOEXPANDngay cả trên Phiên bản doanh nghiệp.

Về mã trình diễn: Đảm bảo bạn chỉ định gợi ý sử dụng WITH (NOEXPAND). Cách bạn đã viết nó, NOEXPANDđược phân tích cú pháp như một bí danh. Cũng lưu ý rằng chỉ các khung nhìn cụ thể hóa (được lập chỉ mục) có thể có một NOEXPANDgợi ý.

Nếu bạn không thể thêm gợi ý trực tiếp, đây sẽ là một cách sử dụng tuyệt vời của Hướng dẫn kế hoạch. Một hướng dẫn kế hoạch cũng có thể được sử dụng để đảm bảo rằng một truy vấn phù hợp với chế độ xem được lập chỉ mục (không đặt tên rõ ràng) thực sự sử dụng chế độ xem được lập chỉ mục.

Hãy nhớ rằng không có NOEXPANDchế độ xem được cụ thể hóa (được lập chỉ mục), SQL Server luôn mở rộng định nghĩa chế độ xem khi bắt đầu biên dịch kế hoạch. Phiên bản doanh nghiệp có thể (hoặc có thể không) khớp (một phần) một truy vấn với chế độ xem được lập chỉ mục tùy thuộc vào đánh giá của nó về chi phí của từng tùy chọn.

Hỏi đáp liên quan:


6

Nếu bạn bị kẹt trên SQL Server 2012, bạn có thể thử tạo một chỉ mục trên khóa chỉ mục được nhóm. Nó có thể nhỏ hơn một chút so với chỉ mục trên một TINYINTcột. Bạn cũng có thể thử thêm nén trang vào chỉ mục của mình. Điều đó có thể làm cho truy vấn của bạn nhanh hơn nhưng nó phụ thuộc vào dữ liệu trong bảng.

Nếu bạn có thể nâng cấp lên SQL Server 2016 thì bạn có thể tạo một chỉ mục cửa hàng cột không bao gồm trên bảng. Điều đó sẽ làm cho COUNT(*)các truy vấn cực kỳ nhanh chóng với chi phí thấp hơn cho các hoạt động DML. Đây là bản demo nhanh:

DROP TABLE IF EXISTS #Items;

CREATE TABLE #Items (
    CLUST_KEY BIGINT NOT NULL,
    SMALL_COLUMN TINYINT NOT NULL,
    FILLER VARCHAR(50) NOT NULL,
    PRIMARY KEY (CLUST_KEY)
);

INSERT INTO #Items WITH (TABLOCK)
SELECT
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    , 1
    , REPLICATE('Z', 50)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

CREATE INDEX NCI ON #Items (SMALL_COLUMN);

SET STATISTICS TIME ON;

-- CPU time = 312 ms,  elapsed time = 320 ms.
SELECT COUNT(*)
FROM #Items
OPTION (MAXDOP 1);


CREATE NONCLUSTERED COLUMNSTORE INDEX NCCI ON #Items (SMALL_COLUMN);

-- CPU time = 0 ms,  elapsed time = 1 ms.
SELECT COUNT(*)
FROM #Items
OPTION (MAXDOP 1);

Với NCCI, tôi có thể đếm sáu triệu hàng dưới 20 ms.


1
  1. bạn có thể thêm cột id mà bạn cập nhật thủ công để luôn có mưa, mùa hè hoặc mùa đông.

  2. Nếu bạn có một bảng duy nhất và không có điều kiện hoặc tham gia thì

     SELECT o.NAME
    ,o.schema_id
    ,ddps.row_count
    FROM sys.indexes AS i
    INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID
    INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID
      AND i.index_id = ddps.index_id
    WHERE i.index_id < 2
      AND o.is_ms_shipped = 0
      AND o.NAME = 'even'
      AND o.schema_id = 1

Tôi nghe nói nó không phụ thuộc vào số liệu thống kê cập nhật. Tôi không chắc chắn.

  1. sp_spaceused employee Nó phụ thuộc vào số liệu thống kê cập nhật.

  2. bạn có thể tạo một cái gì đó giống như công việc chạy một lần một lần và lưu trữ id và số mới nhất

    tạo bảng ItemCount là Recentid int không null, RecentCount int không null

Bảng Itemcount luôn chỉ chứa 1 hàng và không cần bất kỳ chỉ mục nào

insert into ItemCount (Latestid,LatestCount)
select top 1  itemid
,(select count(*) from [dbo].[Items])LatestCount
from [dbo].[Items]
order by itemid DESC

- Ở đây tính logic là của riêng bạn

Vì vậy, khi truy vấn của bạn yêu cầu số lượng, bạn có thể làm điều này,

declare @LatestID INT
declare @LatestCount int

select @LatestID=LatestID,@LatestCount=LatestCount 
from ItemCount ic 

declare @FreshCount int
declare @NewCount int
SELECT @FreshCount=COUNT(1)  FROM [dbo].[Items] it
where it.itemid>=@LatestID 

set @NewCount=@FreshCount+@LatestCount

[dbo].[Items]cột itemid ở đây nên được lập chỉ mục

Điều này cũng sẽ phù hợp nếu bạn có join and filterđiều kiện trong count (*)truy vấn của mình

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.