【数据库学习】PostgreSQL优化

1,数据库减负思路

  1. 缓存 + 页面静态化
    实时性不高的数据;
  2. 数据库优化=sql优化 + 表结构优化 + 数据库分区分表
    合并数据库操作,将多次操作合并成一条sql执行。
  3. 热点数据分离
    主表只保存活跃数据。
  4. 数据库读写分离

2,执行计划

explain只能分析:SELECT、INSERT、DELETE、UPDATE和DECLARE…CURSOR命令。

#查看执行计划。也可以使用navicat的解释功能查看。
--ANALYZE 缺省表示只计划;加上表示查看实际执行成本。
explain [ANALYZE] sql语句;  

结果说明:

QUERY PLAN
Index Scan using tenk1_unique1 on tenk1  (cost=0.00..10.01 rows=1 width=244)
--Index 使用索引
--cost:启动开销..总开销。不过事实总开销可能会低一点:带有 LIMIT 子句的查询将会在 Limit 规划节点的输入节点里很快停止。
--rows:预计输出的行数
--Filter:过滤条件Index Cond: (unique1 < 3)  --从索引中检索出的行的过滤器Filter: (stringu1 = 'xxx'::name)QUERY PLAN
--嵌套循环Nested Loop  (cost=2.37..553.11 rows=106 width=488) ->  Bitmap Heap Scan on tenk1 t1  (cost=2.37..232.35 rows=106 width=244) Recheck Cond: (unique1 < 100)--位图索引->  Bitmap Index Scan on tenk1_unique1  (cost=0.00..2.37 rows=106 width=0)Index Cond: (unique1 < 100)->  Index Scan using tenk2_unique2 on tenk2 t2  (cost=0.00..3.01 rows=1 width=244)Index Cond: ("outer".unique2 = t2.unique2)QUERY PLAN
--内存 Hash 表Hash Join  (cost=232.61..741.67 rows=106 width=488)Hash Cond: ("outer".unique2 = "inner".unique2)->  Seq Scan on tenk2 t2  (cost=0.00..458.00 rows=10000 width=244)->  Hash  (cost=232.35..232.35 rows=106 width=244)->  Bitmap Heap Scan on tenk1 t1  (cost=2.37..232.35 rows=106 width=244)Recheck Cond: (unique1 < 100)->  Bitmap Index Scan on tenk1_unique1  (cost=0.00..2.37 rows=106 width=0)Index Cond: (unique1 < 100)

1)多表连接查询

①Nest Loop Join(嵌套循环连接)

1>场景

适合两个表的数据量都比较少的情况(最简单的 table join 方式)。

  1. 外表为小表,且过滤后的数据量较少。
  2. 内表的关联列上有高效索引(主键或者唯一性索引)。
2>举例
# 内表(t4)被外表(t5)驱动。外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大(大于1 万不适合)
select t4.*,t5.*from tmp_t4 t4,tmp_t5 t5where 1=1and t4.id = t5.idand t4.id = 1;

相当于for循环:

for(t4.data in tmp_t4) { t5.data in tmp_t5 on t5.data = t4.data}

②Hash JOIN(哈希、散列连接)

1>场景

针对那些没有索引或者其中任一个有索引的大表。
哈希连接只能应用于等值连接(如WHERE A.COL3 = B.COL4)、非等值连接(WHERE A.COL3 > B.COL4)、外连接(WHERE A.COL3 = B.COL4(+))。

2>操作步骤

优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。
这种方式适用于较小的表完全可以放于内存中的情况,这样总成本就是访问两个表的成本之和。但是在表很大的情况下并不能完全放入内存,这时优化器会将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段,此时要有较大的临时段从而尽量提高I/O 的性能。

③Sort Merge JOIN

1>场景

通常Hash JOIN的性能都优于Merge JOIN,对于那些连接列上有索引的表(已排好序)Merge JOIN性能会优于Hash JOIN。

2>操作步骤

mrege join的性能开销几乎都在前两步。

  1. 对连接的每个表做全表扫描(table access full);
  2. 对table access full的结果进行排序。
  3. 进行merge join对排序结果进行合并。

在全表扫描比索引范围扫描再通过rowid进行表访问更可取的情况下,merge join会比nested loops性能更佳。当表特别小或特别巨大的时候,实行全表访问可能会比索引范围扫描更有效。

3,SQL优化

对于重复的代码逻辑,sql执行速度远远大于代码逻辑。
但是,由于sql难以测试、难以复用、难以加工变量,对于复杂的逻辑不建议用在sql中。代码可以分成模块、逻辑独立、方便测试。

