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

【PostgreSQL】PG数据库表“膨胀”粗浅学习

文章目录

  • 1 为什么需要关注表膨胀?
  • 2 如何确定是否发生了表膨胀?
    • 2.1 通过查询表的死亡元组占比情况来判断膨胀率
      • 2.1.1 指定数据库和表名
      • 2.1.2 查询数据库里面所有表的膨胀情况
  • 3 膨胀的原理
    • 3.1 什么是膨胀?膨胀率?
    • 3.2 哪些数据库元素会发生膨胀?
    • 3.3 为什么会产生膨胀的现象?
    • 3.4 必须要做清理的原因?
    • 3.5 VACUUM进度报告
  • 4 如何处理表膨胀问题?
    • 4.1 简单粗暴但是有效彻底的空间回收:“vacuum full 表名”-不推荐
      • 4.1.1 FULL参数使用注意
      • 4.1.2 FULL参数使用示例
    • 4.2 相对优雅一些的回收方式:“vacuum 表名”-推荐
      • 4.2.1 标准的vacuum(不带full参数的方式)
      • 4.2.2 标准VACUUM回收清理使用示例
      • 4.2.3 标准vacuum支持多个option命令方式:vacuum (verbose,analyze) mytest;
    • 4.3 模拟大表膨胀的简单方法
  • 5 膨胀产生后的危害&如何长远应对?
    • 5.1 产生哪些危害?
    • 5.2 如何应对?
  • 6 总结

1 为什么需要关注表膨胀?

有一天,发现数据库所在的服务器上的空间在报不够用了,有一天发现某些和数据库有关的功能的莫名的变慢了,有一天发现某些功能时快时慢。。。
这些时候,我们可能要考虑一下是不是有表膨胀在发生?

2 如何确定是否发生了表膨胀?

2.1 通过查询表的死亡元组占比情况来判断膨胀率

pg_stat_all_tables里面的relname是表名。 可以看到如果类似最后一列dead_tup_ratior如果值很大,一般来说大于50了,那么一定要介入处理了。这个值相当于是无效数据的占比。

2.1.1 指定数据库和表名

下面的示例是:数据库名是test,数据库表是mytest

test=# select schemaname||'.'||relname as table_name,pg_size_pretty(pg_relation_size(schemaname||'.'||relname)) as table_size,n_dead_tup,n_live_tup,round(n_dead_tup*100/(n_live_tup+n_dead_tup),1) as dead_tup_ratio
from pg_stat_all_tables
where n_live_tup + n_dead_tup <> 0 and relname='mytest';table_name   | table_size | n_dead_tup | n_live_tup | dead_tup_ratio
---------------+------------+------------+------------+----------------public.mytest | 1042 MB    |   10000001 |    5999859 |           62.0
(1 row)

2.1.2 查询数据库里面所有表的膨胀情况

select schemaname||'.'||relname as table_name,pg_size_pretty(pg_relation_size(schemaname||'.'||relname)) as table_size,n_dead_tup,n_live_tup,round(n_dead_tup*100/(n_live_tup+n_dead_tup),1) as dead_tup_ratio
from pg_stat_all_tables
where n_live_tup + n_dead_tup <> 0
order by dead_tup_ratio desc;

3 膨胀的原理

3.1 什么是膨胀?膨胀率?

顾名思义,本来应该是一个大小,但是因为某种原因,它的大小变得更大了,甚至超乎想象的那么大。这就是发生了膨胀,而其中的膨胀的程度的体现,就是膨胀率。因此膨胀率可以直观的体现膨胀到底有多厉害。
反观数据库的膨胀的理解,一张A表或者A表的索引正常应该是占用一个大小的空间,但是查出来实际占用超过了这个空间的大小,往往随着时间的推移可能会占用的越来越来离谱。

3.2 哪些数据库元素会发生膨胀?


数据库表、索引

*索引实际会和表强关联,因此,可以比较泛指到就是表膨胀。

3.3 为什么会产生膨胀的现象?

