Postgres 不使用索引来实现慢速功能

2024-01-19

在我的数据库设计中,用到了很多函数。而且其中许多都非常慢。因此,我认为在其中一些上创建索引以使执行速度更快一点可能是一个明智的想法。 然而,我没有成功说服 PostgreSQL (9.6) 实际使用我的索引。

考虑这个表“用户”

id integer | name jsonb
1          | {"last_names": ["Tester"], "first_names": ["Teddy","Eddy"]} 
2          | {"last_names": ["Miller"], "first_names": ["Lisa","Emma"]}   

通常,我需要将名称作为一个字符串,这是通过类似(称为“concat_name”)的查询来完成的

SELECT array_to_string(jsonb_arr2text_arr(name->'last_names'), ' ') || ', ' || array_to_string(jsonb_arr2text_arr(name->'first_names'), ' ');

我决定将该功能放入一个函数中,因为它用于多个表:

CREATE OR REPLACE FUNCTION public.concat_name(name jsonb)
  RETURNS text AS
$BODY$
  SELECT pg_sleep(50);
  SELECT array_to_string(jsonb_arr2text_arr(name->'last_names'), ' ') || ', ' || array_to_string(jsonb_arr2text_arr(name->'first_names'), ' ');
$BODY$
  LANGUAGE sql IMMUTABLE SECURITY DEFINER
  COST 100;

你看,为了实际测试它是否有效,我添加了“人为”超时。 现在,我创建了一个索引,例如:

CREATE INDEX user_concat_name_idx ON "user" (concat_name(name));

它成功并花费了预期的时间(因为 pg_sleep)。然后我运行一个查询:

SELECT concat_name(name) FROM "user";

但是,索引没有被使用,查询速度非常慢。反而,EXPLAIN告诉我刨床对“用户”进行序列扫描。

我做了一些研究,很多人指出查询规划器认为,如果表很小或检索的数据集(几乎)是整个表,它认为进行序列扫描比查找索引更有效。 然而,对于功能,尤其是慢速功能,这对我来说没有任何意义。即使您查询仅包含一行的表 - 如果您的查询包含每次需要 50 秒执行的函数,则使用函数索引也可以显着减少执行时间。

因此,在我看来,查询规划器必须比较查找索引值所需的时间与执行函数所需的时间。表或查询本身的大小(返回多少行)在这里根本不重要。而且,如果函数执行需要 50 秒,那么查找索引应该总是获胜。

那么,我可以在这里做什么来让查询规划器使用索引而不是每次都重新执行该函数呢?


首先,索引(id, concat_name(name))如果您想在仅选择的查询中使用它,则毫无意义concat_name(name)。索引应该是:

create index user_concat_name_idx on "user" (concat_name(name));

其次,索引将在需要时使用,例如当你添加order by concat_name(name):

explain analyse
select concat_name(name)
from "user"
order by 1;

                                                                  QUERY PLAN                                                                   
-----------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using user_concat_name_idx on "user"  (cost=0.42..29928.42 rows=100000 width=82) (actual time=0.157..1046.168 rows=100000 loops=1)
 Planning time: 0.753 ms
 Execution time: 1048.862 ms
(3 rows)

此外,您可以使您的函数更简单、更快:

create or replace function concat_name(name jsonb)
returns text language sql immutable as $$
    select concat_ws(', ',
        (select string_agg(value, ' ')
        from jsonb_array_elements_text(name->'last_names')),
        (select string_agg(value, ' ')
        from jsonb_array_elements_text(name->'first_names'))
    )
$$;

我可以在这里做什么来使查询规划器使用索引而不是每次都重新执行该函数?

您应该声明该函数的更大成本,例如:

create or replace function concat_name(name jsonb)
returns text language sql immutable as $$
-- ...
$$
cost 1000;

Per 文档 https://www.postgresql.org/docs/current/static/sql-createfunction.html:

执行成本

