Endless lseek导致的SQL异常

news/2024/4/25 15:02:35/文章来源:https://blog.csdn.net/weixin_39540651/article/details/129166839

最近碰到同事咨询的一个问题,在执行一个函数时,发现会一直卡在那里。

strace抓了下发现会话一直在执行lseek,大致情况如下:

16:13:55.451832 lseek(33, 0, SEEK_END) = 1368064 <0.000037>
16:13:55.477216 lseek(33, 0, SEEK_END) = 1368064 <0.000026>
16:13:55.502579 lseek(33, 0, SEEK_END) = 1368064 <0.000026>
16:13:55.528162 lseek(33, 0, SEEK_END) = 1368064 <0.000024>
16:13:55.553714 lseek(33, 0, SEEK_END) = 1368064 <0.000025>
16:13:55.579242 lseek(33, 0, SEEK_END) = 1368064 <0.000022>
......% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 124 lseek
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 124 total

而当手动去取消掉会话时也能发现,是卡在了其中一个insert语句:

[postgres@xxx/(rasesql)himsdpsods][02-22.16:13:24]M=# select pgawr_snap('cron based snapshot',59451);
^CCancel request sent
ERROR: 57014: canceling statement due to user request
CONTEXT: SQL statement "INSERT INTO pgawr_indexes
( snapid, idx_scan, idx_tup_read, idx_tup_fetch, idx_blks_read,
idx_blks_hit, index_name_id, table_name_id)
SELECT
spid as snapid,
i.idx_scan as idx_scan,
i.idx_tup_read as idx_tup_read,
i.idx_tup_fetch as idx_tup_fetch,
ii.idx_blks_read as idx_blks_read,
ii.idx_blks_hit as idx_blks_hit,
n1.nameid,
n2.nameid
FROM
pg_stat_all_indexes i
join pg_statio_all_indexes ii on i.indexrelid = ii.indexrelid
join pgawr_names n1 on i.schemaname ||'.'|| i.indexrelname=n1.name
join pgawr_names n2 on i.schemaname ||'.'|| i.relname=n2.name"
PL/pgSQL function pgawr_snap(character varying,bigint) line 104 at SQL statement
LOCATION: ProcessInterrupts, postgres.c:3203
Time: 203994.651 ms (03:23.995)

当然分析这种函数执行慢的,最常用的还是auto_explain,可以在会话中设置来打印函数中具体执行的情况:

load 'auto_explain';set client_min_messages='log';
set auto_explain.log_min_duration = 0;
set auto_explain.log_analyze = true;
set auto_explain.log_verbose = true;
set auto_explain.log_buffers = true;
set auto_explain.log_nested_statements = true;

根据上面得到的信息发现文件句柄33对应的恰好也是该SQL中的一张表,而lseek(33, 0, SEEK_END) = 1368064的返回值也的确是和该数据文件的大小一致,说明的确是扫描完该表了。

那就有点奇怪了,这个SQL也很简单,而且单独拿出来执行也都没问题,为什么会一直卡在lseek这个数据文件这里呢?

上网搜了下,发现有个类似的bug:BUG #15455: Endless lseek,其中的情况和我这个有些类似:

 

但是往后看了malilist里面的讨论也是不了了之,最终也没有个结论。。。

哎,没有办法,只能自己接着分析了。

为了方便查看,我这里把SQL简写了,insert也换成select。

