Cách nhanh nhất để đếm số lượng hàng chính xác trong một bảng rất lớn?


234

Tôi đã đi qua các bài báo trạng thái SELECT COUNT(*) FROM TABLE_NAMEsẽ chậm khi bảng có nhiều hàng và nhiều cột.

Tôi có một bảng có thể chứa hàng tỷ hàng [nó có khoảng 15 cột]. Có cách nào tốt hơn để có được CHÍNH XÁC số lượng của số lượng hàng của một bảng không?

Vui lòng xem xét những điều sau đây trước câu trả lời của bạn:

  • Tôi đang tìm kiếm một giải pháp độc lập nhà cung cấp cơ sở dữ liệu. Sẽ ổn nếu nó bao gồm MySQL , Oracle , MS SQL Server . Nhưng nếu thực sự không có giải pháp độc lập với nhà cung cấp cơ sở dữ liệu thì tôi sẽ giải quyết các giải pháp khác nhau cho các nhà cung cấp cơ sở dữ liệu khác nhau.

  • Tôi không thể sử dụng bất kỳ công cụ bên ngoài khác để làm điều này. Tôi chủ yếu tìm kiếm một giải pháp dựa trên SQL.

  • Tôi không thể bình thường hóa thiết kế cơ sở dữ liệu của mình nữa. Nó đã có trong 3NF và hơn nữa rất nhiều mã đã được viết xung quanh nó.


4
Và chỉ tò mò tại sao cần số lượng hàng ngay lập tức chính xác khi bạn có hàng tỷ trong số đó ...
zerkms

2
Không phải tất cả chúng ta đều hy vọng rằng cấu trúc cụ thể này đã được tối ưu hóa bởi nhà cung cấp cơ sở dữ liệu của chúng ta?
KevinDTimm

5
@Swaranga, bạn có thể làm rõ thêm một chút về mục đích bảo trì cơ sở dữ liệu này là gì để biết chính xác số lượng hàng trong bảng không? Tôi không thể tưởng tượng được. Và như Kevin nói, nếu có cách nhanh hơn COUNT (*) thì nhà cung cấp DBMS chắc chắn sẽ nên triển khai lại COUNT (*) để sử dụng nó ...
Tony Andrew

3
Chắc chắn nếu bảng được ghi thường xuyên thì số đếm chính xác của bạn sẽ chỉ chính xác cho một thời điểm cụ thể và thậm chí có thể không chính xác nếu các quy trình khác được ghi vào bảng, trừ khi bạn đặt khóa bảng vào truy vấn.
Steve Ford

2
Bạn có thể sử dụng chèn và xóa kích hoạt để giữ số lượng cán?
paparazzo

Câu trả lời:


246

Câu trả lời đơn giản:

  • Nhà cung cấp cơ sở dữ liệu giải pháp độc lập = sử dụng tiêu chuẩn = COUNT(*)
  • Có các giải pháp SQL Server gần đúng nhưng không sử dụng COUNT (*) = ngoài phạm vi

Ghi chú:

COUNT (1) = COUNT (*) = COUNT (Chính khóa) chỉ trong trường hợp

Biên tập:

Ví dụ về máy chủ SQL (1,4 tỷ hàng, 12 cột)

SELECT COUNT(*) FROM MyBigtable WITH (NOLOCK)
-- NOLOCK here is for me only to let me test for this answer: no more, no less

1 lượt chạy, 5:46 phút, đếm = 1,401,659,700

--Note, sp_spaceused uses this DMV
SELECT
   Total_Rows= SUM(st.row_count)
FROM
   sys.dm_db_partition_stats st
WHERE
    object_name(object_id) = 'MyBigtable' AND (index_id < 2)

2 lần chạy, cả dưới 1 giây, đếm = 1,401,659,670

Cái thứ hai có ít hàng = sai. Sẽ giống nhau hoặc nhiều hơn tùy thuộc vào ghi (xóa được thực hiện ngoài giờ ở đây)


9
Nope, COUNT(*) = COUNT(key). Điều này chỉ sai. Nếu không có NOT NULLràng buộc - thì chúng có thể không bằng nhau (về kết quả cũng như trong kế hoạch thực hiện).
zerkms

14
@zerkmsby: Đối với COUNT (khóa) Tôi có nghĩa là COUNT (khóa chính) không thể rỗng. Tôi sẽ làm rõ
gbn

