7

我有下表:

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

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

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

CREATE INDEX IDX_RecipeMetadata_GlutenFree ON RecipeMetadata(diet_glutenfree) WHERE diet_glutenfree;

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

我应该在子句中添加一个运算符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)'

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

4

2 回答 2

4

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

我重新创建了随机数据,只是这次设置diet_glutenfreerandom() > 0.9所以只有 10% 的机会on

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

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,所以看起来它肯定是部分的。

于 2011-12-15T06:54:56.267 回答
1

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

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

于 2011-12-17T12:56:14.510 回答