之所以产生膨胀的原因跟PostgreSQL数据库的数据维护方式是息息相关的,
PG使用MVCC(多版本并发控制),
实际上MVCC是oracle、sqlserver数据库也使用的核心原理,但是新旧版本的数据存储的机制有所不同,因此造就了各个数据库在膨胀现象的表现有所不同。
sqlserver数据库:旧版本的数据专门写入到临时表中,新数据写入日志,然后再去更改数据。新旧分别放在不同的地方,膨胀的情况相对低一点,但是也会有这种情况发生,发生后,也需要按照SQLSERVER相关的处理方式进行。
oracle数据库:旧版本的数据放到UNDO,新数据放到REDO,然后更改数据。oracle数据库本身对redo、undo文件有自动清理、扩展的机制,因此总体来说对膨胀的控制相对可控,但是也不排除处问题的情况。有的时候也需要有重建undo文件的事情发生。
PG数据库:旧版本标示为无效,新数据写入日志,执行成功后把新版本的数据写入到新的位置。旧版本的数据在仍然是存储在表中,只是标示为无效,如果不及时做清理,那么无效的数据会占用空间越来越大,这样就发生了膨胀。

对于PG数据库,它把旧版本、新版本的表数据都同时存储在业务实际访问的表中,也称为数据页中,只是对于就旧版本的数据元组做了一个标记。因此,如果没有及时清理的话,导致数据库表臃肿,会很容易导致正常访问表的操作因此发生异常的现象。
delete、update操作会引发数据上的变化,因此,如果实际使用表会频繁出现删除和更新数据,这种情况下会很容易出现死亡元组,如果经常有大量数据的删除和更新,那么这个表会比较容易出现大的膨胀现象。

3.4 必须要做清理的原因?

PostgreSQL的VACUUM命令出于几个原因必须定期处理每一个表:

恢复或重用被已更新或已删除行所占用的磁盘空间。
更新被PostgreSQL查询规划器使用的数据统计信息。
更新可见性映射,它可以加速只用索引的扫描。
保护老旧数据不会由于事务ID回卷或多事务ID回卷而丢失。

VACUUM后,会更新pg_class等其他的表,会优化索引查询、优化执行计划等,进而达到恢复数据库表相关操作的性能。

3.5 VACUUM进度报告

只要VACUUM正在运行,每一个当前正在清理的后端(包括autovacuum工作者进程)在pg_stat_progress_vacuum视图中都会有一行。下面的表描述了将被报告的信息并且提供了如何解释它们的信息。VACUUM FULL命令的进度是通过pg_stat_progress_cluster报告的,因为VACUUM FULL和CLUSTER都是重写表,而普通的VACUUM只是原地修改表。

pg_stat_progress_vacuum视图说明:

序号类型描述
1pidinteger后端的进程ID。
2datidoid这个后端连接的数据库的OID。
3datnamename这个后端连接的数据库的名称。
4relidoid被vacuum的表的OID。
5phasetextvacuum的当前处理阶段。
6heap_blks_totalbigint该表中堆块的总数。这个数字在扫描开始时报告,之后增加的块将不会(并且不需要)被这个VACUUM访问。
7heap_blks_scannedbigint被扫描的堆块数量。由于可见性映射被用来优化扫描,一些块将被跳过而不做检查,被跳过的块会被包括在这个总数中,因此当清理完成时这个数字最终将会等于heap_blks_total。仅当处于扫描堆阶段时这个计数器才会前进。
8heap_blks_vacuumedbigint被清理的堆块数量。除非表没有索引,这个计数器仅在处于清理堆阶段时才会前进。不包含死亡元组的块会被跳过,因此这个计数器可能有时会向前跳跃一个比较大的增量。
9index_vacuum_countbigint已完成的索引清理周期数。
10max_dead_tuplesbigint在需要执行一个索引清理周期之前我们可以存储的死亡元组数,取决于maintenance_work_mem。
11num_dead_tuplesbigint从上一个索引清理周期以来收集的死亡元组数。

在这里插入图片描述

VACUUM的阶段:

序号阶段描述
1初始化VACUUM正在准备开始扫描堆。这个阶段应该很简短。
2扫描堆VACUUM正在扫描堆。如果需要,它将会对每个页面进行修建以及碎片整理,并且可能会执行冻结动作。heap_blks_scanned列可以用来监控扫描的进度。
3清理索引VACUUM当前正在清理索引。如果一个表拥有索引,那么每次清理时这个阶段会在堆扫描完成后至少发生一次。如果maintenance_work_mem不足以存放找到的死亡元组,则每次清理时会多次清理索引。
4清理堆VACUUM当前正在清理堆。清理堆与扫描堆不是同一个概念,清理堆发生在每一次清理索引的实例之后。如果heap_blks_scanned小于heap_blks_total,系统将在这个阶段完成之后回去扫描堆;否则,系统将在这个阶段完成后开始清理索引。
5清除索引VACUUM当前正在清除索引。这个阶段发生在堆被完全扫描并且对堆和索引的所有清理都已经完成以后。
6截断堆VACUUM正在截断堆,以便把关系尾部的空页面返还给操作系统。这个阶段发生在清除完索引之后。
7执行最后的清除VACUUM在执行最终的清除。在这个阶段中,VACUUM将清理空闲空间映射、更新pg_class中的统计信息并且将统计信息报告给统计收集器。当这个阶段完成时,VACUUM也就结束了。