[postgres@xxx/(rasesql)himsdpsods][02-22.16:40:10]M=# EXPLAIN ANALYZE SELECT
->   i.idx_scan         as idx_scan,
->   i.idx_tup_read     as idx_tup_read,
->   i.idx_tup_fetch    as idx_tup_fetch,
->   ii.idx_blks_read   as idx_blks_read,
-> ii.idx_blks_hit    as idx_blks_hit,
->   n1.nameid
->  FROM
->   pg_stat_all_indexes i
->   join pg_statio_all_indexes ii on i.indexrelid = ii.indexrelid
->   join pgawr_names n1 on i.schemaname ||'.'|| i.indexrelname=n1.name;QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------Nested Loop  (cost=1805.21..3055.18 rows=3 width=44) (actual time=0.381..0.384 rows=0 loops=1)Join Filter: ((((n.nspname)::text || '.'::text) || (i.relname)::text) = (n1.name)::text)->  Seq Scan on pgawr_names n1  (cost=0.00..228.00 rows=1 width=44) (actual time=0.380..0.381 rows=0 loops=1)->  Nested Loop  (cost=1805.21..2815.83 rows=502 width=136) (never executed)->  Hash Join  (cost=1804.92..2585.91 rows=502 width=140) (never executed)Hash Cond: (c.relnamespace = n.oid)->  Nested Loop  (cost=1801.01..2580.62 rows=502 width=80) (never executed)->  Hash Join  (cost=1800.73..2057.32 rows=900 width=12) (never executed)Hash Cond: (x.indexrelid = x_1.indexrelid)->  Hash Join  (cost=766.65..1005.74 rows=2267 width=8) (never executed)Hash Cond: (x.indrelid = c.oid)->  Seq Scan on pg_index x  (cost=0.00..224.09 rows=5709 width=8) (never executed)->  Hash  (cost=715.81..715.81 rows=4067 width=8) (never executed)->  Seq Scan on pg_class c  (cost=0.00..715.81 rows=4067 width=8) (never executed)Filter: (relkind = ANY ('{r,t,m}'::"char"[]))->  Hash  (cost=1005.74..1005.74 rows=2267 width=4) (never executed)->  Hash Join  (cost=766.65..1005.74 rows=2267 width=4) (never executed)Hash Cond: (x_1.indrelid = c_1.oid)->  Seq Scan on pg_index x_1  (cost=0.00..224.09 rows=5709 width=8) (never executed)->  Hash  (cost=715.81..715.81 rows=4067 width=8) (never executed)->  Seq Scan on pg_class c_1  (cost=0.00..715.81 rows=4067 width=8) (never executed)Filter: (relkind = ANY ('{r,t,m}'::"char"[]))->  Index Scan using pg_class_oid_index on pg_class i  (cost=0.29..0.58 rows=1 width=68) (never executed)Index Cond: (oid = x.indexrelid)->  Hash  (cost=2.85..2.85 rows=85 width=68) (never executed)->  Seq Scan on pg_namespace n  (cost=0.00..2.85 rows=85 width=68) (never executed)->  Index Only Scan using pg_class_oid_index on pg_class i_1  (cost=0.29..0.46 rows=1 width=4) (never executed)Index Cond: (oid = i.oid)Heap Fetches: 0

可以看到卡住的SQL拿出来单独执行是没有问题的,但是仔细观察可以发现,该执行计划中很多never executed的节点,说明下面的这些部分实际都没有执行,那是因为pgawr_names这张表是空的,因此对于这个嵌套循环来说,被驱动的部分其实就没有必要执行了。

而查看完该函数的内容之后发现,在执行这个SQL之前是有往pgawr_names这张表里面插入数据的。

这样一下子就有思路了:因为在同一个会话中,前一条SQL往pgawr_names表里面插入了大量数据,而表的统计信息在会话提交前是不会更新的。

[postgres@xxx/(rasesql)himsdpsods][02-22.16:54:40]M=# begin;
BEGIN
Time: 0.128 ms[postgres@xxx/(rasesql)himsdpsods][02-22.16:55:11]M=# select n_live_tup,last_analyze from pg_stat_all_tables where relname = 'pgawr_names';
n_live_tup | last_analyze
------------+-------------------------------
0 | 2023-02-22 15:09:43.348236+08
(1 row)Time: 11.319 ms
[postgres@xxx/(rasesql)himsdpsods][02-22.16:55:27]M=# insert into pgawr_names (name)
-> select distinct i.schemaname ||'.'|| i.indexrelname
-> from pg_stat_all_indexes i
-> left join pgawr_names on i.schemaname ||'.'|| i.indexrelname=name
-> where
-> name is null;
INSERT 0 5709
Time: 207.526 ms[postgres@xxx/(rasesql)himsdpsods][02-22.16:55:41]M=# ANALYZE pgawr_names ;
ANALYZE
Time: 73.666 ms[postgres@xxx/(rasesql)himsdpsods][02-22.16:55:46]M=# select n_live_tup,last_analyze from pg_stat_all_tables where relname = 'pgawr_names';
n_live_tup | last_analyze
------------+-------------------------------
0 | 2023-02-22 15:09:43.348236+08
(1 row)Time: 0.876 ms

既然如此,看来前面看到的会话一直卡在lseek其实是执行计划后面的嵌套循环太多导致的,我们可以把pgawr_names表中手动插入较少的数据来验证下:

