判断是否存在索引异常的行为

部分分区DDL如果不带UPDATE GLOBAL INDEX子句,会导致分区表Global索引失效。同时用户也可以使用ALTER TABLE或者ALTER INDEX使分区表索引失效。当分区表或者部分分区上索引不可用后,会导致查询SQL无法走索引扫描,从而出现慢SQL场景。

  • 查询索引类型和状态

分区表的索引有两种,Local索引和Global索引。Local索引会在每个分区创建一个索引,Global索引会在整个分区表上创建一个全局索引。对于Local索引,需要确认整个索引自身状态和目标查询分区的索引状态;对于Global索引,只需要确认整个索引自身状态。
可以通过系统表pg_index查询分区表的所有索引,并获取索引是否可用的状态,其索引类型在pg_class中给出。下面给出了查询分区表t1的全部索引状态及索引类型的命令参考:

gaussdb=# select c.relname, i.indisusable, c.relkind from pg_class c join pg_index i on c.oid=i.indexrelid 
    join pg_class r on i.indrelid=r.oid where r.relname='t1'; 
      relname       | indisusable | relkind  
--------------------+-------------+--------- 
 t1_c1_idx          | t           | i 
 t1_c2_tableoid_idx | f           | I

其中indisusable字段为’t’表示该索引可用,为’f’表示索引已经失效,在查询业务中该索引无法使用;relkind为’i’表示该索引为Local索引,为’I’表示该索引为Global索引。
或者通过元语句\d命令查询分区表的索引信息:

gaussdb=# \d t1 
      Table "public.t1" 
 Column |  Type   | Modifiers  
--------+---------+----------- 
 c1     | integer |  
 c2     | integer |  
Indexes: 
    "t1_c1_idx" btree (c1) LOCAL TABLESPACE pg_default 
    "t1_c2_tableoid_idx" btree (c2) TABLESPACE pg_default UNUSABLE 
Partition By RANGE(c1) 
Number of partitions: 2 (View pg_partition to check each partition range.)

可以看到表t1的两条索引t1_c1_idx、t1_c2_tableoid_idx被列出。其中t1_c1_idx带有LOCAL关键字,表示该索引为Local索引,t1_c2_tableoid_idx没有LOCAL关键字,表示该索引为Global索引。同时t1_c2_tableoid_idx标记了UNUSABLE,表示该索引不可用。

  • 查询索引分区状态

对于Local索引,还需要确认目标查询分区的索引状态,这个信息可以从系统表pg_partition中查询。

gaussdb=# select p.relname,p.indisusable from pg_partition p join pg_class c on p.parentid=c.oid where c.relname='t1_c1_idx'; 
  relname  | indisusable  
-----------+------------- 
 p1_c1_idx | t 
 p2_c1_idx | f 
(2 rows)

可以看到索引分区p1_c1_idx可用,索引分区p2_c1_idx不可用。在分区p2上的查询无法使用索引t1_c1_idx。

  • 重建异常的索引/索引分区

如果分区表的索引/索引分区状态异常,会导致查询SQL无法走索引扫描,需要重建索引/索引分区。重建索引的命令如下:

ALTER INDEX t1_c2_tableoid_idx REBUILD;

重建索引分区的命令如下:

ALTER INDEX t1_c1_idx REBUILD PARTITION p2_c1_idx;

判断分区表是否存在剪枝异常的场景

当分区表的分区键所在列存在条件时,可以触发分区剪枝。数据库会在优化器/执行器阶段识别到需要扫描的分区,而不会扫描全部分区。只有分区表的业务是顺序扫描,或者使用Local索引进行扫描时候,才可能触发分区剪枝;Global索引不会触发分区剪枝,这是因为Global索引是在整个分区表上创建的单个索引,不存在剪枝的概念。
剪枝是被动触发的,当查询业务满足分区剪枝条件时,会自动触发分区剪枝。

  • 判断是否触发了分区剪枝

