Đếm hàng trong các bảng lớn được biết là chậm trong PostgreSQL. Mô hình MVCC yêu cầu số lượng hàng trực tiếp đầy đủ để có một con số chính xác. Có những cách giải quyết để tăng tốc độ này lên đáng kể nếu số lượng không không phải chính xác giống như nó có vẻ như trong trường hợp của bạn.
(Hãy nhớ rằng ngay cả một số lượng "chính xác" cũng có thể chết khi đến nơi!)
Số lượng chính xác
Chậm cho các bảng lớn.
Với các thao tác ghi đồng thời, nó có thể lỗi thời ngay khi bạn nhận được.
SELECT count(*) AS exact_count FROM myschema.mytable;
Ước tính
Cực kỳ nhanh :
SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';
Thông thường, ước tính là rất gần. Mức độ gần như thế nào, phụ thuộc vào việc ANALYZE
hoặc VACUUM
được chạy đủ - trong đó "đủ" được xác định bởi mức độ hoạt động ghi vào bảng của bạn.
Ước tính an toàn hơn
Phần trên bỏ qua khả năng có nhiều bảng có cùng tên trong một cơ sở dữ liệu - trong các lược đồ khác nhau. Để giải thích điều đó:
SELECT c.reltuples::bigint AS estimate
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'mytable'
AND n.nspname = 'myschema';
Truyền tới bigint
định dạng real
số độc đáo, đặc biệt đối với số lượng lớn.
Ước tính tốt hơn
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
Nhanh hơn, đơn giản hơn, an toàn hơn, thanh lịch hơn. Xem hướng dẫn về Các loại mã nhận dạng đối tượng.
Thay thế 'myschema.mytable'::regclass
với to_regclass('myschema.mytable')
trong Postgres 9.4+ để không nhận được gì thay vì một ngoại lệ cho các tên bảng không hợp lệ. Xem:
- Cách kiểm tra xem một bảng có tồn tại trong một lược đồ nhất định không
Chưa có ước tính tốt hơn (với rất ít chi phí bổ sung)
Chúng tôi có thể làm những gì người lập kế hoạch Postgres làm. Trích dẫn Ví dụ về ước tính hàng trong sách hướng dẫn:
Những con số này hiện tại kể từ
VACUUM
cuối cùng hoặcANALYZE
trên bàn. Sau đó, trình lập kế hoạch tìm nạp số trang hiện tại thực tế trong bảng (đây là một thao tác rẻ, không yêu cầu quét bảng). Ifthat khác vớirelpages
rồi đếnreltuples
được chia tỷ lệ theo tỷ lệ để đạt được ước tính số hàng hiện tại.
Postgres sử dụng estimate_rel_size
được định nghĩa trong src/backend/utils/adt/plancat.c
, cũng bao gồm trường hợp không có dữ liệu trong pg_class
bởi vì mối quan hệ không bao giờ được hút chân không. Chúng ta có thể làm điều gì đó tương tự trong SQL:
Biểu mẫu tối thiểu
SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM pg_class
WHERE oid = 'mytable'::regclass; -- your table here
An toàn và rõ ràng
SELECT (CASE WHEN c.reltuples < 0 THEN NULL -- never vacuumed
WHEN c.relpages = 0 THEN float8 '0' -- empty table
ELSE c.reltuples / c.relpages END
* (pg_relation_size(c.oid) / pg_catalog.current_setting('block_size')::int)
)::bigint
FROM pg_class c
WHERE c.oid = 'myschema.mytable'::regclass; -- schema-qualified table here
Không bị vỡ với các bảng trống và bảng chưa từng thấy VACUUM
hoặc ANALYZE
. Hướng dẫn sử dụng pg_class
:
Nếu bảng chưa bao giờ được hút chân không hoặc phân tích, hãy
reltuples
chứa-1
cho biết rằng số lượng hàng không xác định.
Nếu truy vấn này trả về NULL
, chạy ANALYZE
hoặc VACUUM
cho bảng và lặp lại. (Ngoài ra, bạn có thể ước tính chiều rộng hàng dựa trên các loại cột như Postgres, nhưng điều đó tẻ nhạt và dễ xảy ra lỗi.)
Nếu truy vấn này trả về 0
, bàn có vẻ trống. Nhưng tôi sẽ ANALYZE
để chắc chắn. (Và có thể kiểm tra autovacuum
của bạn cài đặt.)
Thông thường, block_size
là 8192. current_setting('block_size')::int
bao gồm các trường hợp ngoại lệ hiếm hoi.
Mức độ bảng và giản đồ giúp nó miễn nhiễm với bất kỳ search_path
nào và phạm vi.
Dù bằng cách nào, truy vấn luôn mất <0,1 mili giây đối với tôi.
Các tài nguyên Web khác:
- Câu hỏi thường gặp về Postgres Wiki
- Các trang wiki của Postgres dành cho ước tính số lượng và tính hiệu suất (*)
TABLESAMPLE SYSTEM (n)
trong Postgres 9.5+
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
Giống như @a_horse đã nhận xét, mệnh đề được thêm vào cho SELECT
lệnh có thể hữu ích nếu thống kê trong pg_class
không đủ hiện tại vì một số lý do. Ví dụ:
- Không có
autovacuum
đang chạy. - Ngay sau
INSERT
lớn /UPDATE
/DELETE
. -
TEMPORARY
bảng (không nằm trongautovacuum
).
Điều này chỉ xem xét một n ngẫu nhiên % (1
trong ví dụ) lựa chọn các khối và đếm các hàng trong đó. Một mẫu lớn hơn làm tăng chi phí và giảm lỗi, lựa chọn của bạn. Độ chính xác phụ thuộc vào nhiều yếu tố hơn:
- Phân phối kích thước hàng. Nếu một khối nhất định xảy ra chứa các hàng rộng hơn bình thường, thì số lượng sẽ thấp hơn bình thường, v.v.
- Bộ giá trị đã chết hoặc một
FILLFACTOR
chiếm không gian mỗi khối. Nếu phân bổ không đồng đều trên bảng, ước tính có thể bị sai lệch. - Các lỗi làm tròn chung.
Thông thường, ước tính từ pg_class
sẽ nhanh hơn và chính xác hơn.
Câu trả lời cho câu hỏi thực tế
Trước tiên, tôi cần biết số hàng trong bảng đó, nếu tổng số tiền lớn hơn một số hằng số được xác định trước,
Và liệu nó ...
... có thể xảy ra tại thời điểm số đếm vượt qua giá trị không đổi của tôi, nó sẽ dừng quá trình đếm (và không đợi kết thúc quá trình đếm để thông báo số lượng mũi tên lớn hơn).
Có. Bạn có thể sử dụng truy vấn con với LIMIT
:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres thực sự ngừng đếm vượt quá giới hạn đã cho, bạn nhận được chính xác và hiện tại đếm cho đến n hàng (trong ví dụ là 500000) và n nếu không thì. Gần như không nhanh như ước tính trong pg_class
, mặc dù.