8
với (NOLOCK) không phải là thứ cho phép nó chạy trên sản xuất và nó có thể dẫn đến số lượng không chính xác. Khi bạn sử dụng gợi ý đó, chắc chắn rằng nó ngăn chặn khóa nhưng tác dụng phụ trên hộp sản xuất là bạn có thể đếm hàng hai lần trong một số tình huống hoặc bỏ qua hàng trong các tình huống khác. NOLOCK tốt hơn để sử dụng trên một bảng không được ghi vào vì nó cho phép "đọc bẩn". Đừng khuyên mọi người sử dụng gợi ý đó trừ khi họ hoàn toàn hiểu hậu quả
Davos

4
@mishrsud Truy vấn chính xác duy nhất là CHỌN COUNT (*), nhưng nó chậm. Bạn có thể có chính xác & chậm, hoặc thô và nhanh chóng. Những gì bạn làm sẽ phụ thuộc vào những gì quan trọng hơn cho mục đích bạn cần tính. KHÔNG LOCK có thể bao gồm hoặc thực sự loại trừ các hàng là giao dịch giữa hoặc các trang di chuyển vì bất kỳ lý do gì.
Davos

5
@gbn giải pháp rất hay, bạn có thể cho biết công dụng của nó là index_id < 2gì không?
cam kết

29

Cách nhanh nhất cho đến nay trên MySQL là:

SHOW TABLE STATUS;

Bạn sẽ ngay lập tức nhận được tất cả các bảng của mình với số lượng hàng (là tổng số) cùng với nhiều thông tin bổ sung nếu bạn muốn.


1
Cách thông minh..với điều này, bạn có thể nhận được số lượng hàng của nhiều bảng trong 1 truy vấn.
Deval Khandelwal

Bạn đã chạy trên db có các bảng có ~ tỷ mục như @gbn và nhận thấy thời gian chưa?
KNU

Giá trị nào là tổng số hàng cho tất cả các bảng trong cơ sở dữ liệu? Và đây là gần đúng - nếu bạn muốn các giá trị đếm hàng chính xác thì sao?
Kreeverp 14/03/2015

2
ví dụ, điều này hoàn toàn không hoạt động, trên INNODB, công cụ lưu trữ đọc một vài hàng và ngoại suy để đoán số lượng hàng
Martijn Scheffer

10

Tôi đã bắt gặp các bài viết nói rằng CHỌN COUNT (*) TỪ TABLE_NAME sẽ chậm khi bảng có nhiều hàng và nhiều cột.

Điều đó phụ thuộc vào cơ sở dữ liệu. Ví dụ, một số tăng tốc độ bằng cách theo dõi xem các hàng đang sống hay đã chết trong chỉ mục, cho phép chỉ mục chỉ quét để trích xuất số lượng hàng. Những người khác thì không, và do đó yêu cầu truy cập toàn bộ bảng và đếm từng hàng một. Hoặc là sẽ chậm cho một bảng lớn.

Lưu ý rằng bạn thường có thể trích xuất một ước tính tốt bằng cách sử dụng các công cụ tối ưu hóa truy vấn, thống kê bảng, v.v. Trong trường hợp của PostgreQuery, bạn có thể phân tích cú pháp đầu ra explain count(*) from yourtablevà có được ước tính hợp lý về số lượng hàng. Điều này đưa tôi đến câu hỏi thứ hai của bạn.

Tôi có một bảng có thể chứa hàng tỷ hàng [nó có khoảng 15 cột]. Có cách nào tốt hơn để có được số lượng CHÍNH XÁC của số lượng hàng của một bảng không?

Nghiêm túc? :-) Bạn thực sự có nghĩa là số đếm chính xác từ một bảng có hàng tỷ hàng? Bạn thật sự chắc không? :-)

Nếu bạn thực sự làm, bạn có thể theo dõi tổng số sử dụng kích hoạt, nhưng hãy chú ý đến sự tương tranh và bế tắc nếu bạn làm vậy.


Có Denis, số lượng chính xác là bắt buộc. :(
Swaranga Sarma

5
Thật may mắn khi các nhà quản lý Google hợp lý hơn sếp của bạn ... Hãy hình dung mọi thứ sẽ chậm đến mức nào nếu trả về số lượng kết quả tìm kiếm chính xác cho mỗi truy vấn của bạn thay vì bám vào số ước tính.
Denis de Bernardy

Ít nhất bạn đồng cảm với tôi. Làm thế nào về một giải pháp duy nhất của Oracle? Điều đó sẽ làm giảm vấn đề của tôi đến một mức độ. Hiện tại khách hàng đang sử dụng Oracle; Vì vậy, nếu tôi đưa ra một cách giải quyết chỉ dành cho Oracle, điều đó sẽ làm [trong thời điểm hiện tại]. :)
Swaranga Sarma

