在 PostgreSQL 中索引空值
Posted
技术标签:
【中文标题】在 PostgreSQL 中索引空值【英文标题】:Indexing Null Values in PostgreSQL 【发布时间】:2011-03-28 22:25:16 【问题描述】:我有一个表格查询:
select m.id from mytable m
left outer join othertable o on o.m_id = m.id
and o.col1 is not null and o.col2 is not null and o.col3 is not null
where o.id is null
查询返回几百条记录,尽管这些表有数百万行,并且运行需要很长时间(大约一个小时)。
当我使用以下方法检查我的索引统计信息时:
select * from pg_stat_all_indexes
where schemaname <> 'pg_catalog' and (indexrelname like 'othertable_%' or indexrelname like 'mytable_%')
我看到只有 othertable.m_id 的索引被使用,而 col1..3 的索引根本没有被使用。这是为什么呢?
我在fewplaces 中读到,PG 传统上无法索引 NULL 值。但是,我读过这自 PG 8.3 以来应该有所改变?我目前在 Ubuntu 10.04 上使用 PostgreSQL 8.4。我是否需要专门创建一个“部分”或“功能”索引来加速 IS NOT NULL 查询,还是它已经索引 NULL 而我只是误解了这个问题?
【问题讨论】:
【参考方案1】:你可以试试部分索引:
CREATE INDEX idx_partial ON othertable (m_id)
WHERE (col1 is not null and col2 is not null and col3 is not null);
来自文档:http://www.postgresql.org/docs/current/interactive/indexes-partial.html
【讨论】:
这对我来说非常有效。需要几分钟才能运行的测试查询现在使用此索引只需几秒钟即可运行。【参考方案2】:部分索引在这里对您没有帮助,因为它们只会找到您不想要的记录。您想创建一个包含您想要的记录的索引。
CREATE INDEX findDaNulls ON othertable ((COALESCE(col1,col2,col3,'Empty')))
WHERE col1 IS NULL AND col2 IS NULL AND col3 IS NULL;
SELECT *
FROM mytable m
JOIN othertable o ON m.id = o.m_id
WHERE COALESCE(col1,col2,col3,'Empty') = 'Empty';
顺便说一句,搜索空左连接通常不如在 Postgres 中使用 EXISTS 或 NOT EXISTS 快。
【讨论】:
这是一个有趣的想法,但不完全符合我的逻辑。您的解决方案会查找 all 列为 NULL 的所有 othertables 记录。在我的示例中,我对 至少 一列为 NULL 的所有记录感兴趣。【参考方案3】:我首先想到的是 m_id、col1、col2 和 o.col3 上的单个索引。
并在此查询上使用EXPLAIN 以查看它是如何执行的,以及什么需要这么多时间。您可以向我们展示结果以帮助您。
【讨论】:
【参考方案4】:partial index 似乎是正确的方式:
如果您有一个包含两者的表 已开票和未开票的订单,其中 未开单的订单占小 总表的一小部分,但 这些是访问次数最多的行,你 可以通过创建一个 仅对未开票的行编制索引。
也许这些可为空的列 (col1,col2,col3) 在您的场景中充当某种标志来区分表中的某些记录子类? (例如,某种“逻辑删除”)?在这种情况下,除了部分索引解决方案之外,您可能更愿意重新考虑您的设计,并将它们放在不同的物理表中(可能使用继承),一个用于“实时记录”,另一个用于“历史记录”并访问完整集(仅在需要时)通过视图。
【讨论】:
【参考方案5】:您是否尝试在 othertable(m_id, col1, col2, col3) 上创建组合索引?
您还应该检查执行计划(使用 EXPLAIN)而不是检查系统表的索引使用情况。
PostgreSQL 9.0(目前处于测试阶段)将能够使用 IS NULL 条件并为其编制索引。该功能被推迟了
【讨论】:
你有参考吗?以上是关于在 PostgreSQL 中索引空值的主要内容,如果未能解决你的问题,请参考以下文章