在 Postgresql 中索引外键

2024-02-14

像许多 Postgres 一样n00bs我们有很多带有外键约束但未建立索引的表。在某些情况下,这不会对性能造成很大影响 - 但这需要进一步分析。

我读过以下文章:https://www.cybertec-postgresql.com/en/index-your-foreign-key/ https://www.cybertec-postgresql.com/en/index-your-foreign-key/

并使用以下查询查找所有没有索引的外键:

SELECT c.conrelid::regclass AS "table",
       /* list of key column names in order */
       string_agg(a.attname, ',' ORDER BY x.n) AS columns,
       pg_catalog.pg_size_pretty(
          pg_catalog.pg_relation_size(c.conrelid)
       ) AS size,
       c.conname AS constraint,
       c.confrelid::regclass AS referenced_table
FROM pg_catalog.pg_constraint c
   /* enumerated key column numbers per foreign key */
   CROSS JOIN LATERAL
      unnest(c.conkey) WITH ORDINALITY AS x(attnum, n)
   /* name for each key column */
   JOIN pg_catalog.pg_attribute a
      ON a.attnum = x.attnum
         AND a.attrelid = c.conrelid
WHERE NOT EXISTS
        /* is there a matching index for the constraint? */
        (SELECT 1 FROM pg_catalog.pg_index i
         WHERE i.indrelid = c.conrelid
           /* the first index columns must be the same as the
              key columns, but order doesn't matter */
           AND (i.indkey::smallint[])[0:cardinality(c.conkey)-1]
               @> c.conkey::int[])
  AND c.contype = 'f'
GROUP BY c.conrelid, c.conname, c.confrelid
ORDER BY pg_catalog.pg_relation_size(c.conrelid) DESC;

这向我展示了具有复合唯一约束的表,只有唯一索引中的“一”列:

\d topics_items;
-----------------+---------+--------------+---------------+------------------------------
 topics_items_id | integer |              | not null      | generated always as identity
 topic_id        | integer |              | not null      |
 item_id         | integer |              | not null      |
Index:
    "topics_items_pkey" PRIMARY KEY, btree (topics_items_id)
    "topic_id_item_id_unique" UNIQUE CONSTRAINT, btree (topic_id, item_id)
Foreign Keys:
    "topics_items_item_id_fkey" FOREIGN KEY (item_id) REFERENCES items(item_id) ON DELETE CASCADE
    "topics_items_topic_id_fkey" FOREIGN KEY (topic_id) REFERENCES topics(topic_id) ON DELETE CASCADE

在这种情况下,检查查询仅找到item_id而不是topic_id作为未索引字段。

公平地说,这只是所使用的查询的问题,我必须单独索引两个字段(topic_id 和 item_id) - 或者是否涉及一些黑色巫术并且只有item_id需要索引吗?


tl;dr您需要添加索引item_id。 Postgres 索引的“黑魔法”包含在11. 索引 https://www.postgresql.org/docs/11/indexes.html.

您有一个综合索引(topic_id, item_id)列顺序很重要。 Postgres 可以使用它来索引查询topic_id,对两者进行查询topic_id and item_id,但不是(或效率较低)item_id alone.

From 11.3。多列索引 https://www.postgresql.org/docs/11/indexes-multicolumn.html...

多列 B 树索引可与涉及索引列的任何子集的查询条件一起使用,但当前导(最左边)列存在约束时,索引效率最高。

-- indexed
select *
from topics_items
where topic_id = ?

-- also indexed
select *
from topics_items
where topic_id = ?
  and item_id = ?

-- probably not indexed
select *
from topics_items
where item_id = ?

这是因为像这样的复合索引(topic_id, item_id)首先存储主题 ID,然后存储也具有该主题 ID 的项目 ID。为了在此索引中有效地查找项目 ID,Postgres 必须首先使用主题 ID 缩小搜索范围。


Postgrescan如果认为值得付出努力,则反转索引。如果可能的主题 ID 较少,而可能的索引 ID 较多,则会在每个主题 ID 中搜索索引 ID。

例如,假设您有 10 个可能的主题 ID 和 1000 个可能的项目 ID 以及您的索引(topic_id, index_id)。这就像有 10 个明确标记的主题 ID 桶,每个桶内有 1000 个明确标记的项目 ID 桶。要获取项目 ID 存储桶,它必须查看每个主题 ID 存储桶内部。要使用该索引where item_id = 23Postgres 必须在 10 个主题 ID 存储桶中的每一个中搜索项目 ID 为 23 的所有存储桶。

但是,如果您有 1000 个可能的主题 ID 和 10 个可能的项目 ID,Postgres 将必须搜索 1000 个主题 ID 存储桶。它很可能会进行全表扫描。在这种情况下,您需要反转索引并使其(item_id, topic_id).