6
"Có Denis, số lượng chính xác là bắt buộc.:" "- tôi chỉ có thể suy đoán. Quá trình bảo trì db có phát hiện ra rằng có 42.123.876 hàng trong bảng A và sau đó tạo 42.123.876 hàng trống trong bảng B, rồi lặp qua bảng A và cập nhật các hàng trong bảng B ...? Hay nó điên hơn thế? ;-)
Tony Andrew

1
Giao dịch 2 không thể bắt đầu trước khi giao dịch 1 được cam kết. Nếu không có bản cập nhật "bảng đếm", nhiều giao dịch cập nhật có thể chạy song song. Với "bảng đếm", mỗi giao dịch phải "lấy một vé" để cập nhật số lượng của nó. Vì vậy, các giao dịch bắt đầu xếp hàng tại máy bán vé (người lên lịch quyết định ai sẽ là người tiếp theo nhận được khóa trên bảng đếm).
Erwin Smout

10

Có cách nào tốt hơn để có được số lượng CHÍNH XÁC của số lượng hàng của một bảng không?

Để trả lời câu hỏi của bạn một cách đơn giản, Không .

Nếu bạn cần một cách độc lập DBMS để làm điều này, cách nhanh nhất sẽ luôn là:

SELECT COUNT(*) FROM TableName

Một số nhà cung cấp DBMS có thể có những cách nhanh hơn chỉ hoạt động cho hệ thống của họ. Một số tùy chọn này đã được đăng trong các câu trả lời khác.

COUNT(*) dù sao cũng nên được tối ưu hóa bởi DBMS (ít nhất là bất kỳ DB xứng đáng nào của SẢN PHẨM), vì vậy đừng cố gắng bỏ qua tối ưu hóa của chúng.

Lưu ý phụ:
Tôi chắc chắn nhiều truy vấn khác của bạn cũng mất nhiều thời gian để hoàn thành vì kích thước bảng của bạn. Bất kỳ mối quan tâm về hiệu suất có lẽ nên được giải quyết bằng cách suy nghĩ về thiết kế lược đồ của bạn với tốc độ trong tâm trí. Tôi nhận ra rằng bạn nói rằng đó không phải là một tùy chọn để thay đổi nhưng nó có thể chỉ ra rằng hơn 10 phút truy vấn không phải là một tùy chọn. NF thứ 3 không phải lúc nào cũng là cách tiếp cận tốt nhất khi bạn cần tốc độ và đôi khi dữ liệu có thể được phân vùng trong một số bảng nếu các bản ghi không phải được lưu trữ cùng nhau. Đôi điều suy nghĩ...


10

Tôi đã nhận được tập lệnh này từ một câu hỏi / câu trả lời khác của StackOverflow:

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'YourTableNameHere'
  AND s.name = N'dbo'
  AND p.index_id IN (0,1);

Bảng của tôi có 500 triệu bản ghi và trả về ở trên trong vòng chưa đến 1ms. Trong khi đó,

SELECT COUNT(id) FROM MyTable

mất 39 phút, 52 giây!

Chúng mang lại số lượng hàng chính xác như nhau (trong trường hợp của tôi, chính xác là 519326012).

Tôi không biết nếu đó sẽ luôn luôn là trường hợp.


Bạn có thể thêm một tham số để có được số hàng với truy vấn này không? Ví dụ: Chọn COUNT (1) TỪ TABLENAME WHERE CộtFiled = '1' Với truy vấn của bạn?
VnDevil

Đó là số đếm - số lượng hàng (bản ghi) là "số đếm" trong trường hợp này. "500 triệu bản ghi" là một con số gần đúng và "519326012" là số lượng hàng hoặc số chính xác. Hàng = hồ sơ = đếm.
JakeJ

9

Bạn có thể thử sp_spaceuse này (Transact-SQL)

Hiển thị số lượng hàng, không gian đĩa dành riêng và không gian đĩa được sử dụng bởi một bảng, chế độ xem được lập chỉ mục hoặc hàng đợi Nhà môi giới dịch vụ trong cơ sở dữ liệu hiện tại hoặc hiển thị không gian đĩa dành cho toàn bộ cơ sở dữ liệu.