一个正数,给出函数的估计执行成本,以 cpu_operator_cost 为单位。如果函数返回一个集合,则这是每个返回行的成本。如果未指定成本,则假定 C 语言和内部函数为 1 个单位,所有其他语言的函数为 100 个单位。较大的值会导致规划器尝试避免不必要地频繁地评估函数。

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

Postgres 不使用索引来实现慢速功能 的相关文章

  • postgresql 不同的不工作

    我使用以下代码从数据库获取值 但是当我编写这段代码时 测试看看问题出在哪里 我注意到查询没有从数据库中获取不同的值 这是查询 select distinct ca id as id acc name as accName pIsu name
  • 格式化多维数组 Python

    如何编写代码来更改多维数组中每个单独数组的值a出现负值后立即归零 所以里面的第二个数组a有负值 12 34 5 6 88 10 30 75 10 会将其所有值及其后的值转为零 将数组变成 12 34 5 6 88 0 0 0 我怎样才能获得
  • 没有提示指令的直连接中表的顺序是否会影响性能?

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

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

    我有一个 C 项目 我使用实体框架作为 ORM 我有一个User 可以向多家银行付款 每家银行都是一个独立的实体 并且每家银行都由不同的字段描述 问题是 一User可以没有或有很多不同的Banks 我不太确定如何对此进行建模 临时解决方案是
  • 如何创建没有循环关系的树形表?

    CREATE TABLE TREE node1 id UUID REFERENCES nodes object id NOT NULL node2 id UUID REFERENCES nodes object id NOT NULL CO
  • Ruby ActiveRecord 和 sql 元组支持

    ActiveRecord 是否支持 where 子句中的元组 假设底层数据库支持 结果 where 子句看起来像这样 where name address in John 123 Main St I tried Person where n
  • PLpgSQL 函数不返回匹配的标题

    当给定文本时 我试图返回电影名称以及演员和工作人员的数量 当我输入字符串并使用 ilike 时 我的查询返回不匹配的标题 我之前创建了一个视图 其中包含要在函数中输入的电影标题和工作人员数量 我的代码是 create or replace
  • 向带有检查约束 SQL 的表添加列

    我想向表中添加一列 然后添加一个检查约束以确保其大于 0 我似乎无法让它在 oracle sl Developer 中运行 Alter TABLE store101 add column Base salary Number 7 2 con
  • PostgreSQL:删除数据库但数据库仍然存在[重复]

    这个问题在这里已经有答案了 我是 PostgreSQL 的新手 我尝试着理解它 我熟悉数据库和MySQL 我正在尝试删除我创建的数据库 因为 psql 似乎忽略了我尝试通过 Django 推送的更改 当我执行时 l我得到以下回复 List
  • 针对约 225 万行的单表选择查询的优化技术?

    我有一个在 InnoDB 引擎上运行的 MySQL 表 名为squares大约有 2 250 000 行 表结构如下 squares square id int 7 unsigned NOT NULL ref coord lat doubl
  • 如何关闭 gorm 1.20.0 中的数据库实例

    由于我没有在 Close 函数中找到 gorm 实例 任何帮助将不胜感激 dbURI fmt Sprintf user s password s dbname s port s sslmode s TimeZone s username p
  • Pandas:使用日期时间索引列表从 DataFrame 中提取多行

    我有一个 pandas Dataframe 其索引具有秒频率 DatetimeIndex 2015 12 28 05 20 05 2015 12 28 05 20 06 2015 12 28 05 20 07 2015 12 28 05 2
  • 如何将今天的日期返回到 Oracle 中的变量

    我想做这个 DECLARE today as smalldatetime SELECT today GetDate 但我需要一个oracle翻译 甲骨文使用SYSDATE 还有 ANSI 标准CURRENT TIMESTAMP 除其他外 S
  • 在 plpgsql 函数中使用 quote_ident()

    我是创建 plpgsql 函数的新手 我需要一些有关在函数内部执行的动态命令上使用 quote ident 甚至 quote literal 的说明 希望有人能给我一个关于它们如何在函数内部工作的具体解释 TIA 这是一个例子 EXECUT
  • 使用函数的 SQL 查询 - 如何获取列表的最大计数

    如何查询 MAXIMUM COUNT 交易次数 我的代码如下 SELECT customer id COUNT customer id FROM rental GROUP BY customer id HAVING MAX COUNT cu
  • SQL Server:如果存在会大大减慢查询速度

    正在使用SQL Server 2012 我找到了一些关于查询优化的主题 并将 EXISTS 与 COUNT 进行比较 但我找不到这个确切的问题 我有一个看起来像这样的查询 select from tblAccount as acc join
  • “WHERE”处或附近的语法错误

    创建 postgres 函数时会导致错误 如下所示 错误 WHERE 处或附近的语法错误 第 19 行 其中 s shift id shiftid 错误 错误 WHERE 处或附近的语法错误 SQL状态 42601 人物 108 请帮忙 C
  • 为什么 ISNUMERIC('.') 返回 1?

    最近我在 SQL Server 中使用 ISNUMERIC 时遇到了一个问题 导致找到了这段代码 SELECT ISNUMERIC 这会返回 1 如 true 所示 难道不应该像 false 一样返回 0 吗 See Numeric 损坏了
  • 在Python中按属性获取对象列表中的索引

    我有具有属性 id 的对象列表 我想找到具有特定 id 的对象的索引 我写了这样的东西 index 1 for i in range len my list if my list i id specific id index i break