sql优化的思路有两种:
一是:

The fastest way to do something is don’t do it
去掉无用的步骤

二是优化算法,如让sql走更优的执行计划上。

1)概念

1>引擎优化策略

基于规则的优化(RBO,Rule Based Optimizer)
这是一种比较老的技术,简单说基于规则的优化就是当数据库执行一条query语句的时候必须遵循预先定义好的一系列规则(比如oracle的15条规则,排名越靠前的执行引擎认为效率越高)来确定执行过程,它不关心访问表的数据分布情况,仅仅凭借规则经验来确定,所以说是一种比较粗放的优化策略。

基于代价的优化(CBO,Cost Based Optimizer)
基于代价的优化的产生就是为了解决上面RBO的弊端,让执行引擎依据预先存储到数据库中表的一些实时更新的统计信息来选择出最优代价最小的执行计划来执行query语句,CBO会根据统计信息来生成一组可能被使用到的执行计划,进而估算出每个计划的代价,从而选择出代价最小的交给执行器去执行,其中表的统计信息一般会有表大小,行数,单行长度,单列数据分布情况,索引情况等等。

总结:
基于规则的优化器更像是一个经验丰富熟知各条路段的老司机,大部分情况可以根据自己的经验来判断走哪条路可以更快的到达目的地,而基于代价的优化更像手机里面的地图,它可以选择出许多不同的路径根据实时的路况信息综合考虑路程长度,交通状况来挑出最优的路径。

2)SQL高性能归约

1>查询

  1. 禁止使用select * ,用SELECT <字段列表> 查询;
  2. 同一列操作,用in代替or。
    in 操作可以更有效的利用索引,or 大多数情况下很少能利用到索引。

2>表连结

  1. 联结的表越多效率越低,一般<5张;
    SQL本身不限制联结表的数目,但DBMS有最大数目限制。
  2. join查询一般比子查询快;
  3. 小表驱动大表+ 合适索引(给大表的join条件建立索引)+ 合理运用连接条件(大表改成二次查询表,通过where语句过滤大部分数据),基本上连接可以解决绝大部分问题。
  4. 排序字段必须是驱动表字段,不然可能用不到索引。

3>数据库层面

  1. 减少同数据库的交互次数,合并多个相同操作。

4>表设计

  1. 表数据量的大小<500w
  2. 分区表
    分区表由多个文件存储,逻辑上表现为一个表。
    跨区查询效率更低。
  3. 尽量做到冷热数据分离,减少表的宽度。
  4. 禁止在表中建立预留字段
    预留字段的命名很难做到见名识义 预留字段无法确认存储的数据类型,所以无法选择合适的类型 对预留字段类型的修改,会对表进行锁定。
  5. 禁止在数据库中存储图片,文件等大的二进制数据;
  6. 优先选择符合存储需要的最小的数据类型。
    列的字段越大,建立索引时所需要的空间也就越大。
  7. 必须有主键、update_time;

4,配置优化

pg中与内存有关的配置参数:

1>shared_buffers(共享缓存区)

i>工作原理

shared_buffers是一个8KB的数组,postgres在从磁盘中查询数据前,会先查找shared_buffers的页,如果命中,就直接返回,避免从磁盘查询。
多个进程通过共享内存技术来共享缓存中的数据。

  1. shared_buffers存储什么?
    表数据;
    索引,索引也存储在8K块中;
    执行计划,存储基于会话的执行计划,会话结束,缓存的计划也就被丢弃。

  2. 什么时候加载shared_buffers?
    1)在访问数据时,数据会先加载到os缓存,然后再加载到shared_buffers,这个加载过程可能是一些查询,也可以使用pg_prewarm预热缓存。
    2)当然也可能同时存在os和shared_buffers两份一样的缓存(双缓存)。
    3)查找到的时候会先在shared_buffers查找是否有缓存,如果没有再到os缓存查找,最后再从磁盘获取。
    4)os缓存使用简单的LRU(移除最近最久未使用的缓存),而数据库采用的优化的时钟扫描,即缓存使用频率高的会被保存,低的被移除。

ii>优化策略