Sp_spaceuse không cho tôi một số lượng gần đúng?
Swaranga Sarma

1
FYI: Điều này sử dụng sys.dm_db_partition_stats trong nội bộ
gbn

6

Nếu phiên bản SQL Server là 2005/2008, bạn có thể sử dụng DMV để tính số hàng trong một bảng:

-- Shows all user tables and row counts for the current database 
-- Remove is_ms_shipped = 0 check to include system objects 
-- i.index_id < 2 indicates clustered index (1) or hash table (0) 
SELECT o.name, 
 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 
ORDER BY o.NAME 

Đối với công cụ cơ sở dữ liệu SQL Server 2000, sysindexes sẽ hoạt động, nhưng chúng tôi khuyên bạn nên tránh sử dụng nó trong các phiên bản tương lai của SQL Server vì nó có thể bị xóa trong tương lai gần.

Mã mẫu được lấy từ: Cách lấy số lượng hàng trong bảng một cách nhanh chóng và không đau đớn


Điều này gần đúng không chính xác : vui lòng xem câu trả lời của tôi
gbn

Bạn có biết một ví dụ mà điều này không chính xác? AFAIK, nó không phụ thuộc vào số liệu thống kê cập nhật.
Alireza Maddah

5

tôi sử dụng

select /*+ parallel(a) */  count(1) from table_name a;

chọn / * + song song (a) * / đếm (1) từ tên_bảng a
Mainsh S

5

Tôi gần như là chuyên gia như những người khác đã trả lời nhưng tôi gặp vấn đề với quy trình tôi đang sử dụng để chọn một hàng ngẫu nhiên từ một bảng (không liên quan quá mức) nhưng tôi cần biết số lượng hàng trong bảng tham chiếu của mình để tính chỉ số ngẫu nhiên. Sử dụng công cụ Đếm truyền thống (*) hoặc Đếm (1) nhưng đôi khi tôi nhận được tối đa 2 giây để truy vấn của mình chạy. Vì vậy, thay vào đó (đối với bảng của tôi có tên 'tbl_HighOrder') tôi đang sử dụng:

Declare @max int

Select @max = Row_Count
From sys.dm_db_partition_stats
Where Object_Name(Object_Id) = 'tbl_HighOrder'

Nó hoạt động rất tốt và thời gian truy vấn trong Management Studio bằng không.


1
FWIW, bạn nên đề cập đến nhà cung cấp cơ sở dữ liệu WHICH bạn đang sử dụng; Tôi nghĩ rằng tuyên bố sẽ hơi khác nhau tùy thuộc vào nhà cung cấp.
ToolmakerSteve

5

Chà, muộn 5 năm và không chắc chắn nếu nó giúp:

Tôi đã cố gắng để đếm không. trong số các hàng trong bảng SQL Server sử dụng MS SQL Server Management Studio và gặp phải một số lỗi tràn, sau đó tôi đã sử dụng như sau:

chọn Count_big (1) TỪ [dbname]. [dbo]. [FactSampleValue];

Kết quả :

24296650578 hàng


5

Tôi đã tìm thấy bài viết hay này SQL Server Hướng dẫn CÁCH: nhanh chóng truy xuất số lượng hàng chính xác cho bảng từ martijnh1đó đưa ra một bản tóm tắt tốt cho mỗi kịch bản.

Tôi cần mở rộng điều này khi tôi cần cung cấp số lượng dựa trên một điều kiện cụ thể và khi tôi tìm ra phần này, tôi sẽ cập nhật thêm câu trả lời này.

Trong khi đó, đây là chi tiết từ bài viết:

Cách 1:

Truy vấn:

SELECT COUNT(*) FROM Transactions 

Bình luận:

Thực hiện quét toàn bộ bảng. Chậm trên bàn lớn.

Cách 2:

Truy vấn:

SELECT CONVERT(bigint, rows) 
FROM sysindexes 
WHERE id = OBJECT_ID('Transactions') 
AND indid < 2 

Bình luận:

Cách nhanh chóng để lấy hàng đếm. Phụ thuộc vào số liệu thống kê và không chính xác.

Chạy DBCC UPDATEUSAGE (Cơ sở dữ liệu) VỚI COUNT_lawS, có thể mất thời gian đáng kể cho các bảng lớn.

Cách 3:

Truy vấn:

SELECT CAST(p.rows AS float) 
FROM sys.tables AS tbl 
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and
idx.index_id < 2 
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int) 
AND p.index_id=idx.index_id 
WHERE ((tbl.name=N'Transactions' 
AND SCHEMA_NAME(tbl.schema_id)='dbo')) 

Bình luận:

Cách phòng quản lý SQL đếm các hàng (xem các thuộc tính bảng, lưu trữ, đếm hàng). Rất nhanh, nhưng vẫn là một số lượng hàng xấp xỉ.

Cách 4:

Truy vấn:

SELECT SUM (row_count) 
FROM sys.dm_db_partition_stats 
WHERE object_id=OBJECT_ID('Transactions')    
AND (index_id=0 or index_id=1); 

Bình luận:

Hoạt động nhanh (mặc dù không nhanh như phương pháp 2) và không kém phần quan trọng, đáng tin cậy.


Cảm ơn! Mẹo thực sự hữu ích. Tôi không có quyền xem các bảng hệ thống nên phương thức 4 không phải là tôi. Tuy nhiên phương pháp 3 là đủ tốt.
Nicholas Humphrey

3

Tôi không nghĩ có một giải pháp chung luôn luôn nhanh nhất: một số RDBMS / phiên bản có tối ưu hóa cụ thể để SELECT COUNT(*)sử dụng các tùy chọn nhanh hơn trong khi các giải pháp khác chỉ đơn giản là quét bảng. Bạn cần phải đi đến các trang web tài liệu / hỗ trợ cho bộ thứ hai, có thể sẽ cần một số truy vấn cụ thể hơn để viết, thường là một truy vấn theo một chỉ mục theo một cách nào đó.

BIÊN TẬP:

Đây là một suy nghĩ có thể hoạt động, tùy thuộc vào lược đồ và phân phối dữ liệu của bạn: bạn có cột được lập chỉ mục tham chiếu giá trị tăng, ID tăng số, nói, hoặc thậm chí dấu thời gian hoặc ngày không? Sau đó, giả sử việc xóa không xảy ra, có thể lưu trữ số đếm lên đến một số giá trị gần đây (ngày hôm qua, giá trị ID cao nhất tại một số điểm mẫu gần đây) và thêm số lượng vượt quá, sẽ giải quyết rất nhanh trong chỉ mục . Tất nhiên, phụ thuộc vào các giá trị và chỉ số, nhưng áp dụng cho hầu hết mọi phiên bản của bất kỳ DBMS nào.


Tôi rất hy vọng rằng bất kỳ DBMS phong nha nào cũng sẽ sử dụng một chỉ mục cho SELECT COUNT(*). Ngay cả MySQL rõ ràng cũng làm điều đó ....
sleske

giả sử xóa không xảy ra - nghiêm túc ?? ; p
ToolmakerSteve

3

Tôi đến trễ câu hỏi này, nhưng đây là những gì bạn có thể làm với MySQL (khi tôi sử dụng MySQL). Tôi đang chia sẻ những quan sát của tôi ở đây:

1) SELECT COUNT(*) AS TOTAL_ROWS FROM <TABLE_NAME>

Kết quả
Hàng đếm: 508534
Đầu ra của bảng điều khiển: Các hàng bị ảnh hưởng: 0 Các hàng được tìm thấy: 1 Cảnh báo: 0 Thời lượng cho 1 truy vấn: 0.125 giây.
Mất một lúc cho một bảng có số lượng hàng lớn, nhưng số hàng rất chính xác.

2) SHOW TABLE STATUS or SHOW TABLE STATUS WHERE NAME="<TABLE_NAME>"

Kết quả
Số hàng: 511235
Đầu ra của bảng điều khiển: Các hàng bị ảnh hưởng: 0 Các hàng được tìm thấy: 1 Cảnh báo: 0 Thời lượng cho 1 truy vấn: 0,250 giây Tóm tắt: Số hàng không chính xác.

3) SELECT * FROM information_schema.tables WHERE table_schema = DATABASE();

Kết quả
Số hàng: 507806
Đầu ra của bảng điều khiển: Các hàng bị ảnh hưởng: 0 Các hàng được tìm thấy: 48 Cảnh báo: 0 Thời lượng cho 1 truy vấn: 1.701 giây.
Số hàng không chính xác.

Tôi không phải là chuyên gia về cơ sở dữ liệu hoặc MySQL, nhưng tôi nhận thấy rằng đối với các bảng rất lớn, bạn có thể sử dụng tùy chọn 2 hoặc 3 và nhận được 'ý tưởng công bằng' về số lượng hàng có mặt.

