0

桌子:

CREATE TABLE msp_adm_munic_complet_g_01
(
  nom_tri character varying(64),
  ogc_fid serial NOT NULL
)

指数:

CREATE INDEX idx_gist_msp_adm_munic_complet_g_nom_tri
  ON msp_adm_munic_complet_g_01
  USING gist
  (nom_tri COLLATE pg_catalog."default" gist_trgm_ops);

询问:

select * from msp_adm_munic_complet_g_01
ORDER BY 'potato'<->nom_tri
LIMIT 25;

问题:

为什么它通过 ORDER BY + LIMIT 组合的索引而不是当查询仅包含 ORDER BY 时?

当然,使用索引会提高查询速度

我发现的唯一解释是: http ://www.postgresql.org/docs/9.1/static/indexes-ordering.html

但它缺乏细节

编辑#1:

带有 LIMIT 的查询计划:

Limit  (cost=0.00..19.27 rows=25 width=590)
  ->  Index Scan using idx_gist_msp_adm_munic_complet_g_nom_tri on
msp_adm_munic_complet_g_01  (cost=0.00..2784.49 rows=3612 width=590)
      Order By: ((nom_tri)::text <-> 'potato'::text)

没有限制的查询计划:

Sort  (cost=1847.59..1856.62 rows=3612 width=590)
  Sort Key: (('potato'::text <-> (nom_tri)::text))
  ->  Seq Scan on msp_adm_munic_complet_g_01  (cost=0.00..682.15 rows=3612 width=590)
4

1 回答 1

0

当然,使用索引会提高查询速度

我认为这是问题的关键。没有关于它的“当然”。

想象你有一本大书。这本书的背面有一个索引,列出了不同的术语和它们出现的页码。

你的老板来找你说“我希望你按字母顺序列出书中的前 10 个术语,并写下关于它们的所有内容”。您可以从索引开始,然后转到针对您找到的前 10 个术语列出的每个页面。不会花很长时间。尤其是与阅读整本书并尝试在脑海中对其进行排序,然后找到前 10 个的替代方案相比。

接下来你的老板来找你,说他希望你按字母顺序列出书中所有的术语及其定义。天真地,您决定使用相同的方法。你会不断地来回翻阅这本书,多次重访每一页。这将需要永远。

当你完成时,你会阅读整个索引并多次访问书中的每一页。如果只是阅读本书,从头到尾,对内容进行排序,会更快(特别是如果你是一个数据库,它的短期记忆比人类大得多,并且可以轻松地对记忆中的大列表进行排序)。

这正是数据库中发生的事情。计算机顺序读取磁盘文件效率更高,因为它不必来回寻找磁盘磁头。它一次读取整页。与我们人类相比,它也有一些优势——巨大的短期记忆意味着它可以一次在它的记忆中保存数千页。但是一张大桌子和/或繁重的工作量会打败它。

因此,数据库在执行每个查询之前都会对其进行分析。它将尝试估计将返回的表的比例,以及它对随机访问页面与顺序访问页面的成本的了解,以及有关表中值分布的其他表统计信息。有时它会说扫描整个表并忘记索引会更有效。

您可能会认为这个简单的类比不适用于三元索引,但它确实适用。索引不是按字母顺序排列的,但构建排序列表的机制是相同的——除了并非所有索引类型都适合在任何情况下返回排序行。许多索引类型允许您快速找到某些内容,但不保持键的顺序。在内置的索引类型中,只有 b-tree 适合返回排序后的数据。实际上,我对 trigram 索引可用于此感到有点惊讶。但这取决于 ORDER 表达式 - 我猜这个索引确实以 <-> 顺序返回数据。

如果按排序顺序遍历行是此表上的常见操作,那么您可以采取一些措施使其运行得更快。

如果您使用的是 Postgresql 9.2,您可能能够使用仅索引扫描。在您的查询中,您选择了所有列,这意味着它不能使用仅索引扫描,并且无论如何我认为您不能将仅索引扫描与三元索引一起使用。

您可以使用CLUSTER命令以与索引相同的顺序排列表(尽管在插入或更新数据时不会保持这种方式,因此需要在经常更新的表中定期进行)。

您可能会发现该表将受益于微调保留在其上的统计信息。更多的统计数据可能会让它更频繁地使用索引。

您可以调整规划器用来估计顺序读取数据与随机访问数据的相对成本的参数。你可以改用固态磁盘而不是老式的旋转磁盘。

当然,更多的 RAM 永远不会损害数据库。

于 2014-02-07T23:02:58.173 回答