提高shared_buffers,增加缓存命中率,提高查询效率。
同时为了避免Double Buffering问题,将shared_buffers设置较小,更多的内存留给文件系统使用。

  1. 【Double Buffering(双缓存)】问题:
    pg的数据文件都存储在文件系统中,os的文件系统也有缓存,这导致pg的数据库副本可能同时存在于共享内存和文件系统中,造成内存利用率低的问题。
    Oracle中通过设置Birect I/O避免双缓存问题,但pg不支持。 shared_buffers的大小不应该超过内存的1/4。

  2. shared_buffers设置的合理范围
    1)windows服务器有用范围是64MB到512MB,默认128MB
    2)linux服务器建议设置为25%,亚马逊服务器设置为75%(避免双缓存,数据会存储在os和shared_buffers两份)
    os缓存的重要性:数据写入时,从内存到磁盘,这个页面就会被标记为脏页,一旦被标记为脏页,它就会被刷新到os缓存,然后写入磁盘。所以如果os高速缓存大小较小,则它不能重新排序写入并优化io,这对于繁重的写入来说非常致命,因此os的缓存大小也非常重要。给予shared_buffers太大或太小都会损害性能。

  3. shared_buffers调整策略

2> work_mem

为每个进程单独分配的内存,主要用于group by, sort, hash agg, hash join 等操作。
注意:work_mem是每次分配的内存,加入有M个并发进程,每个进程有N个HASH操作,那么需要分配的内存为 MNwork_mem。因此work_mem不宜设置太大,通常保持默认的4MB即可,如果设置的太大超过256MB,很容易因为瞬间的大并发操作导致oom。

3>maintenance_work_mem

为每个进程单独分配的内存,主要进行维护操作时需要的内存,如VACUUM、create index、ALTER TABLE ADD FOREIGN KEY等操作需要的内存。

4>autovacuum_work_mem

pg9.4版本新增参数。
9.4之后,AutoVacuum的worker进程分配的内存由参数autovacuum_work_mem控制,手动Vacuum时分配的内存由maintenance_work_mem 控制。9.4之前都用maintenance_work_mem 参数。
默认值为-1,表示与maintenance_work_mem 一样。
vacuum 大小 = autovacuum_max_workers * autovacuum_work_mem

5>temp_buffers(临时表缓存)

为每个不同的进程单独分配的内存,不在共享内存中,默认为8MB。

6>wal_buffers(WAL日志缓存大小)

默认为-1,表示根据shared_buffer的大小自动设置。

7>huge_pages(是否使用大页)

默认值为try,表示尽量使用大页。若os未开启大页,不使用大页内存,不影响数据库正常使用。

8>effective_cache_size(sql执行中的实际磁盘缓存)

与具体内存分配无关

5,sql审计

相关配置:

参数调整说明
log_min_duration_statementsql审计记录的标准,超过该时长的sql将被记录到日志文件。默认为-1,不记录超时sql。
log_statementnone默认,不记录;all-记录所有语句;ddl-记录所有数据定义语句;mod记录所有ddl和数据修改语句;
log_min_error_statement控制日志中是否记录导致数据库出现错误的SQL语句。默认为error

6,排查sql

-- 查看表结构 
SELECT column_name,data_type FROM information_schema.columns WHERE table_name = '表名'; -- 查看慢查询日志是否开启 
SHOW log_min_duration_statement; -- 设置慢查询日志 
ALTER DATABASE test SET log_min_duration_statement TO 10000; --慢sql 添加\watch 1监控
select query,wait_event_type,wait_event from pg_stat_activity 
where wait_event is not null and now()-state_change>interval '5 second';--长wait事件
select query,wait_event_type,wait_event from pg_stat_activity where state='active' and wait_event is not null and now()-state_change>interval '5 second';-- 查找经常被扫描的大型表 
SELECT schemaname, relname, seq_scan, seq_tup_read, idx_scan, seq_tup_read / seq_scan AS avg FROM pg_stat_user_tables WHERE seq_scan > 0 ORDER BY seq_tup_read DESC LIMIT 20; -- 跟踪 vacuum 进度 
SELECT * FROM pg_stat_progress_vacuum ;

7,pg统计收集器

比较耗费性能,默认关闭,可在postgresql.conf进行配置( stats_start_collector = true )。

这些表的具体说明参见:华为 openGauss (GaussDB) v2.1 使用手册

1>pg_stat_activity

常见应用