4 如何处理表膨胀问题?

*注意考虑到业务忙时影响

4.1 简单粗暴但是有效彻底的空间回收:“vacuum full 表名”-不推荐


注意有失败的可能:
vacuum full 需要注意看看是否操作的表多大,磁盘空闲空间是否充足,否则会命令执行失败。
如果遇到了该问题,或者做之前,提前在服务器上进行磁盘空间释放,确保无用的文件再去删除。务必注意生产环境实施该操作要谨慎!高危!

4.1.1 FULL参数使用注意

序号vacuum full使用注意具体说明
用途通常用于需要从表中回收庞大的空间时候,而且最好是释放给操作系统使用,一般不建议使用。
1缺点需要给清理的表加上排它锁,执行操作期间对该表的insert、update、select、delete等操作会被阻塞
2缺点需要比较长的时间,时间长短跟表本身的大小以及膨胀的程度相关
3缺点需要临时额外占用操作系统上的磁盘空间,用于创建该表的新的拷贝,在操作执行完成前不会释放旧的拷贝。
1优点可以回收更多空间
2优点回收到的空间可以释放给操作系统,真正的物理上清理释放

选择“FULL”清理,它可以收回更多空间,并且需要更长时间和表上的排他锁。这种方法还需要额外的磁盘空间,因为它会创建该表的一个新拷贝,并且在操作完成之前都不会释放旧的拷贝。通常这种方法只用于需要从表中收回数量庞大的空间时。

不引入其他插件的情况下,如果能够挑选到业务不繁忙的时候或者说能够接受短时间内的锁表、功能卡顿的话,可以执行下面的语句:VACUUM FULL 具体表名;
使用前,务必关注上述列出的缺点。

4.1.2 FULL参数使用示例

膨胀的时候的空间占用,1个G左右:

test=# select schemaname||'.'||relname as table_name,pg_size_pretty(pg_relation_size(schemaname||'.'||relname)) as table_size,n_dead_tup,n_live_tup,round(n_dead_tup*100/(n_live_tup+n_dead_tup),1) as dead_tup_ratio
from pg_stat_all_tables
where n_live_tup + n_dead_tup <> 0 and relname='mytest';table_name   | table_size | n_dead_tup | n_live_tup | dead_tup_ratio
---------------+------------+------------+------------+----------------public.mytest | 1042 MB    |   10000001 |    5999859 |           62.0
(1 row)

完成回收后,空间占用下降到了391MB

test=# VACUUM FULL mytest;
VACUUM
test=#
test=# select schemaname||'.'||relname as table_name,pg_size_pretty(pg_relation_size(schemaname||'.'||relname)) as table_size,n_dead_tup,n_live_tup,round(n_dead_tup*100/(n_live_tup+n_dead_tup),1) as dead_tup_ratio
from pg_stat_all_tables
where n_live_tup + n_dead_tup <> 0 and relname='mytest';table_name   | table_size | n_dead_tup | n_live_tup | dead_tup_ratio
---------------+------------+------------+------------+----------------public.mytest | 391 MB     |          0 |    7481453 |            0.0
(1 row)

4.2 相对优雅一些的回收方式:“vacuum 表名”-推荐


注意可能有失败的可能:
1、长事务,如果当存在长时间运行的事务(长事务)对表进行操作(如insert、delete、update等操作且未提交),VACUUM操作会失效,因为此时的死元组对长事务是可见的,尽管对其他事务不可见,但仍然无法删除死元组‌。

如果碰到了,解决的办法就是,杀死长事务或者以后合理设置idle_in_transaction_session_timeout 参数,不要让连接不必要地“闲置在事务中”。配置参数idle_in_transaction_session_timeout可以被用来自动断开拖延会话的连接。
实际上,执行的失败提示信息中会写明有更旧的xmin水平

SELECT pid, datname, usename, state, backend_xmin
FROM pg_stat_activity
WHERE backend_xmin IS NOT NULL
ORDER BY age(backend_xmin) DESC;

查询到后,pg_terminate_backend(pid)来做终止事务
2、 废弃的复制槽 复制延迟或者备服务器关闭

SELECT slot_name, slot_type, database, xmin
FROM pg_replication_slots
ORDER BY age(xmin) DESC;

使用pg_drop_replication_slot()删除复制槽

