当前位置: 首页 > news >正文

postgresql-重复执行相同语句,试试 prepare!

文章目录


每次你向 PostgreSQL 发送 SQL 语句时,数据库都必须对其进行解析(parse)。解析虽然很快,但如果同样的语句被解析一千次,这种操作累积起来可能会占用大量时间,而这些时间本可以用于处理其他事务。为避免这种情况,PostgreSQL 提供了 prepare 语句。通过使用它,你可以避免重复解析语句,数据库只需执行planning和execution操作。

为了生成一些示例数据,这里使用了scale factor(规模因子)为 100 的 pgbench,这在 pgbench_accounts 表中产生10,000,000 行:

bench=#pgbench -U dbmgr -h 127.0.0.1 -p 5432 -i -s 100 bench
Password: 
dropping old tables...
NOTICE:  table "pgbench_accounts" does not exist, skipping
NOTICE:  table "pgbench_branches" does not exist, skipping
NOTICE:  table "pgbench_history" does not exist, skipping
NOTICE:  table "pgbench_tellers" does not exist, skipping
creating tables...
generating data (client-side)...
10000000 of 10000000 tuples (100%) done (elapsed 19.54 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done in 29.01 s (drop tables 0.00 s, create tables 0.02 s, client-side generate 20.19 s, vacuum 0.70 s, primary keys 8.09 s).
postgres@pgrec-d:~psql bench
psql (15.5 (Ubuntu 15.5-1.pgdg22.04+1))
Type "help" for help.bench=# select count(*) from pgbench_accounts;count  
----------10000000
(1 row)bench=# d pgbench_accountsTable "public.pgbench_accounts"Column  |     Type      | Collation | Nullable | Default
----------+---------------+-----------+----------+---------aid      | integer       |           | not null | bid      | integer       |           |          | abalance | integer       |           |          | filler   | character(84) |           |          | 
Indexes:"pgbench_accounts_pkey" PRIMARY KEY, btree (aid)

简单query一下:

bench=# select count(*) from pgbench_accounts where aid = 11111;count
-------1
(1 row)

正如本文开头所述,PostgreSQL 将需要解析该语句。使用带有正确选项的 explain,您可以看到产生执行计划花费了多少时间:

                                                                    QUERY PLAN                                                                     
---------------------------------------------------------------------------------------------------------------------------------------------------Aggregate  (cost=4.46..4.46 rows=1 width=8) (actual time=0.041..0.042 rows=1 loops=1)Buffers: shared hit=4->  Index Only Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.43..4.45 rows=1 width=0) (actual time=0.030..0.032 rows=1 loops=1)Index Cond: (aid = 11111)Heap Fetches: 0Buffers: shared hit=4Planning Time: 0.125 msExecution Time: 0.086 ms
(8 rows)

产生此语句的执行计划比执行它花费更多时间。现在假设您要执行同一条语句一千次:

bench=#\t
bench=#select 'select count(*) from pgbench_accounts where aid = 11111;' from generate_series(1,1000) i; \g test.sql
bench=# \! cat test.sql | head
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
select count(*) from pgbench_accounts where aid = 11111;
...

当执行该命令时,强制 PostgreSQL解析所有这 1000 条语句:

bench=# \timing
Timing is on.
bench=#\! /usr/bin/time -p psql -U dbmgr -f test.sql -d bench
real 0.76s
user 0.13s
sys 0.1s

为了避免这种情况,我们使用prepare去准备这条sql:

prepare c1 as select count(*) from pgbench_accounts where aid = 11111;
PREPARE

一旦prepare好,就可以执行它:

bench=# execute c1;count
-------1
(1 row)

explain:

bench=# explain(analyze,buffers) execute c1;Aggregate  (cost=4.46..4.46 rows=1 width=8) (actual time=0.041..0.042 rows=1 loops=1)Buffers: shared hit=4->  Index Only Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.43..4.45 rows=1 width=0) (actual time=0.030..0.032 rows=1 loops=1)Index Cond: (aid = 11111)Heap Fetches: 0Buffers: shared hit=4Planning Time: 0.007 msExecution Time: 0.100 ms

注意,与未准备好的语句相比,planning time减少了不少:

bench=# explain(analyze,buffers) select count(1) from pgbench_accounts where aid=11111;Aggregate  (cost=4.46..4.46 rows=1 width=8) (actual time=0.076..0.077 rows=1 loops=1)Buffers: shared hit=4->  Index Only Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.43..4.45 rows=1 width=0) (actual time=0.057..0.059 rows=1 loops=1)Index Cond: (aid = 11111)Heap Fetches: 0Buffers: shared hit=4Planning:Buffers: shared hit=3Planning Time: 0.376 msExecution Time: 0.166 ms

当现在这样执行一千次:

bench=# \t
Tuples only is off.
bench=# select 'execute c1;' from generate_series(1,1000) i; \g test.sql
bench=# \! sed -i '1s/^/prepare c1 as select count(*) from pgbench_accounts where aid = 11111;/' test.sql
bench=# \! /usr/bin/time -p psql -U dbmgr -f test.sql -d bench
real 0.55s
user 0.11s
sys 0.15s

执行时间将会缩短。在这个简单的例子中,效果不太明显,但这是因为语句本身非常简单。顺便提一下,预编译的语句只在会话期间有效,所以 sed 命令将 prepare 语句添加到文件顶部,预编译本身也需要时间。如果不预编译,执行时间会更短。
当 where 子句中的值发生变化时,可以这样做:

bench=# prepare c1 as select count(*) from pgbench_accounts where aid = $1;
PREPARE
Time: 0.387 ms

解除prepare好的语句

bench=# deallocate c1;
DEALLOCATE
Time: 0.336 ms

相关文章:

postgresql-重复执行相同语句,试试 prepare!

文章目录 每次你向 PostgreSQL 发送 SQL 语句时,数据库都必须对其进行解析(parse)。解析虽然很快,但如果同样的语句被解析一千次,这种操作累积起来可能会占用大量时间,而这些时间本可以用于处理其他事务。为避免这种情况&#xff…...

wpf加载带材料的3D模型(下载的3D预览一样有纹理)

背景:最近真的是忙啊,累出汁水了 整体效果: 放大可以看清砖头: 1、需要自己准备好3D模型,比如我这里是下载的这里的3D Warehouse,下载Collada File格式文件 2、解压可以看到一个model.dae和材料的文件夹&…...

【k8s之深入理解调度】调度框架扩展点理解

参考自 K8s 调度框架设计与 scheduler plugins 开发部署示例(2024) 调度插件扩展点 等待调度阶段PreEnqueuePod 处于 ready for scheduling 的阶段。 内部工作原理:sig-scheduling/scheduler_queues.md。在 Pod 被放入调度队列之前执行的插…...

音视频基础理论

1. 音频基础 1.1 音频基本概念 1.1 频率:声波的频率,即声音的音调,人类听觉的频率(音调)范围为20Hz--20KHz 1.2 振幅:即声波的响度,通俗的讲就是声音的高低,一般男生的声音振幅(响度)大于女生。 1.3 波形…...

《江苏科技大学学报(自然科学版)》

《江苏科技大学学报(自然科学版)》(双月刊,国内外公开发行)是由江苏省教育厅主管、江苏科技大学主办的理工类学术期刊,1986年创刊,国际刊号:ISSN1673-4807,国内刊号&…...

C++初学者指南-5.标准库(第二部分)–随机数生成

C初学者指南-5.标准库(第二部分)–随机数生成 文章目录 C初学者指南-5.标准库(第二部分)–随机数生成基本概念例子统一随机数布尔值(“抛硬币”)正态分布具有独立概率的整数 怎么做种子引擎使用自定义生成器 shuffle算法分布类型概述通用接口均匀分布采样…...

Unity2017在安卓下获取GPS位置时闪退的解决办法

在Unity使用低功耗蓝牙通信(BLE)需要用到设备的位置信息。但是调用Input.location.Start()程序会闪退。 解决办法:调用原生安卓接口。 参见《Unity2021通过aar调用Android方法》编写一个aar插件gpsplugin,在插件中提供获取GPS位…...

OpenGL ES 索引缓冲区(4)

OpenGL ES 索引缓冲区(4) 简述 本节会介绍索引缓冲区,索引缓冲区和顶点缓冲区类似,也是显存上的一段内存,只不过上面的数据用处不同,索引缓冲区故名思义里面的数据是用于索引,主要作用是用于复用顶点缓冲区里的数据。…...

01:(寄存器开发)点亮一个LED灯

