当前位置: 首页 > 知识库问答 >
问题:

sql - 关于PostgreSQL部分索引的疑问?

戚阳曜
2023-08-17

PostgreSQL 官方文档关于部分索引给了以下一个示例:

Example 11.2. Setting up a Partial Index to Exclude Uninteresting Values

If you have a table that contains both billed and unbilled orders, where the unbilled orders take up a small fraction of the total table and yet those are the most-accessed rows, you can improve performance by creating an index on just the unbilled rows. The command to create the index would look like this:

CREATE INDEX orders_unbilled_index ON orders (order_nr)    WHERE billed is not true;

A possible query to use this index would be:

SELECT * FROM orders WHERE billed is not true AND order_nr < 10000;

好奇针对未开票的订单,直接在 billed 字段上针对 not true 部分创建索引不是更好吗?

CREATE INDEX orders_unbilled_index ON orders (billed)    WHERE billed is not true;

官方示例却在 order_nr 字段上创建部分索引,这里是有什么讲究吗?求大佬指教 ~

共有2个答案

邓昀
2023-08-17

你没明白它这个 Partial Index 特性的意图。

先忽略它的这个具体的例子,你现在先这么想:

首先,你现在有一张大表 R,其中有部分字段是经常会在出现的查询条件里的,这些字段我们叫它 P 吧。于是你想到了给 P 加上索引。

接着,你发现虽然是在查询这张大表 R,但其实只有其中的某些行(我们可以管这部分数据集合叫 R1)才是高频访问的。而前面 P 加的索引,是对全表 R 生效的,这样其实有很多是浪费了的,因为索引本身存储需要空间、插入和更新时也会有额外开销

那么,自然而然想到,有没有办法只针对 R1 这部分数据的 P 才加索引,而不是对全表 R 的 P 都加索引呢?

这就是 Partial Index。

回到你题目中的例子上,“orders” 就是大表 R,“orders WHERE billed is not true” 大表的子集 R1,“order_nr” 是 P。


至于为什么要多一步 R → R1、然后再加 P,而不是把 P 范围扩大化、然后直接给 R 加,前面已经说了,因为索引本身是有开销的。

例子中已经说了,只有未开票订单才是高频访问的,言外之意就是已开票订单有没有索引其实不重要。给想给 billed 设索引,确实有一定效果,但缺点很明显,那就是你这么做已开票订单这个字段同样也有了索引的开销(注意前文加粗部分)。


当然了,如果是 MySql 这种没有 Partial Index 特性的数据库,你还真的确实需要给 billed 加个索引。

牟正真
2023-08-17

第一个索引根据order_nr字段,只包括billed为false的行,这个可以快速定位到没开票的订单的行,第二个是可以查所有没开票的订单,但是加上一些过滤条件的话可能性能没第一个好,取决于你的需求

 类似资料:
  • 我做错了什么?我应该使用吗? 用于允许推断部分唯一索引的index_predicate。可以推断出满足谓词的任何索引(实际上不必是部分索引)。遵循创建索引格式。https://www.PostgreSQL.org/docs/9.5/static/sql-insert.html

  • 索引是加速搜索引擎检索数据的一种特殊表查询。简单地说,索引是一个指向表中数据的指针。一个数据库中的索引与一本书的索引目录是非常相似的。 拿汉语字典的目录页(索引)打比方,我们可以按拼音、笔画、偏旁部首等排序的目录(索引)快速查找到需要的字。 索引有助于加快 SELECT 查询和 WHERE 子句,但它会减慢使用 UPDATE 和 INSERT 语句时的数据输入。索引可以创建或删除,但不会影响数据。

  • 以下代码在 chrome 输出 1,2,3 这个在网上找到了,forEach 一开始就已经获取了 数组长度 The range of elements processed by forEach is set before the first call to callbackfn. Elements which are appended to the array after the call to

  • 在我的一个项目中,我有一个表,其中保存了某种设备的固件更新信息。最初,任何固件更新进程都处于排队状态。更新过程可能有其他状态值,例如正在进行、已完成、失败。对于单个设备,可能存在状态为“已完成”和“已失败”的多行(已完成的更新过程,最终状态!)。但在任何时候,处于排队或正在进行状态的每个设备都必须只有一个更新过程——新固件的推出应该只适用于没有“活动/非最终”更新过程的设备。我试图用Postgre

  • 问题内容: 尝试在PostgreSQL上重新创建我的SQL Server数据库。一切正常,除了我找不到如何重新创建此索引: 将非常感谢您的帮助。 阿列克谢 更新: http://img38.imageshack.us/img38/1071/89013974.png这是db结构star + eav ,只有一个查询 也许这不是最佳的atm。我也正在努力。也许是这样的 任何提示欢迎=) 问题答案: 不支

  • 问题内容: 我想使用Postgres 9.4 在json列上创建一个索引,该索引将在搜索列中的特定键时使用。 例如,我有一个带有json列“ animals”的“农场”表。 animals列具有通用格式的json对象: 我已经尝试了多个索引(分别): 我想运行如下查询: 并让该查询使用索引。 当我运行此查询时: 那么(1)索引就可以了,但是我无法获得任何索引来解决不平等问题。 这样的索引可能吗?