test=# select  pg_drop_replication_slot('aaaa');

3、孤立的准备事务 某种异常情况下,导致事务处于准备好的状态但是未继续提交或者中止。

SELECT gid, prepared, owner, database, transaction AS xmin
FROM pg_prepared_xacts
ORDER BY age(transaction) DESC;
ROLLBACK PREPARED transaction_id
例如:ROLLBACK PREPARED '123'

4.2.1 标准的vacuum(不带full参数的方式)

序号标准vacuum使用注意使用说明
1用途推荐日常使用,设置合理定时在非忙时执行,但是VACUUM使用过程会带来I/O流量的的产生,会导致数据库其他会话的操作性能变差,因此使用过程中需要搭配一些策略参数来防护后台清理工作给数据库性能带来的冲击。例如:vacuum_cost_delay、vacuum_cost_page_hit 、vacuum_cost_page_miss 、vacuum_cost_page_dirty 、vacuum_cost_limit 将导致清理进程休眠的累计代价。默认值为200。
1缺点标准的vacuum完成回收后的空间不会实际释放给操作系统,只是标记为继续给当前的表或者索引复用。当膨胀的程度很高的时候,该方式无法释放占用空间给物理服务器操作系统使用。除非在特殊的情况中表尾部的一个或多个页面变成完全空闲并且能够很容易地得到一个排他表锁。
2缺点执行过程中会可能产生大量I/O流量,对数据库处理性能产生一定负面影响。
1优点不阻塞基础数据库表增删改查,标准形式的VACUUM可以和生产数据库操作并行运行(SELECT、INSERT、UPDATE和DELETE等命令将继续正常工作,但在清理期间你无法使用ALTER TABLE等命令来更新表的定义)
2优点执行耗时相对FULL参数方式较短

4.2.2 标准VACUUM回收清理使用示例

回收清理前,表占用的大小空间table_size是781M,膨胀比例为50%,
执行标准的回收后,表占用的大小空间table_size还是781M,死亡元组为0。
pg_stat_all_tables字段 last_autovacuum 表示最近一次自动回收的时间。

test=# select schemaname||'.'||relname as table_name,pg_size_pretty(pg_relation_size(schemaname||'.'||relname)) as table_size,n_dead_tup,n_live_tup,round(n_dead_tup*100/(n_live_tup+n_dead_tup),1) as dead_tup_ratio
from pg_stat_all_tables
where n_live_tup + n_dead_tup <> 0 and relname='mytest';table_name   | table_size | n_dead_tup | n_live_tup | dead_tup_ratio
---------------+------------+------------+------------+----------------public.mytest | 781 MB     |    6000001 |    5995257 |           50.0
(1 row)test=# \timing on
Timing is on.
test=# vacuum mytest;
VACUUM
Time: 29512.550 ms (00:29.513)
test=# select schemaname||'.'||relname as table_name,pg_size_pretty(pg_relation_size(schemaname||'.'||relname)) as table_size,n_dead_tup,n_live_tup,round(n_dead_tup*100/(n_live_tup+n_dead_tup),1) as dead_tup_ratio
from pg_stat_all_tables
where n_live_tup + n_dead_tup <> 0 and relname='mytest';table_name   | table_size | n_dead_tup | n_live_tup | dead_tup_ratio
---------------+------------+------------+------------+----------------public.mytest | 781 MB     |          0 |    2997602 |            0.0
(1 row)Time: 124.583 ms
test=#

再次执行vacuum full mytest,再查询表占用大小table_size为391M,空间直接释放了一半,这是把空间释放到了操作系统的效果。

test=# vacuum full mytest;
VACUUM
Time: 54052.374 ms (00:54.052)
test=# select schemaname||'.'||relname as table_name,pg_size_pretty(pg_relation_size(schemaname||'.'||relname)) as table_size,n_dead_tup,n_live_tup,round(n_dead_tup*100/(n_live_tup+n_dead_tup),1) as dead_tup_ratio
from pg_stat_all_tables
where n_live_tup + n_dead_tup <> 0 and relname='mytest';table_name   | table_size | n_dead_tup | n_live_tup | dead_tup_ratio
---------------+------------+------------+------------+----------------public.mytest | 391 MB     |          0 |    5972470 |            0.0
(1 row)Time: 22.492 ms
test=#

4.2.3 标准vacuum支持多个option命令方式:vacuum (verbose,analyze) mytest;

VERBOSE
为每个表打印一份详细的清理活动报告。

ANALYZE
更新优化器用以决定最有效执行一个查询的方法的统计信息。

