簡體   English   中英

Postgres min功能表現

[英]Postgres min function performance

我需要runnerId的最低值。

這個查詢:

SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ;

需要80毫秒(1968結果行)。

這個:

SELECT min("runnerId") FROM betlog WHERE "marketId" = '107416794' ;

需要1600毫秒。

是否有更快的方法來找到最小值,或者我應該在我的java程序中計算min?

"Result  (cost=100.88..100.89 rows=1 width=0)"
"  InitPlan 1 (returns $0)"
"    ->  Limit  (cost=0.00..100.88 rows=1 width=9)"
"          ->  Index Scan using runneridindex on betlog  (cost=0.00..410066.33 rows=4065 width=9)"
"                Index Cond: ("runnerId" IS NOT NULL)"
"                Filter: ("marketId" = 107416794::bigint)"

CREATE INDEX marketidindex
  ON betlog
  USING btree
  ("marketId" COLLATE pg_catalog."default");

另一個想法:

SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ORDER BY "runnerId" LIMIT 1 >1600ms
SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ORDER BY "runnerId" >>100ms

LIMIT如何減緩查詢速度?

你需要的是一個多列索引

CREATE INDEX betlog_mult_idx ON betlog ("marketId", "runnerId");

如果有興趣,您可以在dba.SE上找到有關 PostgreSQL中多列索引,鏈接和基准的深入信息。

我是怎么想的?
在多列索引中,行由索引的第一列(“marketId”)排序(從而聚集),並且每個簇依次由索引的第二列排序 - 因此第一行與條件匹配min("runnerId") 這使索引掃描速度極快。

關於LIMIT減慢查詢的悖論效應 - Postgres查詢規划器在那里有一個弱點。 常見的解決方法是使用CTE(在這種情況下不是必需的)。 根據最近這個密切相關的問題查找更多信息:
PostgreSQL查詢耗時太長

min語句將由PostgreSQL使用整個表的順序掃描執行。 您可以使用以下方法優化查詢:SELECT col FROM sometable ORDER BY col ASC LIMIT 1;

當你有一個索引("runnerId") (或者至少用"runnerId"作為高階列)但是沒有索引("marketId", "runnerId")它比較了傳遞所有行的成本匹配"marketId"上使用該列的索引和挑選出最小"runnerId"從使用上的索引設置為掃描的成本"runnerId"和停止的時候才發現的第一行與匹配"marketId" 基於可用的統計數據和假設"marketId"值將隨機分布在"runnerId"的索引的索引條目中,它估計后一種方法的成本較低。

它還估算了掃描整個表格並從匹配行中選擇最小值以及可能還有其他一些替代方案的成本。 它並不總是使用某種類型的計划,而是比較所有替代方案的成本。

問題在於值將在該范圍內隨機分布的假設不一定正確(如在該示例中),導致掃描該范圍的高百分比以找到最后潛伏的行。 對於某些"marketId"值,其中所選值在"runnerId"索引的開頭附近可用,該計划應該非常快。

在PostgreSQL開發人員社區中已經討論過如果數據分布不是假定的那樣,我們可能會對長期運行中存在“風險”的計划產生偏見,並且已經開始跟蹤多列統計數據以便相關價值觀不會遇到這樣的問題。 預計在接下來的幾個版本中該領域將有所改進。 在那之前,Erwin的建議是關於如何解決這個問題的目標。

基本上,它歸結為制定更具吸引力的計划或引入優化障礙。 在這種情況下,您可以通過添加索引("marketId", "runnerId")來提供更具吸引力的選項 - 這允許以直接的方式直接得到答案。 規划人員為該替代方案分配了非常低的成本,從而使其被選中。 如果您不想添加索引,可以通過執行以下操作強制執行優化障礙:

SELECT min("runnerId")
  FROM (SELECT "runnerId" FROM betlog
          WHERE "marketId" = '107416794'
          OFFSET 0) x;

當存在OFFSET子句時(即使偏移量為零),它會強制子查詢單獨計划,並將其結果提供給外部查詢。 我希望這可以在沒有優化障礙的情況下以80毫秒而不是1600毫秒運行。 當然,如果可以添加索引,則緩存數據時查詢的速度應小於1毫秒。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM