2012-09-18 36 views
28

Đếm bảng với số lượng lớn dữ liệu có thể rất chậm, đôi khi phải mất vài phút; nó cũng có thể tạo ra bế tắc trên một máy chủ bận. Tôi muốn hiển thị giá trị thực, NOLOCK không phải là một tùy chọn.Số lượng Máy chủ SQL chậm

Các máy chủ tôi sử dụng là SQL Server 2005 hoặc 2008 Standard hoặc Enterprise - nếu nó quan trọng. Tôi có thể tưởng tượng rằng SQL Server duy trì số lượng cho mỗi bảng và nếu không có mệnh đề WHERE tôi có thể nhận được con số đó khá nhanh, đúng không?

Ví dụ:

SELECT COUNT(*) FROM myTable 

ngay lập tức nên trở lại với giá trị đúng. Tôi có cần phải dựa vào số liệu thống kê để cập nhật không?

+2

Nhận [kế hoạch thực hiện truy vấn] (http://stackoverflow.com/questions/7359702/how-do -i-get-a-query-thi-kế hoạch), sau đó chúng ta có thể nói ...('SELECT COUNT' trực tiếp truy vấn bảng thay vì sử dụng thống kê, vì thống kê có thể lỗi thời) – Justin

+2

Câu hỏi ngớ ngẩn, nhưng bạn có chỉ mục không? – Kermit

+0

@FreshPrinceOfSO nó vẫn còn chậm nếu bạn đếm trên 'Id' (bigint, khóa chính, đặc tả nhận dạng = true). – ANeves

Trả lời

37

Rất gần xấp xỉ (bỏ qua bất kỳ giao dịch trên máy bay) sẽ là:

SELECT SUM(p.rows) FROM sys.partitions AS p 
    INNER JOIN sys.tables AS t 
    ON p.[object_id] = t.[object_id] 
    INNER JOIN sys.schemas AS s 
    ON s.[schema_id] = t.[schema_id] 
    WHERE t.name = N'myTable' 
    AND s.name = N'dbo' 
    AND p.index_id IN (0,1); 

chí này trả lại nhiều, nhanh hơn nhiều so với COUNT (*) và nếu bảng của bạn thay đổi đủ nhanh, nó không thực sự kém chính xác hơn - nếu bảng của bạn đã thay đổi giữa thời điểm bạn bắt đầu COUNT và khi được trả về, điều đó có giá trị hơn không ?

+0

Cũng có thể được sử dụng khi không có chỉ mục. – Kermit

+0

giải pháp của bạn trông rất hứa hẹn nhưng sau khi thử nghiệm trên khoảng 5 triệu bản ghi, tôi nhận được cùng thời gian phản hồi. sẽ sớm kiểm tra trên cơ sở dữ liệu lớn hơn. – Adi

+2

@Adi Một truy vấn đối với sys.partitions mất một thời gian dài? Tôi thấy việc đó khó mà tin tưởng được. –

8

(Làm thế nào lớn là "số lượng lớn các dữ liệu" - nên đã nhận xét này đầu tiên, nhưng có lẽ các exec dưới đây sẽ giúp bạn ra ngoài đã được)

Nếu tôi chạy một truy vấn trên một tĩnh (có nghĩa là không ai khác là gây phiền nhiễu với đọc/ghi/cập nhật trong một thời gian khá để tranh chấp không phải là một vấn đề) bảng với 200 triệu hàng và COUNT (*) trong 15 giây trên máy dev của tôi (oracle). Xét lượng tinh khiết của dữ liệu, điều này vẫn còn khá nhanh (ít nhất là với tôi)

Như bạn nói NOLOCK không phải là một lựa chọn, bạn có thể xem xét

exec sp_spaceused 'myTable' 

là tốt.

Nhưng chân này xuống gần tới giống như NOLOCK (bỏ qua tranh + xóa/cập nhật afaik)

2

Đếm sẽ thực hiện quét bảng hoặc quét chỉ mục. Vì vậy, đối với một số lượng lớn các hàng sẽ chậm. Nếu bạn thực hiện thao tác này thường xuyên, cách tốt nhất là giữ bản ghi số trong một bảng khác.

Tuy nhiên, nếu bạn không muốn làm điều đó, bạn có thể tạo một chỉ số giả (đó sẽ không được sử dụng bởi các truy vấn của bạn) và truy vấn đó là số hạng mục, một cái gì đó như:

select 
    row_count 
from sys.dm_db_partition_stats as p 
inner join sys.indexes as i 
    on p.index_id = i.index_id 
    and p.object_id = i.object_id 
where i.name = 'your index' 

tôi gợi ý tạo một chỉ mục mới, vì chỉ mục này (nếu nó sẽ không được sử dụng) sẽ không bị khóa trong các hoạt động khác.

Như Aaron Bertrand đã nói, việc duy trì truy vấn có thể tốn kém hơn sau đó sử dụng truy vấn đã tồn tại. Vì vậy, sự lựa chọn là của bạn.

+0

Nhưng ngay cả khi chỉ mục này không được sử dụng cho các hoạt động * đọc * khác, nó vẫn phải được duy trì cho DML khác. Tôi nghĩ rằng chỉ số giả này là tốn kém hơn bạn nghĩ. –

+0

Nó có thể giống như bạn nói. Nó phải được kiểm tra. Các sql có thể được sử dụng mà không cần tạo ra một chỉ mục mới, nhưng trên một chỉ mục hiện có. Tôi đã sử dụng một cái gì đó tương tự trên các chỉ mục được lọc. Tôi không bao giờ cần phải thực sự đếm bàn từ đầu đến cuối. –

0

Nếu bạn chỉ cần đếm số hàng thô, ví dụ: để đảm bảo bảng được tải đúng cách hoặc để đảm bảo dữ liệu không bị xóa, hãy làm như sau:

MySQL> connect information_schema; 
MySQL> select table_name,table_rows from tables; 
Các vấn đề liên quan