test=# vacuum (verbose,analyze) mytest;
INFO:  vacuuming "public.mytest"
INFO:  index "mytest_pkey" now contains 6000001 row versions in 32905 pages
DETAIL:  0 index row versions were removed.
16450 index pages have been deleted, 16450 are currently reusable.
CPU: user: 0.10 s, system: 0.27 s, elapsed: 0.65 s.
INFO:  "mytest": found 0 removable, 2 nonremovable row versions in 1 out of 100001 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 853
There were 0 unused item pointers.
Skipped 0 pages due to buffer pins, 50000 frozen pages.
0 pages are entirely empty.
CPU: user: 0.11 s, system: 0.27 s, elapsed: 0.66 s.
INFO:  vacuuming "pg_toast.pg_toast_16779"
INFO:  index "pg_toast_16779_index" now contains 0 row versions in 1 pages
DETAIL:  0 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO:  "pg_toast_16779": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 853
There were 0 unused item pointers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO:  analyzing "public.mytest"
INFO:  "mytest": scanned 30000 of 100001 pages, containing 1793880 live rows and 0 dead rows; 30000 rows in sample, 5979660 estimated total rows
VACUUM
Time: 2096.122 ms (00:02.096)
test=#

4.3 模拟大表膨胀的简单方法

create table student(id int primary key, sname varchar(10), sex int, description text);
insert into student values(generate_series(1,20000000),'test', 1, now());
update student set description='123.123.123' where id>10000000;
delete from student where id <=10000;

另外可以使用定时循环执行update语句持续增加死亡元组。

\watch 1 update student set description='123.123.123' where id>10000000;

5 膨胀产生后的危害&如何长远应对?

5.1 产生哪些危害?

如果对于膨胀的情况听之任之的化,看得见的危害有哪些呢?按照出现的时间序来看:
第一、数据库表占用空间越来越大
第二、数据库对执行计划的选择不是最高效的
第三、普通的数据库表插入、删除、查询都变慢了
第四、突然有一天发现整个系统都慢起来了
第五、发现数据库磁盘配额报告警了
第六、扩展磁盘配额后,过段时间又继续报数据库磁盘配额不足
第七、数据库所在服务器磁盘空间不足
第八、所有和数据库部署在同一个服务器上的应用无法正常创建文件
第九、整个服务器系统宕机了

看起来就是慢慢恶化的过程,实际情况的确也会劣化的非常快。

5.2 如何应对?

序号产生膨胀的可能原因应对举措
1delete减少大量的删除动作,优化删除语句效率,减少耗时。常规建议开启autovacuum进行清理回收。
2update减少大量更新动作,优化更新语句效率,减少耗时。常规建议开启autovacuum进行清理回收。
3select长时间占用优化select查询语句,降低执行查询耗时。减少针对大表的全表扫描。
4索引创建常规建议开启autovacuum进行清理回收。
5数据库事务回滚常规建议开启autovacuum进行清理回收。
6系统异常导致的其他意外情况常规建议开启autovacuum进行清理回收。必要的时候执行vacuum full手动回收。
7IO性能较差优化磁盘使用计划,避免磁盘I/O浪费,减少任务堆积访问数据库配置SSD,或者调整raid模式到I/O更好的方式。
8内存资源紧张建议根据业务特性情况,考虑到业务峰值情况,尽量分配充分的内存资源。且内存的分配要充分考虑PG数据库系统参数的各个值,包括work_mem、shared_buffer等
9CPU资源紧张建议根据业务特性情况,考虑到业务峰值情况,尽量分配充分的CPU资源。
10磁盘资源不足max_wal_size和wal_segment_size,特别是前面的max_wal_size在业务量存在突发海量更新数据的情况下,这个参数需要扩大,具体可以扩大到多少需要充分考虑一下磁盘的空闲空间。 如果这个值设置不当会引起主备PG同步复制流中断。
10PG系统参数设置不合理适当针对部分PG参数进行调优,shared_buffers 、temp_buffers 、max_prepared_transactions 、work_mem 、maintenance_work_mem 等PG参数调优
11没有开启自动回收清理建议开启autovacuum,但是需要根据各自的业务特性确定自动运行回收的策略。另外注意,这个开关可以控制到具体的表级别。执行命令show autovacuum查看开启状态。它的目的是自动执行VACUUM和ANALYZE 命令。当它被启用时,自动清理会检查被大量插入、更新或删除元组的表。这些检查会利用统计信息收集功能,因此除非track_counts被设置为true,自动清理不能被使用。在默认配置下,自动清理是被启用的并且相关配置参数已被正确配置。
12操作系统或者服务器或者数据库异常关闭检查是否有发生膨胀,可以使用vacuum手动清理。