[postgres@xxx:6266/(rasesql)himsdpsods][02-22.17:02:00]M=# begin;
BEGIN
Time: 0.141 ms
[postgres@xxx:6266/(rasesql)himsdpsods][02-22.17:02:02]M=# select n_live_tup,last_analyze from pg_stat_all_tables where relname = 'pgawr_names';n_live_tup |         last_analyze
------------+-------------------------------0 | 2023-02-22 17:01:53.272047+08
(1 row)Time: 11.615 ms
[postgres@xxx:6266/(rasesql)himsdpsods][02-22.17:02:03]M=# insert into pgawr_names(name) select md5(random()::text) from generate_series(1,200);
INSERT 0 200
Time: 52.083 ms
[postgres@xxx:6266/(rasesql)himsdpsods][02-22.17:02:28]M=# EXPLAIN ANALYZE SELECT
->   i.idx_scan         as idx_scan,
->   i.idx_tup_read     as idx_tup_read,
->   i.idx_tup_fetch    as idx_tup_fetch,
->   ii.idx_blks_read   as idx_blks_read,
-> ii.idx_blks_hit    as idx_blks_hit,
->   n1.nameid
->  FROM
->   pg_stat_all_indexes i
->   join pg_statio_all_indexes ii on i.indexrelid = ii.indexrelid
->   join pgawr_names n1 on i.schemaname ||'.'|| i.indexrelname=n1.name;QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------Nested Loop  (cost=1805.21..3055.18 rows=3 width=44) (actual time=5618.220..5618.229 rows=0 loops=1)Join Filter: ((((n.nspname)::text || '.'::text) || (i.relname)::text) = (n1.name)::text)Rows Removed by Join Filter: 1141800->  Seq Scan on pgawr_names n1  (cost=0.00..228.00 rows=1 width=44) (actual time=0.014..0.417 rows=200 loops=1)->  Nested Loop  (cost=1805.21..2815.83 rows=502 width=136) (actual time=0.071..26.143 rows=5709 loops=200)->  Hash Join  (cost=1804.92..2585.91 rows=502 width=140) (actual time=0.069..16.342 rows=5709 loops=200)Hash Cond: (c.relnamespace = n.oid)->  Nested Loop  (cost=1801.01..2580.62 rows=502 width=80) (actual time=0.068..14.519 rows=5709 loops=200)->  Hash Join  (cost=1800.73..2057.32 rows=900 width=12) (actual time=0.066..4.280 rows=5709 loops=200)Hash Cond: (x.indexrelid = x_1.indexrelid)->  Hash Join  (cost=766.65..1005.74 rows=2267 width=8) (actual time=0.028..2.815 rows=5709 loops=200)Hash Cond: (x.indrelid = c.oid)->  Seq Scan on pg_index x  (cost=0.00..224.09 rows=5709 width=8) (actual time=0.002..0.833 rows=5709 loops=200)->  Hash  (cost=715.81..715.81 rows=4067 width=8) (actual time=5.083..5.085 rows=4070 loops=1)Buckets: 4096  Batches: 1  Memory Usage: 191kB->  Seq Scan on pg_class c  (cost=0.00..715.81 rows=4067 width=8) (actual time=0.010..4.506 rows=4070 loops=1)Filter: (relkind = ANY ('{r,t,m}'::"char"[]))Rows Removed by Filter: 6170->  Hash  (cost=1005.74..1005.74 rows=2267 width=4) (actual time=7.443..7.445 rows=5709 loops=1)Buckets: 8192 (originally 4096)  Batches: 1 (originally 1)  Memory Usage: 265kB->  Hash Join  (cost=766.65..1005.74 rows=2267 width=4) (actual time=4.328..6.637 rows=5709 loops=1)Hash Cond: (x_1.indrelid = c_1.oid)->  Seq Scan on pg_index x_1  (cost=0.00..224.09 rows=5709 width=8) (actual time=0.005..1.006 rows=5709 loops=1)->  Hash  (cost=715.81..715.81 rows=4067 width=8) (actual time=4.312..4.313 rows=4070 loops=1)Buckets: 4096  Batches: 1  Memory Usage: 191kB->  Seq Scan on pg_class c_1  (cost=0.00..715.81 rows=4067 width=8) (actual time=0.009..3.746 rows=4070 loops=1)Filter: (relkind = ANY ('{r,t,m}'::"char"[]))Rows Removed by Filter: 6170->  Index Scan using pg_class_oid_index on pg_class i  (cost=0.29..0.58 rows=1 width=68) (actual time=0.001..0.001 rows=1 loops=1141800)Index Cond: (oid = x.indexrelid)->  Hash  (cost=2.85..2.85 rows=85 width=68) (actual time=0.038..0.039 rows=85 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 17kB->  Seq Scan on pg_namespace n  (cost=0.00..2.85 rows=85 width=68) (actual time=0.010..0.023 rows=85 loops=1)->  Index Only Scan using pg_class_oid_index on pg_class i_1  (cost=0.29..0.46 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=1141800)Index Cond: (oid = i.oid)Heap Fetches: 1141800Planning Time: 3.383 msExecution Time: 5618.715 ms
(38 rows)Time: 5623.090 ms (00:05.623)

发现果然如此,仅仅插入了200条数据而已,循环次数就达到了1141800次(5709*200)。而在原先的函数中往pgawr_names表中插入了有5000多条数据,这意味着至少要循环1千万次,这也是为什么会觉得SQL一直卡住在执行lseek的原因了。

回头再去看BUG #15455: Endless lseek,其实也是类似的原因,由于在会话中表数据量变化较多,而统计信息无法更新,同时SQL中有嵌套循环,导致性能异常,陷入了endless lseek中。

 

对此我们需要注意了,如果在同一个事务中先对某张表进行大量的增删操作,又由于其统计信息在事务结束前是不会更新的,而恰好该事务后面又有相关查询使用了该表,可能会对性能产生巨大影响,而如果该SQL中又包含较多嵌套循环,那么你也可能陷入看上去无休无止的lseek中了~

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

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

相关文章

linux下安装mongoDB

一、下载mongoDB包 下载地址&#xff1a; https://www.mongodb.com/try/download/community 个人建议&#xff1a;如果是学习阶段&#xff0c;使用5以下版本更好些。 二、安装及配置 1、安装 # 1、解压 $ tar -zxvf mongodb-linux-x86_64-rhel70-4.4.19-rc1.tgz# 2、迁移目…

【音视频处理】为什么MP3不是无损音乐?音频参数详解,码率、采样率、音频帧、位深度、声道、编码格式的关系

大家好&#xff0c;欢迎来到停止重构的频道。上期我们讨论了视频的相关概念&#xff0c;本期我们讨论音频的相关概念。包括采样率、码率、单双声道、音频帧、编码格式等概念。这里先抛出一个关于无损音频的问题。为什么48KHz采样率的.mp3不是无损音乐 &#xff0c;而48KHz采样率…

高性能爬虫之单线程、多进程、多线程的使用,线程池、进程池、协程池的使用

目录一、单线程爬虫代码实现二、 多线程爬虫1、多线程的方法使用2、队列模块的使用3、多线程实现思路剖析4、代码实现**注意点&#xff1a;**三、多进程爬虫1、多进程程的方法使用2、多进程中队列的使用3 代码实现**小结**四、线程池实现爬虫1、线程池使用方法介绍2、使用线程池…

365天深度学习训练营-第J3周:DenseNet算法实战与解析

目录 一、前言 二、论文解读 1、DenseNet的优势 2、设计理念 3、网络结构 4、与其他算法进行对比 三、代码复现 1、使用Pytorch实现DenseNet 2、使用Tensorflow实现DenseNet网络 四、分析总结 一、前言 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习…

基于OSG的虚拟校园系统的设计与实现

基于open scene graph的虚拟校园系统的设计与实现 摘要 •引言 • OSG基本原理 •OSG操作与动画 •视点的定位和切换 •自由漫游 •路径漫游 • 路径动画 • 点选和文字 • 粒子系统 • 3DMAX • 无线通信与数据库设计 • 实现步骤 • 结论 摘要 随着科技的不断发展,人工智能&a…

DO-254 和 DO-178B的区别(文末有易灵思核心板及配套下载线)

DO-178B介绍 DO-178B&#xff0c;机载系统和设备认证中的软件考虑&#xff0c;在电子硬件被要求符合 DO-254 之前多年就已发布和采纳。DO-178B 的先行一步对电子硬件开发带来两个特别的后果。首先&#xff0c;使得硬件制造商有了一种倾向&#xff0c;为了避免 DO-178B 对软件开…

【MySQL】sql中explain解释和应用

这里写目录标题学习原因MySQL中explain的使用和用法解释explain的使用explain 运行结果的意义文字展示表格展示参考资料&#xff1a;结束语学习原因 在对sql的优化过程中使用了explain对指定的sql进行查看它的运行效果&#xff0c;以便找出sql的性能特点并进行优化 MySQL中ex…

Linux - POSIX信号量,基于环形队列的生产者消费者模型

信号量在Linux下&#xff0c;POSIX信号量是一种线程同步机制&#xff0c;用于控制多个线程之间的访问顺序。POSIX信号量可以用于实现线程之间的互斥或者同步。在之前的阻塞队列生产者消费者模型中&#xff0c;阻塞队列是一个共享资源&#xff0c;不管是生产者还是消费者&#x…

Mysql实战之日志系统:一条SQL更新语句是如何执行的

1.前言 上一篇咱们了解了MySQL 的执行过程&#xff0c;其中设计连接器、分析器、优化器、执行器和存储引擎&#xff0c;接下来我将给大家讲解一下在MySQL中一条更新语句是如何执行。我相信大家可能听公司的DBA提起过&#xff0c;可以将数据恢复到半个月内任意时间的状态&#…

Scala集合详解(第七章:集合、数组、列表、set集合、map集合、元组、队列、并行)(尚硅谷笔记)

集合第七章:集合7.1 集合简介7.1.1 不可变集合继承图7.1.2 可变集合继承图7.2 数组7.2.1 不可变数组7.2.2 可变数组7.2.3 不可变数组与可变数组的转换7.2.4 多维数组7.3 列表 List7.3.1 不可变 List7.3.2 可变 ListBuffer7.4 Set 集合7.4.1 不可变 Set7.4.2 可变 mutable.Set7.…

Android system实战 — Android R(11) 进程保活白名单

Android system实战 — Android R 进程保活白名单0. 前言1. 具体实现1.1 准备工作1.2 源码实现1.2.1 源码1.2.2 diff文件0. 前言 最近在Android R上实现一些需求&#xff0c;进行记录一下&#xff0c;关于进程保活的基础知识可以参考Android system — 进程生命周期与ADJ&#…

自动驾驶路径规划概况

文章目录前言介绍1. 路径规划在自动驾驶系统架构中的位置2. 全局路径规划的分类2.1 基础图搜索算法2.1.1 Dijkstra算法2.1.2 双向搜索算法2.1.3 Floyd算法2.2 启发式算法2.2.1 A*算法2.2.2 D*算法2.3 基于概率采样的算法2.3.1 概率路线图&#xff08;PRM&#xff09;2.3.2 快速…

蓝牙运动耳机什么牌子的好、运动蓝牙耳机排行榜推荐

近些年&#xff0c;户外运动兴起&#xff0c;运动耳机迎来爆发增长&#xff0c;拒绝运动乏味&#xff0c;追求健康运动方式&#xff0c;已经成为当下年轻人的共同诉求。跑步骑行听音乐&#xff0c;已经是运动爱好者再熟悉不过的操作&#xff0c;很多人在运动中离不开音乐的节奏…

代码随想录算法训练营第七天 | 454.四数相加II 、 383. 赎金信、15. 三数之和、18. 四数之和 、总结

打卡第七天&#xff0c;还是哈希表。 今日任务 454.四数相加II383.赎金信15.三数之和18.四数之和总结 454.四数相加II 代码随想录 class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, ve…

【vue2每日小知识】实现directive自定义指令的封装与全局注册

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;将我们的自定义指令directive统一管理并批量注册 目录 一、directive自定义指令介绍 二…

DS期末复习卷(六)

一、选择题(30分) 1&#xff0e; 设一组权值集合W{2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6}&#xff0c;则由该权值集合构造的哈夫曼树中带权路径长度之和为&#xff08; D &#xff09;。 (A) 20 (B) 30 (C ) 40 (D) 45 W(23)*3(456)*245 2&#xff0e;执行一…

Python、Java、JavaScript、C、Go等编程语言如何实现“定时器”功能

这是CSDN平台2月推出的一个活动(活动链接为&#xff1a;CSDN 征文活动)&#xff0c;聊聊时间的话题&#xff0c;小编我也不知道有什么好聊的时间的话题&#xff0c;看了CSDN给出的部分话题上&#xff0c;有一个这样的话题&#xff0c;如何用各种编程语言实现“定时器”&#xf…

GUI可视化应用开发及Python实现

0 建议学时 4学时&#xff0c;在机房进行 1 开发环境安装及配置 1.1 编程环境 安装PyCharm-community-2019.3.3 安装PyQt5 pip install PyQt5-tools -i https://pypi.douban.com/simple pip3 install PyQt5designer -i https://pypi.douban.com/simple1.2 环境配置 选择“…

JVM13命令行

2. JVM 监控及诊断工具-命令行篇 2.1. 概述 简单命令行工具 在我们刚接触 java 学习的时候&#xff0c;大家肯定最先了解的两个命令就是 javac&#xff0c;java&#xff0c;那么除此之外&#xff0c;还有没有其他的命令可以供我们使用呢&#xff1f; 我们进入到安装 jdk 的…

【11】FreeRTOS的延时函数

目录1.延时函数-介绍2.相对延时函数-解析2.1函数prvAddCurrentTaskToDelayedList-解析2.3滴答定时器中断服务函数xPortSysTickHandler()-解析2.4函数taskSWITCH_DELAYED_LISTS() -解析3.延时函数-实验4.总结1.延时函数-介绍 函数描述vTaskDelay()相对延时xTaskDelayUntil()绝对…