这在很大程度上取决于良好的表统计数据,这意味着确保 autovacuum 正常工作。

因此,如果一列的可变性远小于另一列,那么您可以对两列使用单个索引。


如果 Postgres 认为可以使查询运行得更快,它也可以使用多个索引 https://www.postgresql.org/docs/11/indexes-bitmap-scans.html。例如,如果您有一个索引topic_id和一个索引item_id, it can使用两个索引并合并结果。例如where topic_id = 23 or item_id = 42可以使用 topic_id 索引搜索主题 ID 23,使用 item_id 索引搜索项目 ID 42,然后合并结果。

这通常比使用复合材料要慢(topic_id, item_id)指数。它也可能比使用单个索引慢,因此如果 Postgres 决定不使用多个索引,请不要感到惊讶。


一般来说,对于 B 树索引,当您有两列时,您有三种可能的组合。

  • a + b
  • a
  • b

并且您需要两个索引。

  • (a, b) -- a 和 a + b
  • (b) -- b

(a, b)涵盖 a 和 a + b 的搜索。(b)涵盖搜索b.

当您有三列时,您有七种可能的组合。

  • a+b+c
  • a + b
  • a + c
  • a
  • b + c
  • b
  • c

但你只需要三个索引。

  • (a, b, c) -- a, a + b, a + b + c
  • (b, c) -- b, b + c
  • (c, a) -- c, c + a

但是,您可能实际上希望避免在三列上建立索引。经常是这样slower。你真正想要的是这个。

  • (a, b)
  • (b, c)
  • (c, a)

应谨慎使用多列索引。在大多数情况下,单列上的索引就足够了,并且节省空间和时间。除非表的使用非常程式化,否则具有超过三列的索引不太可能有帮助。

从索引读取比从表读取慢。您希望索引减少必须读取的行数,但不希望 Postgres 执行不必要的索引扫描。

