Известно е, че преброяването на редове в големи таблици е бавно в PostgreSQL. Моделът MVCC изисква пълен брой живи редове за точен брой. Има заобиколни решения за ускоряване на това драстично ако броятне трябва да са точни както изглежда във вашия случай.
(Не забравяйте, че дори "точно" преброяване е потенциално мъртво при пристигането!)
Точен брой
Бавно за големи таблици.
При едновременни операции за запис може да е остарял в момента, в който го получите.
SELECT count(*) AS exact_count FROM myschema.mytable;
Оценка
Изключително бързи :
SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';
Обикновено оценката е много близка. Колко близо зависи от това дали ANALYZE
или VACUUM
се изпълняват достатъчно - където "достатъчно" се определя от нивото на активност на запис във вашата таблица.
По-безопасна оценка
Горното игнорира възможността за множество таблици с едно и също име в една база данни - в различни схеми. За да отчетете това:
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';
Прехвърлянето към bigint
форматира real
номер добре, особено за големи бройки.
По-добра оценка
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
По-бързо, по-просто, по-безопасно, по-елегантно. Вижте ръководството за Типове идентификатори на обекти.
Заменете 'myschema.mytable'::regclass
с to_regclass('myschema.mytable')
в Postgres 9.4+, за да не получите нищо вместо изключение за невалидни имена на таблици. Вижте:
- Как да проверите дали таблица съществува в дадена схема
Още по-добра оценка (за много малко добавени разходи)
Можем да правим това, което прави планерът на Postgres. Цитиране на Примерите за оценка на редове в ръководството:
Тези номера са актуални към последния
VACUUM
илиANALYZE
на масата. След това плановникът извлича действителния текущ брой страници в таблицата (това е евтина операция, която не изисква сканиране на таблицата). Ако това е различно отrelpages
след товаreltuples
се мащабира съответно, за да се стигне до текуща оценка на броя на редовете.
Postgres използва estimate_rel_size
дефиниран в src/backend/utils/adt/plancat.c
, който също покрива ъгъла на липса на данни в pg_class
защото връзката никога не е била вакуумирана. Можем да направим нещо подобно в SQL:
Минимална форма
SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM pg_class
WHERE oid = 'mytable'::regclass; -- your table here
Безопасно и ясно
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
Не се прекъсва с празни таблици и таблици, които никога не са виждали VACUUM
или ANALYZE
. Ръководството за pg_class
:
Ако таблицата никога не е била вакуумирана или анализирана,
reltuples
съдържа-1
което показва, че броят на редовете е неизвестен.
Ако тази заявка върне NULL
, стартирайте ANALYZE
или VACUUM
за масата и повторете. (Алтернативно можете да оцените ширината на реда въз основа на типове колони, както прави Postgres, но това е досадно и податливо на грешки.)
Ако тази заявка върне 0
, масата изглежда е празна. Но бих ANALYZE
да се уверите. (И може би проверете вашия autovacuum
настройки.)
Обикновено block_size
е 8192. current_setting('block_size')::int
обхваща редки изключения.
Квалификациите на таблицата и схемата го правят имунизиран срещу всеки search_path
и обхват.
Така или иначе, заявката постоянно отнема <0,1 ms за мен.
Още уеб ресурси:
- ЧЗВ за Postgres Wiki
- Уики страниците на Postgres за прогнози за броя и ефективността на count(*)
TABLESAMPLE SYSTEM (n)
в Postgres 9.5+
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
Както коментира @a_horse, добавената клауза за SELECT
командата може да бъде полезна, ако статистиката в pg_class
не са достатъчно актуални по някаква причина. Например:
- Без
autovacuum
бягане. - Непосредствено след голям
INSERT
/UPDATE
/DELETE
. TEMPORARY
таблици (които не са обхванати отautovacuum
).
Това разглежда само произволно n % (1
в примера) избор на блокове и преброяване на редове в него. По-голяма извадка увеличава цената и намалява грешката, вашият избор. Точността зависи от повече фактори:
- Разпределение на размера на редовете. Ако даден блок съдържа по-широки от обичайните редове, броят е по-нисък от обикновено и т.н.
- Мъртви кортежи или
FILLFACTOR
заемат място на блок. Ако е разпределено неравномерно в таблицата, прогнозата може да е неправилна. - Общи грешки при закръгляването.
Обикновено оценката от pg_class
ще бъде по-бързо и по-точно.
Отговор на действителен въпрос
Първо, трябва да знам броя на редовете в тази таблица, ако общият брой е по-голям от някаква предварително дефинирана константа,
И дали е...
... е възможно в момента, в който броят мине постоянната ми стойност, той ще спре броенето (и няма да чака да завърши броенето, за да информира, че броят на редовете е по-голям).
Да Можете да използвате подзаявка с LIMIT
:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres всъщност спира да брои над дадената граница, получавате точна и актуална броят до n редове (500 000 в примера) и n в противен случай. Не толкова бързо, колкото оценката в pg_class
, все пак.