寄存器开发 1、单片机的简介1.1、什么是单片机1.2、F1系列内核和芯片的系统架构1.3、存储器映像1.4、什么是寄存器 2、寄存器开发模板工程3、使用寄存器点亮一个LED4、代码改进15、代码改进2 本教程使用的是STM32F103C8T6最小系统板,教程来源B站up“嵌入式那些事”。…...

.Net 6.0 Windows平台如何判断当前电脑是否联网

最近在工作中开发需要判断当前电脑是否联网的需求,在网上找了一个调用window API来判断本机是否联网。具体请看下面介绍: 1.方法一(调用winAPI) [DllImport("wininet")] public static extern bool InternetGetConnec…...

微软准备了 Windows 11 24H2 ISO “OOBE/BypassNRO“命令依然可用

Windows 11 24H2 可能在未来几周内开始推出。 微软已经要求 OEM 遵循新的指南准备好 Windows 11 24H2 就绪的驱动程序,并且现在已经开始准备媒体文件 (.ISO)。 OEM ISO 的链接已在微软服务器上发布。 一个标有"X23-81971_26100.1742.240906-0331.ge_release_sv…...

MacOS 终端执行安装 Brew

在配置新的 Mac 环境时,如果你发现终端中无法识别 brew 命令,可以按照以下步骤进行解决。 步骤 1:确保网络稳定 为了避免安装过程中出现中断,建议使用 Wi-Fi 或有线连接,不推荐使用移动网络。 步骤 2:打…...

【设计模式-解释模式】

定义 解释器模式是一种行为设计模式,用于定义一种语言的文法,并提供一个解释器来处理该语言的句子。它通过为每个语法规则定义一个类,使得可以将复杂的表达式逐步解析和求值。这种模式适用于需要解析和执行语法规则的场景。 UML图 组成角色…...

51单片机应用开发(进阶)---数码管+按键+蜂鸣器(电磁炉显示模拟)

实现目标 1、加强数码管、按键的学习,实现数码显示变量数据(四位数的显示); 2、4位数码2个按键无源蜂鸣器实现模拟电磁炉功率调节及显示; 一、内容描述 功能描述:1、开机显示电磁炉功率300,每…...

Emergency Stop (ES)

文章目录 1. 介绍2. Feature List3. 紧急停止信号触发方式3.1 Port触发紧急停止信号3.2 SMU事件触发紧急停止信号3.3 软件触发紧急停止信号 4. 应用场景4.1 Port4.2 MSC 1. 介绍 Emergency Stop (ES)是Ifx System Control Units (SCU)六大模块之一。详细信息可以参考Infineon-…...

[C++][第三方库][gtest]详细讲解

目录 1.介绍2.安装3.使用1.头文件包含2.框架初始化接口3.调用测试样例4.TEST宏5.断言宏6.示例 1.介绍 gtest是一个跨平台的C单元测试框架,由Google公司发布gtest是为了在不同平台上为编写C单元测试而生成的,它提供了丰富的断言、致命和非致命判断、参数…...

【Java数据结构】 链表

【本节目标】 1. ArrayList 的缺陷 2. 链表 3. 链表相关 oj题目 一. ArrayList的缺陷 上节课已经熟悉了ArrayList 的使用&#xff0c;并且进行了简单模拟实现。通过源码知道&#xff0c; ArrayList 底层使用数组来存储元素&#xff1a; public class ArrayList<E>…...

前端——Ajax和jQuery

一、Ajax Ajax即“Asynchronous Javascript And XML”&#xff08;异步 JavaScript 和 XML&#xff09;&#xff0c; 通过 JS 异步的向服务器发送请 求并接收响应数据。 同步访问&#xff1a;当客户端向服务器发送请求时&#xff0c;服务器在处理的过程中&#xff0c;浏览器…...

C++-vector模拟实现

###vector底层相当于是数组&#xff0c;查看源码可以发现&#xff0c;这个类的私有成员变量是三个迭代器&#xff1b;在实现时迭代器就可以当作是vector里面的元素的指针类型&#xff1b; ###vector是一个类模板&#xff0c;实现时也应当按照这样的写法用一个模板去实现&#…...

Activity

69[toc] 1.启停活动页面 1.Activity启动和结束 从当前页面跳到新页面 startActivity(new Intent(this, ActFinishActivity.class));从当前页面返回上一个页面&#xff0c;相当于关闭当前页面 finish();2.Activity生命周期 官方描述生命周期 onCreate&#xff1a;创建活…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...