更新时间:2025-05-29 GMT+08:00

Index Scan

算子说明

在索引扫描中,数据库使用语句指定的索引列,通过遍历索引树来检索行。数据库为一个值扫描索引时,发生n次 I/O 就能找到其要查找的值,其中 n 即 B-tree索引的高度。Index Scan通常用于检索表数据,数据库以轮流方式先读取索引块,找到对应的索引键值,然后通过索引键对应的tid去读取相应的表元组。在数据量大,但是查询结果集较小的场景下,Index Scan的效率往往高于Seq Scan。

典型场景

  • 查询某个表中的特定行:当查询语句中包含WHERE子句时,如果WHERE子句中的条件可以通过索引列进行匹配,那么GaussDB就可能会使用Index Scan来查找符合条件的行。
  • 排序:当查询语句中包含ORDER BY子句时,如果ORDER BY子句中的列可以通过索引进行排序,那么GaussDB就可能会使用Index Scan来进行排序操作。
  • 聚合:当查询语句中包含GROUP BY子句时,如果GROUP BY子句中的列可以通过索引进行分组,那么GaussDB就可能会使用Index Scan来进行聚合操作。
  • 连接:当查询语句中包含JOIN操作时,如果JOIN操作中的列可以通过索引进行匹配,那么GaussDB就可能会使用Index Scan来进行连接操作。

示例

示例1:WHERE子句中的条件可以通过索引列进行匹配。

--数据准备。 
gaussdb=# DROP TABLE IF EXISTS test;
gaussdb=# CREATE TABLE test (c1 int, c2 int); 
CREATE TABLE 
gaussdb=# CREATE INDEX c1_idx ON test (c1); 
CREATE INDEX 
gaussdb=# INSERT INTO test SELECT generate_series(1, 1000000), random()::integer; 
INSERT 0 1000000
gaussdb=# INSERT INTO test SELECT generate_series(1, 1000000), random()::integer; 
INSERT 0 1000000
gaussdb=# INSERT INTO test SELECT generate_series(1, 1000000), random()::integer; 
INSERT 0 1000000

--收集统计信息。
gaussdb=# ANALYZE test;
gaussdb=# EXPLAIN SELECT /*+ indexscan(test c1_idx) */ * FROM test WHERE c1 > 990000;
                                   QUERY PLAN
---------------------------------------------------------------------------------
 Streaming (type: GATHER)  (cost=4.00..25494.30 rows=31127 width=8)
   Node/s: All datanodes
   ->  Index Scan using c1_idx on test  (cost=0.00..24035.17 rows=31127 width=8)
         Index Cond: (c1 > 990000)
(4 rows)

上述示例中,Index Scan算子输出信息如下所示。

信息名称

含义

Index Scan

算子的名称。

Index Cond

该算子的过滤谓词,示例中的过滤条件为c1列的值大于990000。在查询执行时,满足这些条件的行会被包含在最终的结果集中。

示例2:ORDER BY子句中的列可以通过索引进行排序。

gaussdb=# EXPLAIN SELECT /*+ indexscan(test c1_idx) */ * FROM test ORDER BY c1;
                                    QUERY PLAN
-----------------------------------------------------------------------------------
 Streaming (type: GATHER)  (cost=4.00..190456.74 rows=3000000 width=8)
   Merge Sort Key: c1
   Node/s: All datanodes
   ->  Index Scan using c1_idx on test  (cost=0.00..49831.74 rows=3000000 width=8)
(4 rows)

示例3:GROUP BY子句中的列可以通过索引进行分组。

gaussdb=# EXPLAIN SELECT /*+ indexscan(test c1_idx) */ c2 FROM test WHERE c1 = 10 GROUP BY c2;
                                     QUERY PLAN
-------------------------------------------------------------------------------------
 HashAggregate  (cost=8.33..8.34 rows=1 width=4)
   Group By Key: c2
   Skew Agg Optimized by Statistic
   ->  Streaming (type: GATHER)  (cost=8.33..8.34 rows=1 width=4)
         Node/s: datanode2
         ->  HashAggregate  (cost=8.27..8.28 rows=1 width=4)
               Group By Key: c2
               ->  Index Scan using c1_idx on test  (cost=0.00..8.27 rows=1 width=4)
                     Index Cond: (c1 = 10)
(9 rows)

示例4:JOIN操作中可以通过索引进行匹配

gaussdb=#  EXPLAIN SELECT /*+ indexscan(t1 c1_idx) */ t1.*, t2.* FROM test t1 JOIN test t2 on t1.c1 = t2.c1;
                                            QUERY PLAN
--------------------------------------------------------------------------------------------------
 Streaming (type: GATHER)  (cost=4.00..364718.08 rows=4933438 width=16)
   Node/s: All datanodes
   ->  Merge Join  (cost=0.00..133463.18 rows=4933438 width=16)
         Merge Cond: (t1.c1 = t2.c1)
         ->  Index Scan using c1_idx on test t1  (cost=0.00..46356.20 rows=3000000 width=8)
         ->  Materialize  (cost=0.00..50106.20 rows=3000000 width=8)
               ->  Index Scan using c1_idx on test t2  (cost=0.00..46356.20 rows=3000000 width=8)
(7 rows)

--删除。
gaussdb=# DROP TABLE test;