关于postgresql 9.1中INDEX + ORDER BY + LIMIT + TRIGRAM的说明

时间:2014-02-06 19:34:59

标签: sql postgresql indexing postgresql-9.1 sqlperformance

表:

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)

1 个答案:

答案 0 :(得分:0)

  

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

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

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

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

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

当你完成时,你会读完整个索引并多次访问书中的每一页。阅读本书,封面以及随后对内容进行排序本来会更快(特别是如果你是一个数据库,它具有比人类更大的短期记忆并且可以轻松地在其内存中对大型列表进行排序)。

这正是数据库中发生的事情。计算机按顺序读取磁盘文件更有效,因为它不需要来回寻找磁头。它一次读取整个页面。它在某些方面也比我们人类有一些优势 - 小小的短期记忆意味着它可以同时在其内存中保存数千页。但是一张大桌子和/或繁重的工作量会打败那个。

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

您可能认为这种简单的类比不适用于三元组索引,但确实如此。索引不是字母,但构建排序列表的机制是相同的 - 除了并非所有索引类型都适合在任何情况下返回已排序的行。许多索引类型允许您快速查找内容,但不保持键的顺序。在内置索引类型中,只有b-tree适合返回已排序的数据。我实际上有点意外的是,三元组索引可用于此。但它取决于ORDER表达式 - 我猜这个索引确实在&lt; - &gt;中返回数据顺序。

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

如果您使用的是Postgresql 9.2,则可以使用index-only次扫描。在您的查询中,您正在选择所有列,这意味着它无法使用仅索引扫描,并且在任何情况下我都不认为您将能够使用具有trigram索引的仅索引扫描。

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

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

与随机访问数据相比,您可以调整计划程序用于估计顺序读取数据的相对成本的参数。您可以切换到使用固态磁盘而不是旧式旋转磁盘。

当然,更多RAM从不会伤害数据库。