-- 展示在数据库中当前正在执行多少查询 
SELECTdatname,COUNT ( * ) AS OPEN,COUNT ( * ) FILTER ( WHERE STATE = 'active' ) AS active,COUNT ( * ) FILTER ( WHERE STATE = 'idle' ) AS idle,COUNT ( * ) FILTER ( WHERE STATE = 'idle in transaction' ) AS idle_in_trans 
FROMpg_stat_activity
GROUP BYROLLUP ( 1 )-- 查看事务已经打开了多久
SELECTpid,xact_start,now( ) - xact_start AS duration 
FROMpg_stat_activity 
WHERESTATE LIKE'%transaction%' 
ORDER BY3 DESC;-- 检查是否有长查询运行 
SELECT now() - query_start AS duration, datname, query FROM pg_stat_activity WHERE state = 'active' ORDER BY 1 DESC; --查询服务进程PID: 通过count(*)获取当前连接数
select pid,usename,client_addr,client_port from pg_stat_activity;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/649339.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

美易官方:Edward Jones将特斯拉评级从买进下调至持有

近日&#xff0c;知名金融机构Edward Jones宣布将对特斯拉&#xff08;Tesla&#xff09;的评级进行调整&#xff0c;从买进下调至持有。这一消息引起了市场的广泛关注。特斯拉作为全球领先的电动汽车制造商&#xff0c;其股票一直备受投资者关注。本文将对此次评级调整进行分析…

【Go学习】Ginkgo测试框架学习实践 + 问题记录 + 怎么解决(0)

1、ginkgo测试框架介绍&#xff1a;https://onsi.github.io/ginkgo/ 2、重点是学习实践 问题记录 怎么解决 3、送福利&#xff1a;国内好用的ChatGpt有很多&#xff0c;比如&#xff1a;天工、文心一言、讯飞星火、通义万相等 1. 安装 xxxmacdeMacBook-Pro-3  /Volumes/mac…

【JS基础】定时器的使用、事件监听

文章目录 前言一、定时器1.1定时器是什么1.2 setInterval函数1.3 关闭定时器clearInterval 二、事件监听2.1 事件监听是什么2.2 事件监听的使用基本语法点击事件鼠标事件焦点事件键盘事件 2.3 事件对象event 总结 前言 JavaScript 中的定时器和事件监听是 Web 开发中至关重要的…

leetcode hot100组合

在本题中&#xff0c;是要求返回[1,n]这个数组的长度为k的组合。涉及到排列、组合、棋盘、分割等问题的时候&#xff0c;要考虑利用回溯来进行解决。 回溯和递归类似&#xff0c;也分为三步进行分析 确定递归函数的返回值和参数&#xff1a;一般来说返回值都是void&#xff0c…

黑豹程序员-vue实现两级联动下拉列表

需求 在开发中这类需求很多&#xff0c;前后两个下拉框有紧密关系&#xff0c;第一个下拉框相当于一个分类&#xff0c;选中第一个下拉框中的某个分类后&#xff0c;第二个下拉框的内容随之改变&#xff0c;列出其分类下的选项。 图例 选中某个一级风险领域后&#xff0c;二级…

在学校中,N个小朋友站成一队, 第i个小朋友的身高为height[i],,单调栈的应用

在学校中&#xff0c;N个小朋友站成一队&#xff0c; 第i个小朋友的身高为height[i]&#xff0c; 第i个小朋友可以看到的第一个比自己身高更高的小朋友j&#xff0c;那么j是i的好朋友(要求j > i)。 请重新生成一个列表&#xff0c;对应位置的输出是每个小朋友的好朋友位置&a…

时间数据前端显示格式化

背景 在实际我们通常需要在前端显示对数据操作的时间或者最近的更新时间&#xff0c;如果我们只是简单的使用 LocalDateTime.now()来传入数据不进行任何处理那么我们就会得到非常难看的数据 解决方式&#xff1a; 1). 方式一 在属性上加上注解&#xff0c;对日期进行格式…

【Linux】Linux进度条小程序(包含色块实现)

我们再将Linux常用工具与命令都学会了之后&#xff0c; 设计进度条这个小程序可以比较好的帮助我们进行一定程度练习与巩固 目录 预备知识&#xff1a;回车换行&#xff1a;缓冲区&#xff1a; 进度条&#xff1a;准备工作&#xff1a;主题思路&#xff1a;代码实现&#xff1a…

图片保存后多了个水印?教你如何用华为手机保存无水印图片

对于各类生活App的深度用户来说&#xff0c;有时候碰到实用的生活技巧、攻略&#xff0c;甚至是一张好看的风景照&#xff0c;都会第一时间想要长按把图片保存到手机相册&#xff0c;有时候还会分享给朋友、朋友圈。 但是有些图片在App上显示的时候是干净的&#xff0c;保存下…

【AI】深度学习在编码中的应用(11)