Tôi cần lấy số hàng này để hiển thị một số thống kê trên giao diện người dùng. Với các truy vấn trên, tôi biết rằng tổng số hàng là hơn 500.000, vì vậy tôi đã đưa ra các thống kê như "Hơn 500.000 hàng" mà không hiển thị số lượng hàng chính xác.

Có thể tôi chưa thực sự trả lời câu hỏi của OP, nhưng tôi đang chia sẻ những gì tôi đã làm trong tình huống cần số liệu thống kê như vậy. Trong trường hợp của tôi, hiển thị các hàng gần đúng là chấp nhận được và do đó, ở trên đã làm việc cho tôi.


2

Không chính xác là một giải pháp bất khả tri DBMS, nhưng ít nhất mã khách hàng của bạn sẽ không thấy sự khác biệt ...

Tạo một bảng T khác chỉ với một hàng và một trường số nguyên N 1 và tạo INSERT TRIGGER vừa thực hiện:

UPDATE T SET N = N + 1

Đồng thời tạo một TRIGGER XÓA thực thi:

UPDATE T SET N = N - 1

Một DBMS có giá trị muối của nó sẽ đảm bảo tính nguyên tử của các hoạt động trên 2 và N sẽ chứa số lượng hàng chính xác tại mọi thời điểm, sau đó cực kỳ nhanh chóng để có được bằng cách đơn giản:

SELECT N FROM T

Mặc dù các kích hoạt là đặc thù của DBMS, việc chọn từ T không phải và mã khách hàng của bạn sẽ không cần thay đổi cho từng DBMS được hỗ trợ.

Tuy nhiên, điều này có thể có một số vấn đề về khả năng mở rộng nếu bảng bị CHỌN hoặc XÓA chuyên sâu, đặc biệt là nếu bạn KHÔNG CAM KẾT ngay sau khi XÁC NHẬN / XÓA.


1 Những tên này chỉ là giữ chỗ - sử dụng một cái gì đó có ý nghĩa hơn trong sản xuất.

2 Ie N không thể được thay đổi bằng một giao dịch đồng thời giữa đọc và viết thành N, miễn là cả đọc và viết đều được thực hiện trong một câu lệnh SQL.


2

Một câu trả lời điên rồ theo nghĩa đen, nhưng nếu bạn có một loại hệ thống sao chép nào đó được thiết lập (đối với một hệ thống có hàng tỷ hàng, tôi hy vọng bạn làm như vậy), bạn có thể sử dụng công cụ ước tính sơ bộ (như MAX(pk) ), chia giá trị đó cho số nô lệ bạn có, chạy một số truy vấn song song.

Đối với hầu hết các phần, bạn sẽ phân vùng các truy vấn trên các nô lệ dựa trên khóa tốt nhất (hoặc khóa chính tôi đoán), theo cách đó (chúng tôi sẽ sử dụng 250000000 làm Hàng / nô lệ của chúng tôi):

-- First slave
SELECT COUNT(pk) FROM t WHERE pk < 250000000
-- Ith slave where 2 <= I <= N - 1
SELECT COUNT(pk) FROM t WHERE pk >= I*250000000 and pk < (I+1)*250000000
-- Last slave
SELECT COUNT(pk) FROM t WHERE pk > (N-1)*250000000

Nhưng bạn chỉ cần SQL. Thật là một bức tượng bán thân. Ok, vì vậy hãy nói rằng bạn là một người buồn bã. Trên chủ (hoặc nô lệ gần nhất) rất có thể bạn cần tạo một bảng cho việc này:

CREATE TABLE counter_table (minpk integer, maxpk integer, cnt integer, slaveid integer)

Vì vậy, thay vì chỉ có các lựa chọn chạy trong nô lệ của bạn, bạn sẽ phải thực hiện thao tác chèn, giống như sau:

INSERT INTO counter_table VALUES (I*25000000, (I+1)*250000000, (SELECT COUNT(pk) FROM ... ), @@SLAVE_ID)

Bạn có thể gặp vấn đề với nô lệ viết lên bàn trên chủ. Bạn có thể cần nhận được nhiều hơn nữa - ý tôi là, sáng tạo:

-- A table per slave!
INSERT INTO counter_table_slave_I VALUES (...)