修改具体表的自动回收开关autovacuum,例如:

test=# show autovacuum;autovacuum
------------on
(1 row)test=#
test=# alter table mytest set (autovacuum_enabled=on);
ALTER TABLE
test=# \d+ mytestTable "public.mytest"Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | D
escription
--------+---------+-----------+----------+---------+----------+--------------+--
-----------a      | integer |           | not null |         | plain    |              |b      | text    |           |          |         | extended |              |
Indexes:"mytest_pkey" PRIMARY KEY, btree (a)
Options: autovacuum_enabled=on

6 总结

  • 减少或者降低膨胀的程度
    总之,轻微膨胀本身并无多大的危害,且日常操作正常来说也的确是会产生死亡元组,但是过度膨胀,例如:膨胀率超过50%以上,那么需要重点关注。如何避免过度膨胀,其中有效的方式核心来说,包括3点:
    第一、合理设置自动回收autovacuum。
    第二、尽可能的让各个数据库操作快速完成。(手段包括但不限于:数据库表设计调优、索引调优、SQL语句调优、PG数据库参数调优、服务器资源调优等。)
    第三、尽可能减少冗余的删除和修改数据,减少一个事务长时间运行。
  • 进行日常检查
    定期检查数据库健康状态,包括但不限于:
    第一、服务器的磁盘、内存、cpu占用情况。
    第二、膨胀的程度监控,出现很大的膨胀率的时候,先安排vacuum,必要时尽快安排vacuum full。
    第三、记录膨胀表的情况,后续针对性安排可能的优化。



相关文章:

【PostgreSQL】PG数据库表“膨胀”粗浅学习

文章目录 1 为什么需要关注表膨胀&#xff1f;2 如何确定是否发生了表膨胀&#xff1f;2.1 通过查询表的死亡元组占比情况来判断膨胀率2.1.1 指定数据库和表名2.1.2 查询数据库里面所有表的膨胀情况 3 膨胀的原理3.1 什么是膨胀&#xff1f;膨胀率&#xff1f;3.2 哪些数据库元…...

力扣(leetcode)每日一题 871 最低加油次数 | 贪心

871. 最低加油次数 题干 汽车从起点出发驶向目的地&#xff0c;该目的地位于出发位置东面 target 英里处。 沿途有加油站&#xff0c;用数组 stations 表示。其中 stations[i] [positioni, fueli] 表示第 i 个加油站位于出发位置东面 positioni 英里处&#xff0c;并且有 f…...

ppt压缩文件怎么压缩?压缩PPT文件的多种压缩方法

ppt压缩文件怎么压缩&#xff1f;当文件体积过大时&#xff0c;分享和传输就会变得困难。许多电子邮件服务对附件的大小有限制&#xff0c;而在网络环境不佳时&#xff0c;上传和下载大文件可能耗时较长。此外&#xff0c;在不同设备上播放时&#xff0c;较大的PPT文件还可能导…...

2024.10月11日--- SpringMVC拦截器

拦截器 1 回顾过滤器&#xff1a; Servlet规范中的三大接口&#xff1a;Servlet接口&#xff0c;Filter接口、Listener接口。 过滤器接口&#xff0c;是Servlet2.3版本以来&#xff0c;定义的一种小型的&#xff0c;可插拔的Web组件&#xff0c;可以用来拦截和处理Servlet容…...

uniapp 锁屏显示插件 Ba-LockShow(可让vue直接具备锁屏显示能力)

简介 Ba-LockShow 是一款可以直接使uniapp的vue界面在锁屏页展示的插件。 支持使vue直接具备锁屏显示能力支持设置锁屏显示和不显示支持唤醒屏幕 截图展示&#xff08;仅参考&#xff09; 支持定制、本地包、源码等&#xff0c;有建议和需要&#xff0c;请点击文章结尾“Unia…...

CSS计数器

CSS 中的计数器类似于变量&#xff0c;可以实现简单的计数功能&#xff0c;并将结果显示在页面上&#xff0c;在早期的网站上应用比较广泛。要实现计数器需要用到以下几个属性&#xff1a; counter-reset&#xff1a;创建或者重置计数器&#xff1b;counter-increment&#xf…...

嵌入式Linux:信号集

目录 1、信号集初始化 2、向信号集中添加或删除信号 3、测试信号是否在信号集中 在 Linux 系统中&#xff0c;处理多个信号时常用到一种数据结构&#xff1a;信号集&#xff08;sigset_t&#xff09;。信号集允许我们将多个信号组织在一起&#xff0c;以便在系统调用中传递和…...