目前&#xff0c;视觉数据的智能编码压缩技术仍处于快速发展阶段&#xff0c;其主要发展趋势反映在新架构、新内容和新场景三个维度。以下具体将从隐式神经表示、多模态视觉数据压缩和面向人机混合智能的编码三个方面展开梳理和学习。 ——隐式神经表示 隐式神经表示&#xf…

基于SQL注入漏洞的总结与归纳(个人学习 整理归纳复习

第一节 我们首先要知道什么是SQL注入漏洞 SQL注入常见的web漏洞&#xff0c;形成的主要原因是web应用程序在接收相关数据参数时未做好过滤&#xff0c;将其直接带入到数据库中查询&#xff0c;导致攻击者可以拼接执行构造的SQL语句。 像这样我们输入?id1 我们可以获得id1的信…

【QT+QGIS跨平台编译】之九:【LZ4+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、LZ4介绍二、文件下载三、文件分析四、pro文件五、编译实践一、LZ4介绍 LZ4是一种无损压缩算法,压缩速度为每核心400MB/s。 LZ4是目前效率最高的压缩算法,更加侧重于压缩/解压缩速度,压缩比并不突出,本质上就是时间换空间。 LZ4库是使用BSD许可证作为开放源码…

基于LLaMA-Factory的微调记录

文章目录 数据模型准备基于网页的简单微调基于网页的简单评测基于网页的简单聊天 LLaMA-Factory是一个非常好用的无代码微调框架&#xff0c;不管是在模型、微调方式还是参数设置上都提供了非常完备的支持&#xff0c;下面是对微调全过程的一个记录。 数据模型准备 微调时一般…

奔图P1家用激光打印机测评:小巧精致,高效便捷,开启打印新革命

在当今数字化时代&#xff0c;办公方式越来越灵活&#xff0c;日常学习也有很多作业、习题需要打印&#xff0c;无论是为了满足日常的学习、工作需求&#xff0c;还是为了追求个人兴趣、丰富业余生活&#xff0c;我们都离不开打印机的身影。打印机这个曾经被视为专业领域的设备…

每日一题——LeetCode2859.计算K置位下标对应元素的和

方法一 枚举法&#xff1a; 通过不断地将目标数值与 1 进行按位与操作&#xff0c;并根据结果判断最低位是否为 1&#xff0c;从而统计其中包含的 1 的个数。 如果1的个数等于K就加上该值。 var sumIndicesWithKSetBits function(nums, k) {function countOnes(num) {let cou…

springboot+value静态属性获取配置文件中的值的操作方法

1.配置类需要让spring管理 2.set方法不要加static 3.如果静态属性是private修饰&#xff0c;则在使用的时候&#xff0c;需要 类名.getXXX方法 如果静态属性是public修饰&#xff0c;则在使用的时候&#xff0c;需要 类名.属性名 import org.springframework.beans.factory.an…

《菊与刀》读书笔记

前言 大学期间&#xff0c;同寝室的永志大哥喜欢高晓松的《晓说》&#xff0c;受其影响&#xff0c;我也看过几期。高晓松在讲日本文化的时候&#xff0c;推荐过《菊与刀》&#xff0c;那是我第一次知道这本书。 背景 《菊与刀》的作者名叫鲁思本尼迪克特&#xff0c;大学主…

HCIA-Datacom实验指导手册:2 构建互联互通的 IP 网络

HCIA-Datacom实验指导手册:2 构建互联互通的 IP 网络 一、 实验介绍二、实验拓扑:三、实验目的:四、配置步骤:步骤 1 掌握接口 IPv4 地址的配置方法步骤 2 理解 LoopBack 接口的作用与含义,以及什么是InLoopBack0?步骤 3 理解直连路由的产生原则步骤 4 掌握静态路由的配置…

mysql8版本批量造4000个数据SQL

需求&#xff1a; 测试工作中修改单需要构造单元下4000个组合的数据&#xff0c;写个博客来记录&#xff0c;其他类似的可以举一反三。 具体sql&#xff1a; 实现1个产品1个单元下插入4000个组合数据 思路&#xff1a; 在MySQL 8中实现循环插入4000条具有不同主键的记录&a…

老旧小区火灾频发,LoRa无线系统筑牢安全防线

近日&#xff0c;全国各地多个老旧小区火灾事故频发&#xff0c;从安微合肥南二环一老旧小区居民楼起火、上海金山区一小区居民楼火灾&#xff0c;到1月24日江西新余市特大火灾......都造成了不同程度的人员伤亡和财产损失&#xff0c;令人扼腕痛惜&#xff0c;教训十分深刻。 …