2012-06-21 35 views
25

Tôi có một Bảng sách Chương trình SQL với hơn 20 triệu hàng. Nó có một khóa chính nhóm (bookChapterID) và không có bất kỳ khóa hoặc chỉ mục nào khác. Phải mất miliseconds để chạy các truy vấn sau đâyHiệu suất số đếm (*)

if (select count(*) from BookChapters) = 0 
... 

Tuy nhiên, phải mất hơn 10 phút khi tôi thay đổi nó như vậy

if (select count(*) from BookChapters) = 1 
... 

hoặc

if (select count(*) from BookChapters) > 1 
... 

Tại sao vậy? Làm cách nào để có được select count(*) để thực thi nhanh hơn?

+2

Nói chung chọn " đếm (*) từ bảng "- có thể có vấn đề lớn với dữ liệu lớn hơn được;) –

Trả lời

40

Mikael Eriksson có một lời giải thích tốt dưới tại sao truy vấn đầu tiên là nhanh chóng:

SQL server tối ưu hóa nó thành: if exists(select * from BookChapters). Vì vậy, nó đi tìm sự hiện diện của một hàng thay vì đếm tất cả các hàng trong bảng.

Đối với hai truy vấn còn lại, SQL Server sẽ sử dụng quy tắc sau. Để thực hiện truy vấn như SELECT COUNT(*), SQL Server sẽ sử dụng chỉ số hẹp nhất không được phân nhóm để đếm các hàng. Nếu bảng không có bất kỳ chỉ số nào là không được nhóm, nó sẽ phải quét bảng.

Ngoài ra, nếu bảng của bạn có một chỉ số cụm bạn có thể nhận được số của bạn thậm chí nhanh hơn bằng cách sử dụng truy vấn sau đây (mượn từ trang web này Get Row Counts Fast!)

--SQL Server 2005/2008 
SELECT OBJECT_NAME(i.id) [Table_Name], i.rowcnt [Row_Count] 
FROM sys.sysindexes i WITH (NOLOCK) 
WHERE i.indid in (0,1) 
ORDER BY i.rowcnt desc 

--SQL Server 2000 
SELECT OBJECT_NAME(i.id) [Table_Name], i.rows [Row_Count] 
FROM sysindexes i (NOLOCK) 
WHERE i.indid in (0,1) 
ORDER BY i.rows desc 

Nó sử dụng hệ thống bảng sysindexes. Xem thêm thông tin bạn có thể tìm thấy ở đây SQL Server 2000, SQL Server 2005, SQL Server 2008, SQL Server 2012

Dưới đây là một liên kết Why is my SELECT COUNT(*) running so slow? với một giải pháp khác. Nó cho thấy kỹ thuật mà Microsoft sử dụng để nhanh chóng hiển thị số hàng khi bạn nhấp chuột phải vào bảng và chọn thuộc tính.

select sum (spart.rows) 
from sys.partitions spart 
where spart.object_id = object_id(’YourTable’) 
and spart.index_id < 2 

Bạn sẽ thấy điều này trả về rất nhanh bất kể bạn có bao nhiêu bảng.

Nếu bạn đang sử dụng SQL 2000, bạn vẫn có thể sử dụng bảng sysindexes để lấy số.

select max(ROWS) 
from sysindexes 
where id = object_id(’YourTable’) 

Số này có thể hơi lệch tùy thuộc vào tần suất SQL cập nhật bảng sysindexes, nhưng thường là sửa đổi (hoặc ít nhất đủ gần).

+1

bạn có đồng ý với đề xuất của tôi không? –

+1

Hi Aleksey, bạn là thiên tài, rằng nó là, tôi chỉ tò mò rằng bảng mới của tôi BookChapters2 trả về số truy vấn nhanh hơn nhiều, tôi thấy, cũng giống như bạn nói, bởi vì có một chỉ số không cụm bên trong bảng, Cảm ơn bạn nhiều – danmiao

+1

+1 cho câu trả lời tuyệt vời - Cảm ơn! Chỉ thêm một điểm nữa thôi. Đảm bảo các chỉ mục/thống kê được cập nhật trên bảng đang được truy vấn. Vì nó sử dụng những số liệu thống kê cho số lượng, số liệu thống kê trong ngày sẽ cung cấp kết quả không chính xác. – jabs

4

Bạn có xem xét truy vấn select count(BookChapterId) from BookChapterTable? - nơi `BookChapterId là chỉ mục không được nhóm. Điều đó sẽ làm cho nó chạy nhanh hơn nhiều.

Tùy thuộc vào cách bảng được sử dụng và hàng truy cập, truy vấn đối với chỉ số nonclustered có thể là điểm mấu chốt: Tôi chỉ mất một số điểm từ MDSN:

  • Trước khi bạn tạo ra chỉ số nonclustered, hiểu làm thế nào dữ liệu của bạn sẽ truy cập . Xem xét sử dụng các chỉ mục không được chỉ định cho:
  • Cột có chứa một số lượng lớn các giá trị khác biệt, chẳng hạn như kết hợp tên họ và tên đầu tiên (nếu chỉ mục nhóm được sử dụng cho các cột khác). Nếu có rất ít giá trị khác biệt, chẳng hạn như
    chỉ 1 và 0, hầu hết các truy vấn sẽ không sử dụng chỉ mục vì bảng
    quét thường hiệu quả hơn.
  • Truy vấn không trả lại tập hợp kết quả lớn.
  • Cột thường xuyên tham gia vào các điều kiện tìm kiếm của truy vấn (WHERE
    khoản) trả lại kết quả khớp chính xác.
  • Các ứng dụng hệ thống hỗ trợ có quyết định tham gia và nhóm là thường xuyên được yêu cầu. Tạo nhiều chỉ mục nonclustered trên cột tham gia vào các hoạt động nối và nhóm, và chỉ mục nhóm trên bất kỳ cột khóa ngoài nào.
  • Bao gồm tất cả các cột từ một bảng trong một truy vấn nhất định. Điều này giúp loại bỏ tất cả các chỉ số truy cập vào bảng hoặc chỉ mục nhóm.
+0

Hi EIYusubov, tôi đã thử nghiệm, không có sự khác biệt, vẫn còn rất chậm – danmiao

+0

vui lòng truy cập lại các chỉ mục của bạn, có thể bạn có chỉ mục tổng hợp hoặc bạn cần phải xây dựng lại chúng . –

+0

hi EIYusubov, nó là một chỉ mục cụm cột, không phải chỉ mục tổng hợp, tôi đã xóa khóa chính và tạo lại nó, nhưng không có sự khác biệt. – danmiao

7

Nếu bạn có một cái nhìn vào kế hoạch thực hiện cho các truy vấn của bạn, bạn sẽ thấy những gì đang xảy ra.

Truy vấn đầu tiên của bạn if (select count(*) from BookChapters) = 0 được trình tối ưu hóa truy vấn nhận dạng giống như if exists(select * from BookChapters). SQL Server biết rằng biểu thức là đúng nếu có ít nhất một hàng hiện tại để nó tìm kiếm sự hiện diện của một hàng thay vì đếm tất cả các hàng trong bảng.

Đối với các truy vấn khác của bạn, nó không thể thông minh và phải đếm số hàng trong bảng trước khi nó có thể quyết định xem biểu thức đó có đúng hay sai.

3

thử loại này, nếu bạn cần để phát hiện, nếu bảng có nhiều hàng hơn một:

if (SELECT COUNT(*) FROM (SELECT TOP 2 * FROM BookChapters) AS b) > 1 
11

thử này nếu bạn chỉ muốn biết hàng đếm:

exec sp_spaceused [TABLE_NAME]