在大表中搜索一些结果而不扫描整个表

cha*_*shi 2 postgresql performance performance-tuning

我需要搜索一个非常大的PostgreSQL表(500+M行),我想限制返回的搜索结果,但是使用“limit”关键字并不能阻止对整组数据的搜索(正确吗?)

想象一下我的搜索结果包含 1M 行,但我只需要搜索结果中的前 100 条记录!PostgreSQL 数据库是否必须在内存中临时创建这 1M 搜索结果行,然后给我所需的 100 个结果?

或者有什么办法告诉PostgreSQL一旦找到100条记录就停止搜索?

这是我的表,当然还没有填充 500M 记录!

CREATE TABLE con
(
  id bigserial NOT NULL,
  tag1 integer NOT NULL DEFAULT 0,
  tag2 integer NOT NULL DEFAULT 0,
  ref1 integer NOT NULL DEFAULT 0,
  ref2 integer NOT NULL DEFAULT 0,
  CONSTRAINT con_pkey PRIMARY KEY (id)
)
Run Code Online (Sandbox Code Playgroud)

以及测试查询的解释分析:

explain analyze SELECT * FROM con where tag1 = '64813' and tag2 = '80'
Run Code Online (Sandbox Code Playgroud)
Seq Scan on con  (cost=0.00..3215204.72 rows=2470 width=112) (actual time=0.016..36970.528 rows=7505 loops=1)
   Filter: ((tag1 = 64813) AND (tag2 = 80))
  Rows Removed by Filter: 152519685
Total runtime: 36972.921 ms
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 5

但使用“limit”关键字并不能阻止对整组数据的搜索(正确吗?)

正确的; 它只会限制返回的结果数量。

对于某些类型的查询,它还可以限制首先扫描的数量,但在一般情况下您不能依赖它。

PostgreSQL 数据库是否必须在内存中临时创建这 1M 搜索结果行,然后给我所需的 100 个结果?

创建,是的。记忆中,不一定。它通常会溢出到磁盘,或者丢弃不需要的结果,因此它只保留前 100 个。这取决于查询的详细信息。

或者有什么办法告诉PostgreSQL一旦找到100条记录就停止搜索?

在可能的情况下编写一个查询。您尚未显示查询或架构,因此这部分无法有效回答。

一般来说,如果您有ORDER BY某种搜索相关字段,则必须搜索整个数据集,然后过滤前 n 个结果。

简而言之:“这取决于”。具体来说,它取决于架构、可用索引以及您正在搜索的内容以及您想要的结果。

这:

SELECT id 
FROM mytable 
WHERE somefield > 100 
ORDER BY somefield DESC
LIMIT 100;
Run Code Online (Sandbox Code Playgroud)

如果 上有索引,则只会扫描所需的行mytable(somefield DESC)

这:

SELECT id, title
FROM mytable
WHERE title LIKE '%something%'
ORDER BY calculate_relevance(title, 'something')
LIMIT 100;
Run Code Online (Sandbox Code Playgroud)

总是会扫描整个表,这既是因为中缀文本模式匹配 ( LIKE '%blah%') 不能使用 b 树索引,也是因为您无法在采用文字参数的函数上创建表达式索引(如虚函数的情况calculate_relevance)多于。

所以...这完全取决于您正在寻找什么以及如何寻找。


这个答案对你来说是否过于笼统和笼统?所以问题来了。提供具体信息,您将得到更具体的答案。对于此类事情来说,包含示例数据的模式的 http://sqlfiddle.com/ 加上您的 PostgreSQL 版本、预期结果表以及您想要查找的内容的描述通常是最少的


更新:这里有一些问题。

  • tag1和/或上没有索引,tag2因此 Pg 必须对表进行 seqscan,搜索它直到找到 100 个结果。这是极其低效的。

  • 没有ORDER BY,因此 PostgreSQL 可以返回 a 的任何结果LIMIT,并以任何顺序返回它们。

  • 您的架构显示出不必要的非规范化迹象。tag1tag2等通常表明表格设计不佳。我强烈建议您学习关系数据库设计和规范化

在这种特定情况下,如果您这样做,您将能够避免全表扫描CREATE INDEX con_tag1_tag2_idx ON con(tag1, tag2)。但这仅适用于使用tag1和 可选的搜索tag2它对于搜索 just 、 search for没有多大帮助tag2ref1。(感谢 Erwin 关于多列索引使用的重要说明,其中不包括第一列,这对我来说是一个惊喜)。

不要创建大量索引。每个都使用磁盘空间并需要磁盘 I/O 来插入、更新和删除。

答案通常是适当的标准化。

总的来说,我认为你需要购买/借一些关于关系数据库设计和基础到中级 SQL 的优秀入门书籍,最好以 PostgreSQL 为重点,并进行一些研究。