Linux 外设驱动 应用 1 IO口输出

从这里开始外设驱动介绍&#xff0c;这里使用的IMX8的芯片作为驱动介绍 开发流程&#xff1a; 修改设备树&#xff0c;配置 GPIO1_IO07 为 GPIO 输出。使用 sysfs 接口或编写驱动程序控制 GPIO 引脚。编译并测试。 这里假设设备树&#xff0c;已经配置好了。不在论述这个问题…...

基于SpringBoot+Vue+MySQL的留守儿童爱心网站

系统展示 用户前台界面 管理员后台界面 系统背景 随着现代社会的发展&#xff0c;留守儿童问题日益受到关注。传统的纸质管理方式已经无法满足现代人们对留守儿童爱心信息的需求。为了提高留守儿童爱心信息的管理效率&#xff0c;增加用户信息的安全性&#xff0c;并方便及时反…...

调用第三方接口

目录 一、分析给出的接口文档 二、请求体格式之间的区别 三、示例代码 一、分析给出的接口文档 一般的接口文档包括以下几大部分&#xff1a; 1、请求URL&#xff1a;http://{ip}:{port}/api/ec/dev/message/sendCustomMessageSingle 2、请求方式&#xff1a;POST、GET等 3、…...

JAVA 多线程入门例子:CountDownLatch

首先确定线程数量。如果数据集合的大小小于50&#xff0c;就只使用一个线程&#xff1b;否则使用5个线程。计算每个线程平均处理的数据数量sizePerThread以及余数remainder。在划分数据子集合时&#xff0c;对于每个线程的处理范围进行计算。如果有余数&#xff0c;就将余数依次…...

k8s jenkins 动态创建slave

k8s jenkins 动态创建slave 简述使用jenkins动态slave的优势&#xff1a;配置jenkins动态slave配置 Pod Template配置容器模板挂载卷 测试 简述 持续构建与发布是我们日常工作中必不可少的一个步骤&#xff0c;目前大多公司都采用 Jenkins 集群来搭建符合需求的 CI/CD 流程&am…...

MVS海康工业相机达不到标称最大帧率

文章目录 一、相机参数设置1、取消相机帧率限制2、修改相机图像格式3、调整相机曝光时间4、检查相机数据包大小&#xff08;网口相机特有参数&#xff09;5、 恢复相机默认参数6、 相机 ADC 输出位深调整 二、系统环境设置1、 网口相机设置2、 USB 相机设置 一、相机参数设置 …...

数据结构:用双栈实现一个队列

要用两个栈实现一个队列&#xff0c;可以利用“栈”的后进先出 (LIFO) 特性来模拟“队列”的先进先出 (FIFO) 操作。具体做法是使用两个栈&#xff1a;一个作为入栈栈&#xff0c;另一个作为出栈栈。 算法步骤 入队操作&#xff08;enqueue&#xff09;&#xff1a; 将元素压…...

QScroller Class

Header:#include < QScroller > qmake:QT += widgets Since:Qt 5.0 Inherits:QObject This class was introduced in Qt 5.0. Public Types enum Input {InputPress, InputMove, InputRelease } enum ScrollerGestureType {TouchGesture, LeftMouseButtonGesture,…...

React高阶组件详解

React高阶组件&#xff08;HOC&#xff09;详解 定义 React高阶组件&#xff08;HOC&#xff09;是一个函数&#xff0c;该函数接受一个组件作为参数并返回一个新的组件。高阶组件本身不是一个组件&#xff0c;而是一个函数&#xff0c;它利用React的组合特性&#xff0c;对传入…...

TextView把其它控件挤出屏幕的处理办法

1.如果TextView后面的控件是紧挨着TextView的&#xff0c;可以给TextView添加maxWidth限制其最大长度 上有问题的布局代码 <?xml version"1.0" encoding"utf-8"?> <layout xmlns:android"http://schemas.android.com/apk/res/android&qu…...

长度为 K 的重复字符子串数目

长度为 K 的重复字符子串 给你一个由小写字母组成的长度为n的字符串 S &#xff0c;找出所有长度为 k 且包含重复字符的子串&#xff0c;请你返回全部满足要求的子串的数目。 数据范围&#xff1a; 2≤k≤400 , 5≤n≤900 进阶&#xff1a; 时间复杂度O(n)&#xff0c;空间复杂…...

html+css+js实现轮播图

