3 回答

TA貢獻(xiàn)1820條經(jīng)驗(yàn) 獲得超10個(gè)贊
在PostgreSQL中,對(duì)大表中的行進(jìn)行計(jì)數(shù)是很慢的。為了獲得準(zhǔn)確的數(shù)字,由于MVCC的性質(zhì),它必須對(duì)行進(jìn)行完整計(jì)數(shù)。有一種方法來大大加快這如果計(jì)數(shù)也沒有必須要確切喜歡它似乎是在你的情況。
而不是獲得確切的計(jì)數(shù)(大表速度慢):
SELECT count(*) AS exact_count FROM myschema.mytable;
您會(huì)得到如下估算值(非??欤?/p>
SELECT reltuples::bigint AS estimate FROM pg_class where relname='mytable';
估算的接近程度取決于您是否運(yùn)行ANALYZE足夠。通常非常接近。
請(qǐng)參閱PostgreSQL Wiki FAQ。
或用于count(*)性能的專用Wiki頁面。
更好了
PostgreSQL的維基文章的是一個(gè)有點(diǎn)草率。它忽略了一個(gè)數(shù)據(jù)庫中可能存在多個(gè)具有相同名稱的表的可能性-處于不同的模式。要說明這一點(diǎn):
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'
還是更好
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
更快,更簡(jiǎn)單,更安全,更優(yōu)雅。請(qǐng)參閱《對(duì)象標(biāo)識(shí)符類型》手冊(cè)。
to_regclass('myschema.mytable')在Postgres 9.4+中使用可避免無效表名的例外情況:
如何檢查給定架構(gòu)中是否存在表
TABLESAMPLE SYSTEM (n) 在Postgres 9.5+
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
就像@a_horse commented一樣,SELECT如果pg_class由于某些原因當(dāng)前的統(tǒng)計(jì)信息不足,則為該命令新添加的子句可能會(huì)很有用。例如:
沒有autovacuum運(yùn)行。
大INSERT或DELETE。
TEMPORARY表格(未被涵蓋autovacuum)。
這只會(huì)查看隨機(jī)的n%(1在示例中)選擇的塊并計(jì)算其中的行。您可以選擇更大的樣本來增加成本,并減少誤差。準(zhǔn)確性取決于更多因素:
行大小分布。如果給定的塊恰好比平常的行寬,則計(jì)數(shù)比平常的低,等等。
死元組或FILLFACTOR每個(gè)塊占用空間。如果整個(gè)表分布不均,則估計(jì)值可能會(huì)不正確。
一般舍入錯(cuò)誤。
在大多數(shù)情況下,來自的估計(jì)pg_class會(huì)更快,更準(zhǔn)確。
回答實(shí)際問題
首先,我需要知道該表中的行數(shù),如果總計(jì)數(shù)大于某個(gè)預(yù)定義常量,
以及是否...
...在計(jì)數(shù)超過我的常數(shù)值時(shí)是可能的,它將停止計(jì)數(shù)(而不是等待完成計(jì)數(shù)以告知行計(jì)數(shù)更大)。
是。您可以將子查詢與結(jié)合使用LIMIT:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres 實(shí)際上停止計(jì)數(shù)超過給定的限制,您將獲得多達(dá)n行(在本示例中為500000)的精確和當(dāng)前計(jì)數(shù),否則為n。但是,速度不及中的估算速度。pg_class

TA貢獻(xiàn)1850條經(jīng)驗(yàn) 獲得超11個(gè)贊
我通過運(yùn)行在postgres應(yīng)用程序中執(zhí)行了一次:
EXPLAIN SELECT * FROM foo;
然后使用正則表達(dá)式或類似的邏輯檢查輸出。對(duì)于簡(jiǎn)單的SELECT *,輸出的第一行應(yīng)如下所示:
Seq Scan on uids (cost=0.00..1.21 rows=8 width=75)
您可以將該rows=(\d+)值用作將要返回的行數(shù)的粗略估計(jì),然后僅SELECT COUNT(*)在估計(jì)值小于閾值的1.5倍(或您認(rèn)為對(duì)應(yīng)用程序有意義的任何數(shù)目)時(shí)才進(jìn)行實(shí)際計(jì)算。
根據(jù)查詢的復(fù)雜程度,此數(shù)字可能會(huì)越來越少。實(shí)際上,在我的應(yīng)用程序中,當(dāng)我們添加聯(lián)接和復(fù)雜條件時(shí),它變得如此不準(zhǔn)確,以至于完全不值錢,甚至不知道在100的冪內(nèi)將返回多少行,因此我們不得不放棄該策略。
但是,如果您的查詢足夠簡(jiǎn)單,Pg可以在合理的誤差范圍內(nèi)預(yù)測(cè)它將返回多少行,那么它可能對(duì)您有用。

TA貢獻(xiàn)1799條經(jīng)驗(yàn) 獲得超8個(gè)贊
在Oracle中,您可以rownum用來限制返回的行數(shù)。我猜想其他SQL中也存在類似的構(gòu)造。因此,對(duì)于您給出的示例,可以將返回的行數(shù)限制為500001,count(*)然后應(yīng)用a :
SELECT (case when cnt > 500000 then 500000 else cnt end) myCnt
FROM (SELECT count(*) cnt FROM table WHERE rownum<=500001)
- 3 回答
- 0 關(guān)注
- 2243 瀏覽
添加回答
舉報(bào)