我有一个非常简单的表:
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
这里的问题是它认为这to_tsvector是一个非常便宜的操作,即使在整个表上执行它也是如此。基本上,它认为它与两个整数相加的成本相同。但当然不是。在即将发布的 9.5 版本中,该函数的默认成本增加了 100 倍(这可能仍然不够准确……但它应该足以为您的情况调整规模,这就是您所需要的) .
您可以自己更改该功能的成本:
alter function to_tsvector ( regconfig, text) cost 1000;
Run Code Online (Sandbox Code Playgroud)
(请注意,因为这是一个内置函数,您所做的更改将无法在pg_upgrade、或转储、initdb 和恢复循环中继续存在)
这比摆弄全局成本参数要安全得多。
通用(全局)成本参数在此处描述,特定功能的成本参数在此处描述。文档中的任何地方似乎都没有很好地描述两者相互作用的方式。
我自己曾经遇到过这个问题,对于我的情况,我能够通过将 设置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)
| 归档时间: |
|
| 查看次数: |
1557 次 |
| 最近记录: |