PostgreSQL 不使用索引

hvi*_*ard 5 postgresql

我有一个非常简单的表:

CREATE TABLE content
(
  id serial NOT NULL,
  text text,
  fullfilename text,
  CONSTRAINT "PK_ID" PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE content
  OWNER TO postgres;

CREATE INDEX content_idx
  ON content
  USING gin
  (to_tsvector('danish'::regconfig, text));
Run Code Online (Sandbox Code Playgroud)

哪里text是一个相当长的聚合文本来执行全文搜索。

当我运行以下查询时,它求助于 seq 扫描:

EXPLAIN ANALYZE SELECT id
FROM content
WHERE to_tsvector('danish', text) @@ to_tsquery('danish','felter')

"Seq Scan on content  (cost=0.00..164.57 rows=249 width=4) (actual time=41.147..7235.823 rows=289 loops=1)"
"  Filter: (to_tsvector('danish'::regconfig, text) @@ '''felt'''::tsquery)"
"  Rows Removed by Filter: 1149"
"Planning time: 0.366 ms"
"Execution time: 7235.914 ms"
Run Code Online (Sandbox Code Playgroud)

那绝对不行。但是当禁用 seq 扫描时,SET enable_seqscan TO 'off'我得到以下结果:

"Bitmap Heap Scan on content  (cost=17.94..168.53 rows=249 width=4) (actual time=0.145..0.323 rows=289 loops=1)"
"  Recheck Cond: (to_tsvector('danish'::regconfig, text) @@ '''felt'''::tsquery)"
"  Heap Blocks: exact=70"
"  ->  Bitmap Index Scan on content_idx  (cost=0.00..17.87 rows=249 width=0) (actual time=0.121..0.121 rows=289 loops=1)"
"        Index Cond: (to_tsvector('danish'::regconfig, text) @@ '''felt'''::tsquery)"
"Planning time: 0.373 ms"
"Execution time: 0.383 ms"
Run Code Online (Sandbox Code Playgroud)

到底发生了什么,需要调整哪些参数才能更好地运行。我不喜欢从查询规划器工具箱中删除工具的想法。就目前而言,该设置正在运行股票 PostgreSQL 9.4.4

jja*_*nes 8

这里的问题是它认为这to_tsvector是一个非常便宜的操作,即使在整个表上执行它也是如此。基本上,它认为它与两个整数相加的成本相同。但当然不是。在即将发布的 9.5 版本中,该函数的默认成本增加了 100 倍(这可能仍然不够准确……但它应该足以为您的情况调整规模,这就是您所需要的) .

您可以自己更改该功能的成本:

alter function to_tsvector ( regconfig, text) cost 1000;
Run Code Online (Sandbox Code Playgroud)

(请注意,因为这是一个内置函数,您所做的更改将无法在pg_upgrade、或转储、initdb 和恢复循环中继续存在)

这比摆弄全局成本参数要安全得多。

通用(全局)成本参数在此处描述,特定功能的成本参数在此处描述。文档中的任何地方似乎都没有很好地描述两者相互作用的方式。


Chr*_*ris 6

我自己曾经遇到过这个问题,对于我的情况,我能够通过将 设置random_page_cost为仅查询的低值来修复它,如

SET random_page_cost = 0.01;
Run Code Online (Sandbox Code Playgroud)

现在,这当然会使您的随机页面成本降低,您可能不想保持这种状态。因此,您可以在本地为单个交易执行此操作

BEGIN;

SET LOCAL random_page_cost = 0.01;

SELECT id
FROM content
WHERE to_tsvector('danish', text) @@ to_tsquery('danish','felter');

COMMIT;
Run Code Online (Sandbox Code Playgroud)

就我而言,这解决了问题,并允许我“破解”查询并强制进行位图扫描。

如果这确实解决了您的问题,您也可以将其构建为一个函数:

CREATE OR REPLACE FUNCTION matched_ids(in_text text)
RETURNS SETOF content.id%TYPE AS
$$

  SET LOCAL random_page_cost = 0.01;

  SELECT id
  FROM content
  WHERE to_tsvector('danish', text) @@ to_tsquery('danish',in_text);

$$ LANGUAGE SQL;
Run Code Online (Sandbox Code Playgroud)

然后调用它使用

SELECT * FROM matched_ids('felter');
Run Code Online (Sandbox Code Playgroud)