PostgreSQL长事务与失效的索引查询浅析介绍

最近刚写了一篇文章介绍了下长事务,以及一些长事务常见的危害,如无法及时的垃圾回收导致表膨胀之类的问题,最近刚好又碰到一个问题也是长事务所导致的。

上周六早上接到同事电话,说某个库CPU一直很高,看了下全是某张大表的全表扫描导致,但是奇怪的是相关的查询都有用到索引列,不知道为啥查询全部都没走索引。

当我连上去查看时发现确实如此,如果只是某个查询不走索引那可能是SQL本身写的有问题,但是这张表相关的所有SQL都不走索引,那自然会想到是索引本身的原因了。那是不是索引失效了呢?经过检查发现这张表上的索引状态均正常,并且我还将索引重建了,可仍然没起作用。

正当我迷茫的时候,偶然间再去执行相关SQL的时候发现竟然又都走索引了,这又是啥情况。。

我啥都没做你就自己恢复了,那不是显得我很呆?不行,必须得搞清楚啥原因。

当我再去查看相关索引的时候发现,该索引的pg_index中的indcheckxmin列均为true,这个字段我之前有写过一篇索引失效的文章里介绍过。那么什么情况下索引的该属性会被设置为true呢?两种情况:

  1. 当前事务中表上存在broken HOT chains;
  2. 当old_snapshot_threshold被设置时。

之前我们也介绍过,如果索引的该属性为true那么在创建索引的事务中该索引是不可用的,不过这种场景我们基本不太会遇到,因为在实际应用中我们基本不会在事务中创建完索引然后不提交该事务直接去使用。

而关于indcheckxmin的详细解释是:直到此pg_index行的xmin低于查询的TransactionXmin之前,查询都不能使用此索引。那么什么情况下会出现这种问题呢?长事务!

当我们创建索引的时候如果索引的indcheckxmin被设置为true,且数据库中此时存在长事务,那么直到该长事务提交前,该索引会一直不可用。

下面我们来模拟这种情况:

--会话一:打开一个长事务

bill=# begin;
BEGIN
bill=*# delete from t;
DELETE 1000
bill=*#

--会话二:创建索引

由于old_snapshot_threshold参数被设置,所以创建的索引indcheckxmin被设置为true了。

bill=# show old_snapshot_threshold ;
 old_snapshot_threshold
------------------------
 1h
(1 row)
bill=# create index idx_t1 on t1(id);
CREATE INDEX
bill=# select indisvalid,indcheckxmin,indisready,indislive from pg_index where indexrelid = 'idx_t1'::regclass;
 indisvalid | indcheckxmin | indisready | indislive
------------+--------------+------------+-----------
 t          | t            | t          | t
(1 row)

使用该索引列进行查询:

索引的确无法使用。

bill=# explain analyze select * from t1  where id = 100;
                                           QUERY PLAN
-------------------------------------------------------------------------------------------------
 Seq Scan on t1  (cost=0.00..209.00 rows=51 width=37) (actual time=0.010..0.692 rows=51 loops=1)
   Filter: (id = 100)
   Rows Removed by Filter: 9949
 Planning Time: 0.150 ms
 Execution Time: 0.706 ms
(5 rows)
bill=# set enable_seqscan = off;
SET
bill=# explain analyze select * from t1  where id = 100;
                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 Seq Scan on t1  (cost=10000000000.00..10000000209.00 rows=51 width=37) (actual time=0.063..0.732 rows=51 loops=1)
   Filter: (id = 100)
   Rows Removed by Filter: 9949
 Planning Time: 0.089 ms
 Execution Time: 0.796 ms
(5 rows)

提交该长事务后再次查询:

索引变得可用了。

bill=# explain analyze select * from t1  where id = 100;
                                                  QUERY PLAN
---------------------------------------------------------------------------------------------------------------
 Index Scan using idx_t1 on t1  (cost=0.29..54.48 rows=51 width=37) (actual time=0.013..0.052 rows=51 loops=1)
   Index Cond: (id = 100)
 Planning Time: 0.061 ms
 Execution Time: 0.067 ms
(4 rows)