可以通过查询计划来判断是否触发了分区剪枝。当扫描分区数少于分区总数时,即触发了分区剪枝。分区剪枝分为静态剪枝和动态剪枝,静态剪枝是指在优化器阶段就能识别到裁剪的分区;动态剪枝是指优化器阶段只能确定可以进行剪枝,但不知道具体裁剪到哪个分区,在执行器阶段才会确定裁剪的目标分区。
下面的业务触发了分区静态剪枝,计划中的’Iterations: 1’表示扫描了1个分区,'Selected Partitions: 1’表示扫描的目标分区下标是1。
这个下标是一个逻辑数组下标,对于范围分区/间隔分区,按照分区定义上界值升序排列;对于列表分区,按照第一个枚举值升序排列;对于哈希分区,按照计算后的哈希值升序排列。可以通过函数pg_get_tabledef获取分区定义,其列出的分区即为该对应下标。

gaussdb=# explain select * from t1 where c1 < 100; 
                              QUERY PLAN                                
----------------------------------------------------------------------- 
 Partition Iterator  (cost=0.00..27.86 rows=716 width=8) 
   Iterations: 1 
   ->  Partitioned Seq Scan on t1  (cost=0.00..27.86 rows=716 width=8) 
         Filter: (c1 < 100) 
         Selected Partitions:  1 
(5 rows)

下面的业务没有触发分区剪枝,计划中的’Iterations: 2’表示扫描了2个分区,'Selected Partitions: 1…2’表示扫描的目标分区下标是1和2。可以看到扫描的分区数等于分区表的总分区数,表示未进行任何分区剪枝。

gaussdb=# explain select * from t1; 
                               QUERY PLAN                                
------------------------------------------------------------------------ 
 Partition Iterator  (cost=0.00..31.49 rows=2149 width=8) 
   Iterations: 2 
   ->  Partitioned Seq Scan on t1  (cost=0.00..31.49 rows=2149 width=8) 
         Selected Partitions:  1..2 
(4 rows)

下面的业务触发了分区动态剪枝,计划中的’Iterations: PART’和’Selected Partitions: PART’表示优化器识别到分区表可以进行分区剪枝,但具体

gaussdb=# prepare p1 as select * from t1 where c1 < $1; 
gaussdb=# explain execute p1(100); 
                                         QUERY PLAN                                          
-------------------------------------------------------------------------------------------- 
 Partition Iterator  (cost=9.80..28.75 rows=716 width=8) 
   Iterations: PART 
   ->  Partitioned Bitmap Heap Scan on t1  (cost=9.80..28.75 rows=716 width=8) 
         Recheck Cond: (c1 < $1) 
         Selected Partitions:  PART 
         ->  Partitioned Bitmap Index Scan on t1_c1_idx  (cost=0.00..9.62 rows=716 width=0) 
               Index Cond: (c1 < $1) 
               Selected Partitions:  PART 
(8 rows)
  • 支持分区剪枝的场景

当分区键所在列存在条件时,可以进行分区剪枝。条件剪枝支持场景为:比较表达式(<,<=,=,>=,>)、逻辑表达式(AND、OR)、数组表达式。需要注意的是,列表和哈希分区不支持除等号外的其他比较表达式的剪枝。如果条件全为常量,则进行静态剪枝;如果条件带有参数、部分隐式转换、immutable函数,则进行动态剪枝。
当分区表作为参数化路径计划的内表且分区键所在列为索引检索条件时,支持动态剪枝。

  • 不支持分区剪枝的场景

分区键所在列的条件为子查询表达式、无法直接强转的类型转换、stable/volatile函数时,不支持分区剪枝。
分区表在生成除参数化路径外的其他JOIN计划时,不支持动态剪枝。

  • 业务改写适配分区剪枝

当业务设计不合理,导致原本逻辑上可以走分区剪枝的计划,最终未走分区剪枝时,可以改写业务以适配分区剪枝,从而提升分区表查询业务性能。比如使用HINT固定计划、在客户端修改绑参类型等方法。

