【问题标题】:Postgres - Is this the right way to create a partial index on a boolean column?Postgres - 这是在布尔列上创建部分索引的正确方法吗?
【发布时间】:2011-12-15 03:56:59
【问题描述】:

我有下表:

CREATE TABLE recipemetadata
(
  --Lots of columns
  diet_glutenfree boolean NOT NULL,
);

大多数每一行都将设置为FALSE,除非有人想出一些疯狂的新无麸质饮食风靡全国。

我需要能够非常快速地查询该值为 true 的行。我已经创建了索引:

CREATE INDEX IDX_RecipeMetadata_GlutenFree ON RecipeMetadata(diet_glutenfree) WHERE diet_glutenfree;

它似乎有效,但是我不知道如何判断它是否确实只是索引值为 true 的行。我想确保它不会做一些愚蠢的事情,比如索引任何具有任何值的行。

我应该在WHERE 子句中添加一个运算符,还是这个语法完全有效?希望这不是那些会被否决 30 次的超级简单的 RTFM 问题之一。

更新:

我已经开始向 RecipeMetadata 添加了 10,000 行随机值。然后我在桌子上做了一个分析和一个 REINDEX 来确定。当我运行查询时:

select recipeid from RecipeMetadata where diet_glutenfree;

我明白了:

'Seq Scan on recipemetadata  (cost=0.00..214.26 rows=5010 width=16)'
'  Filter: diet_glutenfree'

因此,尽管只有大约一半的行具有此标志,但它似乎正在对表进行顺序扫描。索引被忽略。

如果我这样做:

select recipeid from RecipeMetadata where not diet_glutenfree;

我明白了:

'Seq Scan on recipemetadata  (cost=0.00..214.26 rows=5016 width=16)'
'  Filter: (NOT diet_glutenfree)'

所以无论如何,这个索引并没有被使用。

【问题讨论】:

  • 请从存档中添加一个指向您的 PostgreSQL 邮件列表帖子的链接,以便人们可以将这个讨论与那个讨论联系起来。如果您也可以在邮件列表帖子中发布一个带有此链接的后续内容,那就太好了。如果您要在多个地方交叉发布,请说明以防止人们重复工作。
  • 没问题,我以后会这样(我一般不会在这两个地方发帖)..
  • 顺便说一句,我认为您的问题的简短回答是“是”...但是如果您担心,请在表格中填写一些虚拟数据,ANALYZE 表格,然后使用 @987654330 @ 检查应该命中部分索引的一些查询的计划。
  • 是的,现在确实这样做了..

标签: sql postgresql postgresql-9.1


【解决方案1】:

我已确认索引按预期工作。

我重新创建了随机数据,只是这次将diet_glutenfree 设置为random() > 0.9,因此on 位的可能性只有 10%。

然后我重新创建索引并再次尝试查询。

SELECT RecipeId from RecipeMetadata where diet_glutenfree;

返回:

'Index Scan using idx_recipemetadata_glutenfree on recipemetadata  (cost=0.00..135.15 rows=1030 width=16)'
'  Index Cond: (diet_glutenfree = true)'

还有:

SELECT RecipeId from RecipeMetadata where NOT diet_glutenfree;

返回:

'Seq Scan on recipemetadata  (cost=0.00..214.26 rows=8996 width=16)'
'  Filter: (NOT diet_glutenfree)'

我的第一次尝试似乎被污染了,因为 PG 估计如果它必须加载超过一半的行,扫描整个表而不是命中索引会更快。

但是,我想我会在列的完整索引上得到这些确切的结果。有没有办法验证部分索引中索引的行数?

更新

索引大约是 40k。我为同一列创建了一个完整的索引,它超过了 200k,所以看起来它肯定是部分的。

【讨论】:

  • 是的,继续。 “大约一半”的行不会导致 Pg 支持索引。在索引扫描比 seqscan 更快之前,您需要比 50% 更好的选择性。
  • 非常感谢!我还创建了一个完整的索引来比较大小。它肯定按预期工作。
  • 注意:您似乎只有 10K 条记录。您查询的“工作集”可能适合核心。您执行的优化是在 cpu 使用方面的优化。一旦“工作集”大于可用缓冲区空间,您的查询将成为 I/O 绑定,并且索引将不再为您提供帮助(除非您的行太大以至于只有几行适合磁盘页面)。
【解决方案2】:

一位字段的索引没有意义。为了理解计划者所做的决定,您必须从页面而不是行来考虑。

对于 8K 页面和(预计)80 行大小,每页有 100 行。假设一个随机分布,一个页面只包含具有true 值的行的机会是可以忽略的,pow (0.5, 100),大约 1e-33,IICC。 (当然对于“假”也是如此)因此对于gluten_free == true 上的查询,无论如何都必须获取每个 页面,然后进行过滤。使用索引只会导致 更多 个页面(:索引)被获取。

【讨论】:

  • “一位字段的索引没有意义”。 Postgres bool 需要 8 位存储空间:postgresql.org/docs/8.4/static/datatype-boolean.html“假设随机分布”——这可能是一个很大的假设。远低于 50% 的食物通常不含麸质。有见地的回应,无论如何。
  • “一位字段”是关于信息内容,而不是关于所需的存储大小。可能有一种存储结构可以有效地存储/索引/检索位域(想想:judy-trees),这些可能需要更少的磁盘页面来获取,但很难将它们与 RDBMS 的 ATOM 要求结合起来。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多