随机推荐

  • 将鼠标悬停在信息框上会在其后面的标记上触发悬停事件

    我目前正在使用 Google 地图的 InfoBox 插件 不幸的是 我遇到了一个恼人的问题 我的应用程序上的用户可以通过将鼠标悬停在相应的标记上来打开信息框 效果很好 当信息框打开并且用户将鼠标悬停在其上时 会出现此问题 由于某种原因 标
  • 使用 React 上传多个图像

    我想先通过预览来上传多张图像 然后提交以发送它们 我遇到过这样的情况 TypeError Cannot read property files of null 它还只允许我上传一张图像 我创造了files 作为在提交之前安装图像以供审核的方
  • Windows 7下如何设置进程超时?

    我想使用 Windows 批处理文件启动一个程序 但程序应该在一定的超时值后停止 例如 运行程序60秒 60秒后停止 Linux下有这个不错的timeout命令做我想做的事 Windows 也有一个timeout命令 但它只是暂停命令 延迟
  • 生成不重复的随机数。C# [重复]

    这个问题在这里已经有答案了 大家好 我试图在 C 的同一行上生成 6 个不同的数字 但我面临的问题是有些数字在同一行上重复 这是我的代码 var rand new Random List
  • 在 Mercurial 中,如何将反向补丁应用于特定文件?

    相关Mercurial 在一个存储库中的分支之间合并一个文件 https stackoverflow com questions 1078881 mercurial merging one file between branches in
  • 在 iPhone 应用程序中使用 CoreGraphic 描边作为 Alpha 遮罩

    我基本上希望为不同的目的创建类似于 iSteam iFog alebit 的非常简单版本的东西 实际上 将有两个图像 一个是主题图像 另一个是凝结图像或类似图像 然后 用户可以在屏幕上擦拭手指 它将从顶层 剪切 以显示下层 到目前为止 我已
  • 如何在IntelliJ IDEA中查看JDK外部文档?

    此操作的快捷方式是 Shift F1 但它始终呈灰色 即使我已指出 JDKdocumentation path to the docs文件夹 docs 文件夹解压自jdk 7u2 apidocs zip http www oracle co
  • matplotlib 中的交互线

    我正在尝试使用 matplotlib 制作一个交互式绘图 该绘图创建一个端点处带有两个句柄的线段 您可以单击并拖动手柄 线条将刷新以匹配以此方式指定的位置 与此 matplotlib 示例类似多编辑器 http matplotlib org
  • Java spring security - 拦截不同登录的子域url?

    我有一个安装了 spring security 且运行良好的应用程序 它目前已用完www exampledomain com 我现在想扩展在子域之外运行的应用程序 例如newapp exampledomain com 唯一的问题是 对于这个
  • 是否可以在 lambda 表达式中定位 EventHandler?

    举一个简单的例子 如果我有某种按钮 UI 类 我可以编写一个函数来接受指向其的表达式吗 Click事件处理程序 SomeMethod
  • 如何将编辑后的JTable数据保存到数据库?

    首先为我糟糕的英语感到抱歉 我会尽力理解你我的问题 我想要的只是在单击 保存 按钮时保存用户在 JTable 中输入的新数据 我正在从数据库中检索前两列中的学生 ID 姓名 并且我还在第三列中添加了当前日期 并在第四列中添加了缺席 出席 这
  • 如何使用轮盘赌选择最多数量的海龟

    在我的模型中 海龟有两种性别 雄性有两种潜在的策略 雌性会计算一定半径内雄性的数量 我希望雌性根据两种雄性策略的相对频率来权衡从雄性组中选择的概率 无需替换 我已经有了从男性中选择概率的代码 matingPoolProbAnad and m
  • 与默认 emacs 分开改变 Emacs 迷你缓冲区的字体大小?

    我一直在尝试将 emacs 迷你缓冲区的字体 外观与 emacs 默认字体分开 但运气不佳 具体来说 我有兴趣使迷你缓冲区字体大小更大 以便与 emacs MULE 一起使用 因为使用我当前的字体设置 或者如果我在 上网本 屏幕上使用 em
  • 在 Haskell 中很好地打印/显示二叉树

    我有一个树数据类型 data Tree a b Branch b Tree a b Tree a b Leaf a 我需要使它成为一个实例Show 不使用deriving 我发现很好地显示带有两片叶子的小树枝很容易 instance Sho
  • 选择不同计数(id)与选择计数(不同id)

    我正在尝试从表中获取不同的值 当我跑的时候select distinct count id from table我得到了超过一百万的计数 但是如果我跑了select count distinct id from table我只有大约 300
  • GoogleService-Info.plist 文件中的 iOS Firebase IS_ADS_ENABLED 标志

    添加时Firebase支持 iOS 应用程序 Firebase 生成此GoogleService Info plist file 该文件中的标志之一是IS ADS ENABLED默认为true 我找不到这个标志的任何文档 在网站上或在FIR
  • 如何让线程一个接一个地运行?

    创建三个线程和主线程 将每个线程作为并发任务执行 退出每个线程时显示信息 我可以通过上述练习运行两个线程 但很难运行三个线程 这是我的程序 package Thread 导入 java util concurrent atomic Atom
  • 滚动时 Xcode 表格视图滞后

    void bilgileriYukle NSMutableArray yemekIsimleri NSMutableArray alloc init NSMutableArray resimIsimleri NSMutableArray a
  • Node.js/NodeMailer/Express/Outlook smtp 主机 - 超出并发连接限制

    一切顺利 我正在开发一个使用express和nodemailer的应用程序 我的应用程序成功发送电子邮件 但问题是 我无法以我想要的方式一次发送一封电子邮件 我不想将地址数组放入 收件人 字段中 我希望将每封电子邮件单独发送出去 我已经成功
  • Postgres 不使用索引来实现慢速功能

    在我的数据库设计中 用到了很多函数 而且其中许多都非常慢 因此 我认为在其中一些上创建索引以使执行速度更快一点可能是一个明智的想法 然而 我没有成功说服 PostgreSQL 9 6 实际使用我的索引 考虑这个表 用户 id integer