数据量很小的时候,我们可以看到,seq scan 比 index scan 更加有效。那是因为 index scan 至少要发生两次I/O,一次是 读取索引块, 一次是读取数据块。当index 很大的时候,情况可能会更加复杂。 postgres=# select a.relpages, a.reltuples, a.relfilenode,a.r...
数据库在日常使用的过程中会产生很多SQL语句,而如果有些SQL语句运行了很长时间还没有结束,这些语句会消耗很多的系统性能。 那么如何查询到有哪些SQL语句影响了系统的运行呢? 学了本节课程后,您就将会掌握初步定位GaussDB(for openGauss)慢SQL的方法。 数据库执行SQL语句长时间无响应。 数据库CPU/内存压力一直很大。 使用DAS或者gsql连接实例。 查询系统中长时间运行的查询语句。 SELECT current_timestamp - quer.
分区就是根据指定字段的值进行分类、分组,字段值相同的分为一类然后存储在一个单独的HDFS文件中,多个类就存储在多个文件中。原本存储在一个文件中的数据现在存储在多个文件中,查询数据时只需要知道数据在哪个类别中然后直接去对应类对应的文件中去查询就好,这样只需扫描这一个类别的文件而不需要扫描所有文件,这样提高了查询效率。 分区就是对文件进行水平分割,对数据分门别类的分开存储。 分区有两种: 静态分区: 必须手动显式的添加需要分区的字段值, 分类的值有多少个就要添加多少次 (alter table add partition)。静态分区适合分区字段的值比较少的情况。 动态分区:创建
本文作者:吴松         本文主要介绍OpenGauss中常见的索引结构,索引相关元数据,并结合代码重点讲解B-tree索引使用过程中的重要流程,希望对大家理解OpenGauss中的索引有所帮助。 B-Tree索引         B-tree索引适合比较查询和范围查询,当查询条件使用(>,=,<,>=,<=
3、搜索路径 show search_path; 查看模式搜索路径,无论如何搜索路径前两个一定是pg_temp和pg_catalog set search_path to my_schema,public; 将my_schema,public两个模式加入搜索路径
自2019年5月15日正式发布以来,华为GaussDB数据库受到业界的广泛关注。针对客户和读者的反馈,我们整理了关于GaussDB数据库的十个热点问题,让您能够快速一览华为GaussDB数据的“庐山真面”。 1、GaussDB的命名有什么含义? GaussDB是华为数据库产品品牌名,意在致敬数学家高斯(Gauss)。GaussDB系列数据库产品包括GaussDB OLTP数据库和GaussDB...
在Oracle数据库中,分区查询时是允许进行更新操作的。分区是一种将数据分割成多个逻辑部分的,每个部分都被称为分区。这种分割可以根据特定的条件进行,例如按照日期、地理位置、客户等。分区的设计和使用可以提高查询性能并简化维护。 当我们需要更新分区时,可以使用UPDATE语句来修改中的数据。只需提供指定的分区或特定的查询条件即可对分区中的数据进行更改。更新操作可以针对单个分区进行,也可以同时更新多个分区。 需要注意的是,分区进行更新操作时,要确保更新的数据符合分区规则。换句话说,被更新的数据所在的分区必须与更新操作的条件相匹配。如果不满足分区规则,更新操作可能会失败或者更新的数据不会生效。 另外,对于包含全局索引的分区进行更新操作时,需要特别注意。全局索引是在整个上创建的索引,而不是在各个分区上分别创建的索引。在更新分区时,如果更新操作会导致分区键的变化,那么全局索引也需要相应地更新。这就需要进行一些额外的操作,以确保全局索引的一致性和正确性。 总结来说,Oracle的分区是允许进行更新操作的,但要注意更新的数据必须符合分区规则,并且在更新包含全局索引的分区时需要额外的操作来维护索引的一致性。