实现效果&#xff1a; HTML部分 <div class"carousel"><div class"carousel-wrapper"><img src"./image/1.png" alt""></div><ul class"carousel-indictor"><li class"active"…...

Boost集成模型异同

一、常见Boost集成模型 AdaBoost、GBDT和XGBoost都是集成学习中的提升&#xff08;Boosting&#xff09;算法&#xff0c;它们通过组合多个弱学习器来构建一个强学习器。从经验上来说&#xff0c;XGBoost是诸多竞赛的大杀器&#xff0c;在实际业务工作中可能需要用到集成模型的…...

【系统架构设计师】案例专题四:嵌入式系统考点梳理

更多内容请见: 备考系统架构设计师-核心总结目录 摘要:本文主要梳理系统架构设计师 - 嵌入式系统 案例考点 ,主要包括嵌入式相关概念、软件和硬件可靠性、冗余技术、软件容错、集群技术、负载均衡、可维护性的评价指标、软件维护的分类等。 文章目录 一、相关概念二、软件可…...

Ngin入门套餐

快速了解Nginx 一、代理1.1 正向代理1.2 反向代理1.3 正向代理和反向代理的区别 二、Nginx负载均衡策略2.1 轮询&#xff08;Round Robin&#xff09;2.2 加权轮询&#xff08;Weighted Round Robin&#xff09;2.3 IP 哈希&#xff08;IP Hash&#xff09;2.4 最少连接&#x…...

使用linux编译main.cpp文件

1、首先创建一个简单的test.cpp&#xff0c;使用终端命令形式&#xff1a; touch test.cpp 创建结束&#xff0c;记得ls一下&#xff0c;如下&#xff1a; 2、找到创建结束的test.cpp文件&#xff0c;然后右键编辑&#xff0c;输入一个简单的代码&#xff0c;如下 #include …...

服务器部署‌Traefik 实现子级域名路由服务(对外子域名80,路由对内大端口)

文章目录 1.‌Traefik安装2.启动nginx配置路由 本文档只是为了留档方便以后工作运维&#xff0c;或者给同事分享文档内容比较简陋命令也不是特别全&#xff0c;不适合小白观看&#xff0c;如有不懂可以私信&#xff0c;上班期间都是在得 前言&#xff0c;领导让我调研在线发布得…...

@RequestParam @PathVirable @RequestBody @ApiParam的区别

RequestParam 最常用用value指定参数名字&#xff0c;required字段指定参数是否必须&#xff0c;默认为true&#xff0c;当requiredfalse时&#xff0c;一般配合着defaultValue"xx"使用对应的url是这样的&#xff1a; https://localhost/requestParam/test?key1va…...

Vulnhub靶场案例渗透[5]- DC4

文章目录 1. 靶场搭建2. 信息收集2.1 确定靶机ip2.2 主机信息收集2.3 主机目录探测 3. 渗透过程3.1 sql注入检测3.2 burp爆破3.3 反弹shell3.4 提权 4. 总结 1. 靶场搭建 靶场源地址 检验下载文件的检验码&#xff0c;对比没问题使用vmware打开 # windwos 命令 Get-FileHash …...

http协议概述与状态码

目录 1.HTTP概述 1.1请求报文起始行与开头 ​1.2响应报文起始行 ​ 1.3响应报文开头 ​ 2.http状态协议码 1.HTTP概述 默认端口 80 HTTP超文本传输与协议: 数据请求和响应 传输:将网站的数据传递给用户 超文本:图片 视频等 请求request:打开网站 访问网站 响应r…...

Golang 进阶5—— 反射

Golang 进阶5—— 反射 注意&#xff0c;该文档只适合有编程基础的同学&#xff0c;这里的go教程只给出有区别的知识点 反射&#xff1a; 反射可以在运行时动态获取变量的各种信息&#xff0c; 比如变量的类型、 类别等信息。如果是结构体变量&#xff0c;还可以获取结构体本…...

react 封装防抖

封装防抖 import React, { useRef, useEffect, useCallback } from react;function useDebounce(fn, delay) {const delayRef useRef(delay);const fnRef useRef(fn);// 更新ref值useEffect(() > {delayRef.current delay;}, [delay]);useEffect(() > {fnRef.current…...

Java项目-----图形验证码登陆实现

原理: 验证码在前端显示,但是是在后端生成, 将生成的验证码存入redis,待登录时,前端提交验证码,与后端生成的验证码比较. 详细解释: 图形验证码的原理(如下图代码).前端发起获取验证码的请求后, 1 后端接收请求,生成一个键key(随机的键) 然后生成一个验证码作为map的valu…...