果然是长事务的坑啊!

由于我们的库中基本都打开了old_snapshot_threshold参数,导致创建的索引的indcheckxmin一定是true。但这其实并不会有什么太大影响,问题在于在创建索引的同时数据库中存在长事务,这就导致了索引在创建完之后第一时间变得不可用了,需要直到该长事务被提交后才可用。

后来和同事求证发现他们之前也经常碰到这种CPU变高然后又自己降下来的情况,之前并没有注意是这张表的全表扫描导致的。由于该表是由pg_pathman创建的自动分区,每天都会自己去创建一个新的分区,因此如果每天自动创建分区的时候存在长事务,那么创建完之后相关的分区上的索引均是不可用的,这也是为什么查询不走索引然后又自己恢复的原因了。

这个案例其实我们在实际生产中遇到的可能性还是很大的,如果你的数据库打开了old_snapshot_threshold参数,同时没有做好长事务的监控,那么创建的索引就会出现这种不可用的情况。长事务危害不浅啊!

到此这篇关于PostgreSQL长事务与失效的索引查询浅析介绍的文章就介绍到这了,更多相关PostgreSQL长事务内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • PostgreSQL游标与索引选择实例详细介绍

    之前有写过一个案例,order by limit因为数据分布不均而选择了错误的索引,这是由于优化器没法判断数据的分布关系,默认认为数据分布是均匀的所导致的. 而除了limit,当我们在使用游标时也要注意有可能会出现类似的情况.而往往这类在存储过程中的SQL我们更难发现其选择了错误的执行计划,所以需要注意. 1.建测试表 bill=# create table tbl (id int, c1 int, c2 int, c3 int, c4 int); CREATE TABLE 2.写入一批随机数据

  • PostgreSQL长事务概念解析

    我们在很多地方应该都听到过长事务的危害,比方说长事务会导致表膨胀之类的.那么在PostgreSQL中什么才算是长事务呢? 首先,在PostgreSQL的官方文档中并没有所谓“长事务”这一定义,似乎大家约定俗称的把一个执行了很长却没有提交的事务认为是“长事务”了,而在不同的数据库中关于长事务的定义往往也不尽相同,那么在PostgreSQL中什么是长事务呢? 打个比方,如下所示,我在一个会话中通过begin开启一个事务,然后执行了个简单的查询语句后迟迟不提交,这算不算长事务呢? bill=# beg

  • PostgreSQL长事务与失效的索引查询浅析介绍

    最近刚写了一篇文章介绍了下长事务,以及一些长事务常见的危害,如无法及时的垃圾回收导致表膨胀之类的问题,最近刚好又碰到一个问题也是长事务所导致的. 上周六早上接到同事电话,说某个库CPU一直很高,看了下全是某张大表的全表扫描导致,但是奇怪的是相关的查询都有用到索引列,不知道为啥查询全部都没走索引. 当我连上去查看时发现确实如此,如果只是某个查询不走索引那可能是SQL本身写的有问题,但是这张表相关的所有SQL都不走索引,那自然会想到是索引本身的原因了.那是不是索引失效了呢?经过检查发现这张表上的索引

  • PostgreSQL数据库事务实现方法分析

    本文实例讲述了PostgreSQL数据库事务实现方法.分享给大家供大家参考,具体如下: 事务简介 事务管理器:有限状态机 日志管理器 CLOG:事务的执行结果 XLOG:undo/redo日志 锁管理器:实现并发控制,读阶段采用MVCC,写阶段采用锁控制实现不同的隔离级别 事务是所有数据库系统的一个基本概念. 一次事务的要点就是它把多个步骤捆绑成了一个单一的,不成功则成仁的操作. 其它并发的事务是看不到在这些步骤之间的中间状态的,并且如果发生了一些问题, 导致该事务无法完成,那么所有这些步骤都完

  • MySQL中的长事务示例详解

    前言: 『入门MySQL』系列文章已经完结,今后我的文章还是会以MySQL为主,主要记录下近期工作及学习遇到的场景或者自己的感悟想法,可能后续的文章不是那么连贯,但还是希望大家多多支持.言归正传,本篇文章主要介绍MySQL长事务相关内容,比如说我们开启的一个事务,一直没提交或回滚会怎样呢,出现事务等待情况应该如何处理,本篇文章将给你答案. 注意:本篇文章并不聚焦于谈论事务隔离级别以及相关特性.而是介绍长事务相关危害以及监控处理方法.本文是基于MySQL5.7.23版本,不可重复读(RR)隔离级别

  • 深入了解mysql长事务

    前言: 本篇文章主要介绍MySQL长事务相关内容,比如说我们开启的一个事务,一直没提交或回滚会怎样呢,出现事务等待情况应该如何处理,本篇文章将给你答案. 注意:本篇文章并不聚焦于谈论事务隔离级别以及相关特性.而是介绍长事务相关危害以及监控处理方法.本文是基于MySQL5.7.23版本,不可重复读(RR)隔离级别所做实验.(语句为\G可以使查询结构显示更易读,但只可以在mysql命令行使用.) 1.什么是长事务 首先我们先要知道什么是长事务,顾名思义就是运行时间比较长,长时间未提交的事务,也可以称

  • PostgreSql JDBC事务操作方法详解

    目录 JDBC事务相关方法简介 禁用自动提交模式 提交事务 回滚事务 PostgreSQL JDBC 事务示例 JDBC事务相关方法简介 本文将借助示例,简单讲解下JDBC操作Pg事务的流程. 首先来简单讲解下事务的定义:为了确保两个(多个)数据库操作都生效,或者两个操作都不发生,可以使用事务.根据定义,事务是作为单个单元执行的一组语句.换句话说,要么所有语句都成功执行,要么没有执行. 禁用自动提交模式 当建立与PostgreSQL数据库的连接时,它处于自动提交模式.这意味着每个SQL语句都被视

  • 浅述SQL Server的聚焦强制索引查询条件和Columnstore Index

    前言 本节我们再来穿插讲讲索引知识,后续再讲数据类型中的日期类型,简短的内容,深入的理解. 强制索引查询条件 前面我们也讲了一点强制索引查询的知识,本节我们再来完整的讲述下 (1)SQL Server使用默认索引 USE TSQL2012 GO SELECT * FROM Sales.Orders 上述就不用我再啰嗦了,使用默认主键创建的聚集索引来执行查询执行计划. (2)SQL Server使用强制索引 USE TSQL2012 GO SELECT custid FROM Sales.Orde

  • Spring事务的失效场景你知道多少

    1.Spring事务最终依赖的数据库的事务,如果用的是mysql的话,执行引擎要是innodb;因为只有innoDB 支持事务. 2.Spring的事务是原理是aop,所以加事务所在bean是要Spring容器管理的:自己new出来的对象肯定是不行的. 3.Spring事务标签@Transactional必须注解在public方法上.private.protected.default以及finally修饰的方法或者类,以及静态方法,事务都会失效的. 4.同一个类中内部方法调用,事务会失效的.调用

  • NumPy对数组按索引查询实战方法总结

    目录 前期准备及前情回顾 基础索引 一维数组 二维数组 神奇索引 一维数组 二维数组0 布尔索引(常用) 一维数据 二维数组 布尔索引条件的组合 总结 前期准备及前情回顾 #对于一维向量用np.arange生成以元组形式输出从0开始的数组([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) #对于二维向量(及多维向量),用np.arange生成以元组形式输出从0开始到20结束的数组,用np.reshape(4, 5)函数把一维向量转换为4行5列的二维向量 理解:numpy的二维向量对

  • MySQL分区建索引以及分区介绍总结

    目录 MySQL 分区建索引介绍 MySQL 分区介绍介绍 总结 MySQL 分区建索引介绍 mysql分区后每个分区成了独立的文件,虽然从逻辑上还是一张表其实已经分成了多张独立的表,从“information_schema.INNODB_SYS_TABLES”系统表可以看到每个分区都存在独立的TABLE_ID,由于Innodb数据和索引都是保存在".ibd"文件当中(从INNODB_SYS_INDEXES系统表中也可以得到每个索引都是对应各自的分区(primary key和uniqu

随机推荐