右侧列的约束...在索引中进行检查,因此它们可以节省对表的访问,但不会减少必须扫描的索引部分。例如,给定 (a, b, c) 上的索引和查询条件 WHERE a = 5 AND b >= 42 AND c = 77 的索引条目将被跳过,但仍然必须扫描它们。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Postgresql 中索引外键 的相关文章

  • 从 call_log 中获取最大并发通话数

    我需要帮助在 MySQL 5 0 77 中编写一个查询 根据下面所示的数据 办公室一天的通话量 返回并发电话呼叫的峰值数量 我只是想知道一天中任何特定时间同时打电话的人数最多是多少 首先 这是 MySQL 表 CREATE TABLE ca
  • SQL 标准是否允许函数名和括号之间有空格

    检查一些 RDBMS 我发现类似的事情 SELECT COUNT a SUM b FROM TABLE 允许 注意聚合函数和括号之间的空格 谁能提供一个指向 SQL 标准本身定义的指针 任何版本都可以 编辑 以上在postgres中工作 m
  • 没有提示指令的直连接中表的顺序是否会影响性能?

    所有基于 SQL 的 RDBMS 10 年前的版本 直接连接查询 没有提示指令 中的表顺序是否会对最佳性能和内存管理产生影响 听说最后一个join应该是最大的表 您的数据库的查询优化器如何处理这种情况 回答你的问题 是的 表的顺序在连接中有
  • 解析错误:语法错误,意外的 T_RETURN [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 遇到这个问
  • 处理与不同相关实体的一对多的正确模式

    我有一个 C 项目 我使用实体框架作为 ORM 我有一个User 可以向多家银行付款 每家银行都是一个独立的实体 并且每家银行都由不同的字段描述 问题是 一User可以没有或有很多不同的Banks 我不太确定如何对此进行建模 临时解决方案是
  • SELECT 在 PL/pgSQL 函数中引发异常

    我想在函数内实现循环 但收到此错误 ERROR 查询没有结果数据的目标 代码 CREATE OR REPLACE FUNCTION my function ill int ndx bigint RETURNS int AS DECLARE
  • Postgres - 即使我的角色/用户已被授予“读取”权限,也无法从表中“选择”

    我在 postgres 上有一个管理员角色 用户和一个开发人员角色 开发人员角色继承了我为将来方便而创建的 readaccess 角色的属性 如果我运行 du 我得到 Role name Attributes Member of devel
  • SQL:如何从一个表中获取另一个表中每一行的随机行数

    我有两个数据不相关的表 对于表 A 中的每一行 我想要例如表 B 中的 3 个随机行 使用光标这相当容易 但速度非常慢 那么我该如何用单个语句来表达这一点以避免 RBAR 呢 要获得 0 到 N 1 之间的随机数 可以使用 abs chec
  • 支持 >65k 行的 Excel VBA SQL 驱动程序

    在 Excel 2010 中通过 VBA 查询 Excel 数据时 我遇到一个有趣的问题 我正在使用这些驱动程序连接到 xls 或 xls x m 文件 Sub OpenCon ByRef theConn As Connection ByV
  • 向带有检查约束 SQL 的表添加列

    我想向表中添加一列 然后添加一个检查约束以确保其大于 0 我似乎无法让它在 oracle sl Developer 中运行 Alter TABLE store101 add column Base salary Number 7 2 con
  • 计算2个日期之间每个日期的记录数

    我必须创建一个查询来返回多轴图表的结果 我需要计算为 2 个日期之间的每个日期创建的 ID 数量 我试过这个 DECLARE StartDate datetime2 7 11 1 2020 EndDate datetime2 7 2 22
  • PostgreSQL:删除数据库但数据库仍然存在[重复]

    这个问题在这里已经有答案了 我是 PostgreSQL 的新手 我尝试着理解它 我熟悉数据库和MySQL 我正在尝试删除我创建的数据库 因为 psql 似乎忽略了我尝试通过 Django 推送的更改 当我执行时 l我得到以下回复 List
  • Django 独特的不工作

    我在从查询中过滤掉重复项时遇到问题 我正在使用 Django 1 4 和 Postgres 8 4 13 我在我的模型对象上使用这个查询 它是一个 jquery 自动完成 term request GET get term field re
  • 如何使用 MySQL 选择有特定值的 2 个连续行?

    我正在构建一个系统 该系统应该显示学生何时连续缺席两天 例如 此表包含缺勤情况 day id missed 2016 10 6 1 true 2016 10 6 2 true 2016 10 6 3 false 2016 10 7 1 tr
  • Rails 的多个数据库不适用于远程数据库

    我有一个远程只读 postgres 数据库 它是通过 docker 实例维护的卡尔达诺数据库同步 https github com input output hk cardano db sync 我设法将开发数据库连接到它 它工作正常 但由
  • 从表中选择行,其中另一个表中具有相同 id 的行在另一列中具有特定值

    在 MySQL 中 如果我们有两个表 comments key value 1 foo 2 bar 3 foobar 4 barfoo and meta comment key value 1 1 2 1 3 2 4 1 我想得到来自以下人
  • 如何在 SQL Server 2012 中选择除一列之外的所有列? [复制]

    这个问题在这里已经有答案了 有没有一种方法可以选择所有列 但只选择我不想选择的特定列 我的意思是有时我会遇到这样的问题 表有数百个字段 而我只需要删除一个字段 我需要重写所有列吗 有什么窍门吗 喜欢select
  • “WHERE”处或附近的语法错误

    创建 postgres 函数时会导致错误 如下所示 错误 WHERE 处或附近的语法错误 第 19 行 其中 s shift id shiftid 错误 错误 WHERE 处或附近的语法错误 SQL状态 42601 人物 108 请帮忙 C
  • 如何使用 SQL 查询创建逗号分隔的列表?

    我有 3 个表 名为 应用程序 ID 名称 资源 id 名称 应用程序资源 id app id resource id 我想在 GUI 上显示所有资源名称的表格 在每一行的一个单元格中 我想列出该资源的所有应用程序 以逗号分隔 所以问题是
  • 替换字符串中的多个字符,而不使用任何嵌套替换函数

    我的表中存储了一个方程 我一次获取一个方程 并希望将所有运算符替换为任何其他字符 输入字符串 N 100 6858 6858 N 100 0 2 N 35 运算符或模式 替换字符 输出字符串 N 100 6858 6858 N 100 0

随机推荐

  • EJB3 + JEE6:什么是持久计时器?

    我即将使用新的 EJB3 TimerService 作为 Java EE 6 的一部分 并且像往常一样 JavaDoc 的简洁性给我留下了深刻的印象 你知道它的作用是什么吗persistent的财产TimerConfig object Ja
  • 获取 Emacs Lisp 中的 VC 根

    在 Emacs Lisp 函数中 我想知道任意文件夹的 VC 根目录 如果在源代码控制下 就像 vc print root log 那样 我试图从 VC 文件 文件夹外部执行此操作 尽管创建一个临时缓冲区来执行此操作就可以了 我目前通过 m
  • Qemu-KVM:将访客物理地址转换为主机虚拟/主机物理地址

    我正在做一个需要翻译的项目qemu guest物理地址到主机虚拟 物理地址 我正在使用 VMI 虚拟机自省 来自省 qemu 进程 KVM VM 并读取存储在 virtio 环缓冲区描述符中的来宾物理地址 因此 我正在寻找一种简单的方法来将
  • Maven Tomcat 插件更改端口

    我正在尝试创建一个 Spring MVC 应用程序并使用 Maven Tomcat 插件来部署它 如何更改上下文路径和端口 这是我放置在 pom xml 中的 Maven 插件 plugin gt
  • 将一个类传递给另一个类 (Python)

    我现在在上课时遇到了一些麻烦 我不知道如何解决我的问题 我已阅读文档 但无法将其中所说的任何内容与我遇到的问题联系起来 我正在尝试为游戏制作一些简单的课程 我有一个 Weapon 类和一个 Person 类 我试图将武器传递给 Person
  • 团队消息传递扩展是否可以返回明文响应而不是卡片?

    我正在尝试基于 v4 bot SDK 创建 Teams 消息传递扩展 该扩展可搜索知识库并提供可放入聊天中的建议响应 搜索有效 我可以选择一张卡片放入聊天中 但我想去掉格式 只将一段文本返回到聊天中 即我不希望聊天中的其他人看到响应来自扩展
  • Dart 编辑器:预期 url

    我有这个错误 Internal error http 127 0 0 1 3030 Motion bin csscode dart error line 2 pos 6 url expected part of dart motion 这部
  • 限制 javafx gui 更新

    我在随机时间以高频率接收数据对象 并且需要用这些数据更新 JavaFX GUI 但是 我不想用大量可运行对象填充 javafx 事件队列 我使用 Platform RunLater 我一直在思考如何最好地实现一个节流算法 最好有一个单独的
  • 从多个数组生成所有可能的组合(C#/VB.NET)[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions I have n数组的数量 每个数组
  • 为什么 32 位寄存器上的 x86-64 指令会将整个 64 位寄存器的上部清零?

    In the x86 64 Intel 手册之旅 http x86asm net articles x86 64 tour of intel manuals I read 也许最令人惊讶的事实是诸如这样的指令MOV EAX EBX自动将高
  • 当我运行此命令时,docker 无法识别服务 sudo service docker stop

    我正在尝试将图像推送到我自己的 docker 注册表 我收到无效端点注册表错误 当我用 google 搜索时 我得到了运行这些命令的解决方案 这是链接远程访问私有 docker registry https stackoverflow co
  • 如何校正检测到的椭圆

    我试图在图像中找到圆圈并将它们扭曲回规范视图 即就像看着中心一样 然而 在透视变换下 圆形通常会投影为椭圆 所以我首先检测椭圆 大致执行以下操作 在 OpenCV 中 1 Find contours in the image 2 Estim
  • 如何在 Ruby 中使用 RegEx 更改字符串中字母的大小写

    假设我有一个字符串 hEY 我想将其转换为 嘿 string gsub a z A Z 1 upcase 这就是我的想法 但当我在 gsub 方法中使用 upcase 方法时 它似乎什么也不做 这是为什么 编辑 我想出了这个方法 strin
  • 如何在 Play 2.1 中仅通过命令行获取应用程序名称和版本

    根据这个好技巧 https stackoverflow com a 14581996 1066240我正在设置版本并在命令之后play normalized name version在控制台中得到类似的输出 info Loading pro
  • 使用 javascript、actions 和 webdriver 单击元素?

    我们可以使用以下方法来点击网页元素 myWebElement click or JavascriptExecutor js JavascriptExecutor driver js executeScript arguments 0 cli
  • 变得严重:获取 sessionfactory 时无法在 JNDI 中找到 SessionFactory

    我使用 hibernate 作为持久层来与数据库通信 我使用maven插件hbm2java来生成dao java hbm xml和hibernate cfg xml 到那时插件就可以正常工作了 但是当我尝试与数据库通信时 它给出了以下异常
  • MongoError:聚合期间 PlanExecutor 错误

    我在 mongodb 中有树记录 但可能还有更多 我通过来自前端的 ID 获取商店 我需要获取 20 条记录 并按 itemId 和 colorId 对它们进行分组 并获取每个商店的计数 商店数量可以是 1 2 3 10 等 这是我需要的输
  • 直接访问gitlab数据库

    我正在从 gitlab 运行 AWS AMI 我正在尝试使用 psql 直接访问 postgres 数据库 我想我可以只使用database yml中的凭据 因为rails应用程序工作正常 opt gitlab embedded bin p
  • dotnet System.Web.Caching.Cache 与 System.Runtime.Caching.MemoryCache

    我有一个类需要将数据存储在缓存中 最初我在 asp net 应用程序中使用它 所以我使用 System Web Caching Cache 现在我需要在 Windows 服务中使用它 现在 据我了解 我不应该在非 asp net 应用程序中
  • 在 Postgresql 中索引外键

    像许多 Postgres 一样n00bs我们有很多带有外键约束但未建立索引的表 在某些情况下 这不会对性能造成很大影响 但这需要进一步分析 我读过以下文章 https www cybertec postgresql com en index