Cuối cùng, bạn nên có một nô lệ tồn tại cuối cùng trong đường dẫn đi ngang qua biểu đồ nhân rộng, liên quan đến nô lệ đầu tiên. Nô lệ đó bây giờ nên có tất cả các giá trị truy cập khác và nên có các giá trị riêng. Nhưng vào thời điểm bạn hoàn thành, có thể có các hàng được thêm vào, vì vậy bạn phải chèn một hàng khác bù cho pk tối đa được ghi trong counter_table của bạn và pk tối đa hiện tại.

Tại thời điểm đó, bạn phải thực hiện một hàm tổng hợp để tìm ra tổng số hàng là gì, nhưng điều đó dễ dàng hơn vì bạn sẽ chạy nó trên hầu hết các "số nô lệ bạn có và thay đổi".

Nếu bạn đang ở trong tình huống bạn có các bảng riêng biệt trong các nô lệ, bạn có thể UNIONlấy tất cả các hàng bạn cần.

SELECT SUM(cnt) FROM (
    SELECT * FROM counter_table_slave_1
      UNION
    SELECT * FROM counter_table_slave_2
      UNION
    ...
  )

Hoặc bạn biết, hãy bớt điên rồ hơn một chút và di chuyển dữ liệu của bạn sang hệ thống xử lý phân tán hoặc có thể sử dụng giải pháp Kho dữ liệu (điều này cũng sẽ cung cấp cho bạn dữ liệu tuyệt vời trong tương lai).

Xin lưu ý, điều này phụ thuộc vào mức độ sao chép của bạn được thiết lập. Vì nút cổ chai chính rất có thể sẽ là lưu trữ liên tục, nếu bạn có bộ lưu trữ hỗn độn hoặc kho lưu trữ dữ liệu bị phân tách kém với tiếng ồn hàng xóm nặng nề, điều này có thể sẽ khiến bạn chạy chậm hơn chỉ chờ một lần duy nhấtSELECT COUNT(*) ...

Nhưng nếu bạn có bản sao tốt, thì tốc độ tăng của bạn sẽ liên quan trực tiếp đến số lượng hoặc nô lệ. Trên thực tế, nếu chỉ mất 10 phút để chạy truy vấn đếm một mình và bạn có 8 nô lệ, bạn sẽ cắt thời gian của mình xuống dưới một vài phút. Có lẽ một giờ để giải quyết các chi tiết của giải pháp này.

Tất nhiên, bạn sẽ không bao giờ thực sự nhận được câu trả lời chính xác đáng kinh ngạc vì cách giải quyết phân tán này giới thiệu một chút thời gian nơi các hàng có thể bị xóa và chèn, nhưng bạn có thể thử lấy một khóa hàng phân tán cùng một lúc và có được số đếm chính xác của các hàng trong bảng trong một thời điểm cụ thể.

Trên thực tế, điều này dường như là không thể, vì về cơ bản bạn bị mắc kẹt với một giải pháp chỉ dành cho SQL và tôi không nghĩ rằng bạn đã cung cấp một cơ chế để chạy một truy vấn bị khóa và bị khóa trên nhiều nô lệ, ngay lập tức. Có thể nếu bạn có quyền kiểm soát tệp nhật ký sao chép ... điều đó có nghĩa là bạn thực sự đang quay cuồng nô lệ cho mục đích này, điều này chắc chắn sẽ chậm hơn so với việc chỉ chạy truy vấn đếm trên một máy.

Vì vậy, có hai đồng xu 2013 của tôi.


2

Nếu kích hoạt chèn quá đắt để sử dụng, nhưng có thể đủ khả năng kích hoạt xóa và có chế độ tăng tự độngid , sau đó sau khi đếm toàn bộ bảng một lần và ghi nhớ số đếm last-countlast-counted-id ,

sau đó mỗi ngày chỉ cần đếm cho id> last-counted-id, thêm nó vào last-countvà lưu trữ cái mới last-counted-id.

Trình kích hoạt xóa sẽ giảm số đếm cuối cùng, nếu id của bản ghi bị xóa <= last-Count-id.


.. xin lỗi không có thời gian để hiển thị SQL sẽ được sử dụng (SQL của tôi bị hoen rỉ). Nếu bất cứ ai muốn chỉnh sửa câu trả lời của tôi để thêm SQL, điều đó thật tuyệt!
ToolmakerSteve

1

Nếu bạn có cấu trúc bảng điển hình với cột khóa chính tăng tự động trong đó các hàng không bao giờ bị xóa, sau đây sẽ là cách nhanh nhất để xác định số lượng bản ghi và sẽ hoạt động tương tự trên hầu hết các cơ sở dữ liệu tuân thủ ANSI:

SELECT TOP(1) <primarykeyfield> FROM <table> ORDER BY <primarykeyfield> DESC;

Tôi làm việc với các bảng MS SQL chứa hàng tỷ hàng yêu cầu thời gian phản hồi dưới giây cho dữ liệu, bao gồm cả số lượng bản ghi. Một COUNT CHỌN (*) tương tự sẽ mất vài phút để xử lý bằng cách so sánh.


1
Không hoàn toàn đúng - điều gì xảy ra nếu một INSERTgiao dịch được khôi phục? Giá trị khóa chính đó sẽ không có, vì vậy số lượng bản ghi thực tế sẽ nhỏ hơn một giá trị tối đa.
Ngài Crispalot

Có thể là những khoảng trống theo trình tự. Thường là kết quả của việc rollback.
Osa E

Trên thực tế, có một sửa đổi của câu trả lời này có thể nhanh hơn đáng kể so với count(*), nếu nhà cung cấp cơ sở dữ liệu chưa được tối ưu hóa đủ count(*): Mỗi ngày theo dõi chỉ số tự động cuối cùng và số lượng tương ứng của nó, sau đó yêu cầu đếm số lượng hồ sơ qua đó. Cũng có thể xử lý deletes nếu thêm một kích hoạt khi xóa làm giảm tổng số trước đó , nếu id bản ghi bị xóa <= chỉ mục tự động cuối cùng đó.
ToolmakerSteve

1

Đối với máy chủ Sql hãy thử điều này

SELECT T.name, 
       I.rows AS [ROWCOUNT] 
FROM   sys.tables AS T 
       INNER JOIN sys.sysindexes AS I 
               ON T.object_id = I.id AND I.indid < 2 
WHERE T.name = 'Your_Table_Name'
ORDER  BY I.rows DESC 

0

chọn các hàng từ sysindexes trong đó id = Object_ID ('TableName') và indid <2


0

Đặt một chỉ mục trên một số cột. Điều đó sẽ cho phép trình tối ưu hóa thực hiện quét toàn bộ các khối chỉ mục, thay vì quét toàn bộ bảng. Điều đó sẽ cắt giảm chi phí IO của bạn xuống. Nhìn vào kế hoạch thực hiện trước và sau. Sau đó đo thời gian đồng hồ treo tường cả hai cách.


Nếu một bảng có hàng tỷ hàng không có chỉ mục trên bất kỳ cột nào, thì sẽ có các vấn đề về hiệu năng lan rộng, vượt xa nhu cầu được thể hiện trong câu hỏi ban đầu .. nhưng thật tốt khi bạn đề cập đến điều đó (giả sử không có gì!) :)
ToolmakerSteve

0

Nếu bạn đang sử dụng Oracle, làm thế nào về điều này (giả sử các số liệu thống kê bảng được cập nhật):

select <TABLE_NAME>, num_rows, last_analyzed from user_tables

last_analyned sẽ hiển thị thời gian khi số liệu thống kê được thu thập lần cuối.


0

Với PostgreSQL:

SELECT reltuples AS approximate_row_count FROM pg_class WHERE relname = 'table_name'

-1

Trong máy chủ SQL 2016, tôi chỉ có thể kiểm tra các thuộc tính của bảng và sau đó chọn tab 'Storage' - điều này mang lại cho tôi số lượng hàng, không gian đĩa được sử dụng bởi bảng, không gian chỉ mục được sử dụng, v.v.


Anh đang tìm a database vendor independent solution. Ngoài ra, điều này đòi hỏi một GUI và không thể được tự động. Ngoài ra, nó không nhanh hơn vì COUNT (*)
Frieder

-3

Có thể hơi muộn nhưng điều này có thể giúp những người khác cho MSSQL

; VỚI RecordCount AS (CHỌN ROW_NUMBER () QUÁ (ĐẶT HÀNG B COLNG COLUMN_NAME) NHƯ [RowNumber] TỪ TABLE_NAME) CHỌN MAX (RowNumber) TỪ RecordCount


Đây là WORSE đáng kể so với COUNT (), trừ khi chúng ta RẤT may mắn và trình tối ưu hóa quản lý để tối ưu hóa nó thành COUNT () - tại sao lại yêu cầu SORT trên một cột ngẫu nhiên?!?
DSz
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.