返回顶部
首页 > 资讯 > 数据库 >递归查询两种写法的性能差异
  • 278
分享到

递归查询两种写法的性能差异

递归查询两种写法的性能差异 2017-01-29 06:01:06 278人浏览 才女
摘要

对于递归查询,KINGBASE用户可以选择使用connect by ,或者使用 with recursive 。下面,我们以例子来看下二者的差别。 一、构造数据 create table test_recursive(id intege

递归查询两种写法的性能差异

对于递归查询,KINGBASE用户可以选择使用connect by ,或者使用 with recursive 。下面,我们以例子来看下二者的差别。

一、构造数据

create table test_recursive(id integer,pid integer,name varchar,description text);
insert into test_recursive(id,name,description) select generate_series(1,100000),"a"||generate_series(1,100000),repeat("desc",500);

update test_recursive set pid=1 where id between 2 and 10;
update test_recursive set pid=mod(id,9)+2 where id between 11 and 100;
update test_recursive set pid=mod(id,90)+11 where id between 101 and 1000;
update test_recursive set pid=mod(id,900)+101 where id between 1001 and 10000;
update test_recursive set pid=mod(id,9000)+1001 where id between 10001 and 100000;

create table test_recursive_random(id integer,pid integer,name varchar,description text);
insert into test_recursive_random select * from test_recursive order by random;

create index ind_test_recursive_random_id on test_recursive_random(id);
create index ind_test_recursive_random_pid on test_recursive_random(pid);
vacuum full test_recursive_random;
analyze test_recursive_random;

create index ind_test_recursive_id on test_recursive(id);
create index ind_test_recursive_pid on test_recursive(pid);
vacuum full test_recursive;
analyze test_recursive;

本例子构造了5层的数据,有排序与非排序两种数据。

二、使用connect by

connect by的查询性能:用时 746ms

test=# explain analyze select id,pid,name from test_recursive start with id=1 connect by prior id = pid ;
                                                                        QUERY PLAN                                                                         
-----------------------------------------------------------------------------------------------------------------------------------------------------------
 Recursive Union  (cost=0.29..422.37 rows=101 width=14) (actual time=0.038..728.281 rows=100000 loops=1)
   ->  Index Scan using ind_test_recursive_id on test_recursive  (cost=0.29..8.31 rows=1 width=14) (actual time=0.015..0.017 rows=1 loops=1)
         Index Cond: (id = 1)
   ->  Nested Loop  (cost=0.42..41.30 rows=10 width=14) (actual time=0.002..0.003 rows=1 loops=100000)
         ->  WorkTable Scan on "connect"  (cost=0.00..0.02 rows=1 width=4) (actual time=0.000..0.000 rows=1 loops=100000)
         ->  Index Scan using ind_test_recursive_pid on test_recursive  (cost=0.42..41.18 rows=10 width=14) (actual time=0.002..0.002 rows=1 loops=100000)
               Index Cond: (pid = (PRIOR test_recursive.id))
 Planning Time: 0.185 ms
 Execution Time: 746.102 ms
(9 rows)

  

三、Kingbase with recursive 查询

1、排序数据:用时302ms

explain analyze with recursive tmp1 as (
select id,pid,name from test_recursive where id=1
union all
select a.id,a.pid,a.name from test_recursive a inner join tmp1 b on a.pid=b.id )
select * from tmp1;
                                                                             QUERY PLAN                                                                              
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 CTE Scan on tmp1  (cost=4013.94..4033.96 rows=1001 width=40) (actual time=0.020..297.856 rows=100000 loops=1)
   CTE tmp1
     ->  Recursive Union  (cost=0.29..4013.94 rows=1001 width=14) (actual time=0.018..257.298 rows=100000 loops=1)
           ->  Index Scan using ind_test_recursive_id on test_recursive  (cost=0.29..8.31 rows=1 width=14) (actual time=0.016..0.018 rows=1 loops=1)
                 Index Cond: (id = 1)
           ->  Nested Loop  (cost=0.42..398.56 rows=100 width=14) (actual time=20.529..38.777 rows=16666 loops=6)
                 ->  WorkTable Scan on tmp1 b  (cost=0.00..0.20 rows=10 width=4) (actual time=0.003..2.150 rows=16667 loops=6)
                 ->  Index Scan using ind_test_recursive_pid on test_recursive a  (cost=0.42..39.74 rows=10 width=14) (actual time=0.001..0.002 rows=1 loops=100000)
                       Index Cond: (pid = b.id)
 Planning Time: 0.207 ms
 Execution Time: 302.244 ms
(11 rows)

2、非排序数据:440ms

test=# explain analyze with recursive tmp1 as (
test(# select id,pid,name from test_recursive_random where id=1
test(# union all
test(# select a.id,a.pid,a.name from test_recursive_random a inner join tmp1 b on a.pid=b.id )
test-# select * from tmp1;
                                                                            QUERY PLAN                                                                             
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
 CTE Scan on tmp1  (cost=4206.87..4226.89 rows=1001 width=40) (actual time=0.020..434.721 rows=100000 loops=1)
   CTE tmp1
     ->  Recursive Union  (cost=0.29..4206.87 rows=1001 width=14) (actual time=0.018..397.456 rows=100000 loops=1)
           ->  Index Scan using ind_test_recursive_random_id on test_recursive_random  (cost=0.29..8.31 rows=1 width=14) (actual time=0.017..0.018 rows=1 loops=1)
                 Index Cond: (id = 1)
           ->  Nested Loop  (cost=4.50..417.85 rows=100 width=14) (actual time=33.080..62.311 rows=16666 loops=6)
                 ->  WorkTable Scan on tmp1 b  (cost=0.00..0.20 rows=10 width=4) (actual time=0.007..2.412 rows=16667 loops=6)
                 ->  Bitmap Heap Scan on test_recursive_random a  (cost=4.50..41.67 rows=10 width=14) (actual time=0.002..0.003 rows=1 loops=100000)
                       Recheck Cond: (pid = b.id)
                       Heap Blocks: exact=99557
                       ->  Bitmap Index Scan on ind_test_recursive_random_pid  (cost=0.00..4.49 rows=10 width=0) (actual time=0.001..0.001 rows=1 loops=100000)
                             Index Cond: (pid = b.id)
 Planning Time: 0.304 ms
 Execution Time: 439.563 ms
(14 rows)

3、使用hash join:260ms

test=# set enable_nestloop=off;
SET
test=# explain analyze with recursive tmp1 as (
test(# select id,pid,name from test_recursive where id=1
test(# union all
test(# select a.id,a.pid,a.name from test_recursive a inner join tmp1 b on a.pid=b.id )
test-# select * from tmp1;
                                                                     QUERY PLAN                                                                      
-----------------------------------------------------------------------------------------------------------------------------------------------------
 CTE Scan on tmp1  (cost=24101.58..24121.60 rows=1001 width=40) (actual time=0.018..255.766 rows=100000 loops=1)
   CTE tmp1
     ->  Recursive Union  (cost=0.29..24101.58 rows=1001 width=14) (actual time=0.016..218.427 rows=100000 loops=1)
           ->  Index Scan using ind_test_recursive_id on test_recursive  (cost=0.29..8.31 rows=1 width=14) (actual time=0.015..0.017 rows=1 loops=1)
                 Index Cond: (id = 1)
           ->  Hash Join  (cost=0.33..2407.32 rows=100 width=14) (actual time=13.828..32.571 rows=16666 loops=6)
                 Hash Cond: (a.pid = b.id)
                 ->  Seq Scan on test_recursive a  (cost=0.00..2031.00 rows=100000 width=14) (actual time=0.005..8.240 rows=100000 loops=6)
                 ->  Hash  (cost=0.20..0.20 rows=10 width=4) (actual time=5.114..5.114 rows=16667 loops=6)
                       Buckets: 131072 (originally 1024)  Batches: 2 (originally 1)  Memory Usage: 3073kB
                       ->  WorkTable Scan on tmp1 b  (cost=0.00..0.20 rows=10 width=4) (actual time=0.004..2.068 rows=16667 loops=6)
 Planning Time: 0.196 ms
 Execution Time: 260.360 ms
(13 rows)

四、执行计划差异分析

  • connect by 查询执行逻辑:查询是通过 pid = prior id ,也就是将前条记录的 id 作为值,传给 pid 进行索引扫描。逻辑上可以看做是逐个分支查询,上个分支查询结束,再进行下个分支扫描。loop = 100000,就是表示针对每条记录,都要访问一次索引。
  • with recursive 查询逻辑:是按层次查询,上层结果都返回后,再执行下层查询。每层可以根据所有ctid进行排序,也就是 Bitmap Index Scan,将所有ctid都返回,排序,再访问表,效率提高。另外,由于是每层数据返回后,再去关联查找下层数据,可以使用hash join,提升访问效率。 rows=16666 loop = 6,表示需要访问6个批次,每次平均 16666 条记录。 

五、oracle connect by 查询性能

以下是同样数据量的情况下,Oracle connect by 查询的性能:

SQL> select id,pid,name from test_recursive start with id=1 connect by prior id = pid ;

100000 rows selected.

Elapsed: 00:00:00.98

Execution Plan
----------------------------------------------------------
Plan hash value: 2099392185

----------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                        |    12 |   384 |    18  (12)| 00:00:01 |
|*  1 |  CONNECT BY WITH FILTERING            |                        |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED | TEST_RECURSIVE         |     1 |    32 |     2   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN                   | IND_TEST_RECURSIVE_ID  |     1 |       |     1   (0)| 00:00:01 |
|   4 |   NESTED LOOPS                        |                        |    11 |   495 |    14   (0)| 00:00:01 |
|   5 |    CONNECT BY PUMP                    |                        |       |       |            |          |
|   6 |    TABLE ACCESS BY INDEX ROWID BATCHED| TEST_RECURSIVE         |    11 |   352 |    12   (0)| 00:00:01 |
|*  7 |     INDEX RANGE SCAN                  | IND_TEST_RECURSIVE_PID |    11 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------

Predicate InfORMation (identified by operation id):
---------------------------------------------------

   1 - access("PID"=PRIOR "ID")
   3 - access("ID"=1)
   7 - access("connect$_by$_pump$_002"."prior id "="PID")

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
   - this is an adaptive plan


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
     101983  consistent gets
          0  physical reads
          0  redo size
    2337649  bytes sent via sql*Net to client
      73769  bytes received via SQL*Net from client
       6668  SQL*Net roundtrips to/from client
          8  sorts (memory)
          0  sorts (disk)
     100000  rows processed

 

您可能感兴趣的文档:

--结束END--

本文标题: 递归查询两种写法的性能差异

本文链接: https://lsjlt.com/news/8519.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 递归查询两种写法的性能差异
    对于递归查询,KINGBASE用户可以选择使用connect by ,或者使用 with recursive 。下面,我们以例子来看下二者的差别。 一、构造数据 create table test_recursive(id intege...
    99+
    2017-01-29
    递归查询两种写法的性能差异
  • 递归查询两种写法与性能差异
    对于递归查询,KINGBASE用户可以选择使用connect by ,或者使用 with recursive 。下面,我们以例子来看下二者的差别。 一、构造数据 create table test_recursive(id intege...
    99+
    2021-07-23
    递归查询两种写法与性能差异
  • Oracle递归查询的几种方法
    oracle的start with connect by prior是根据条件递归查询"树",分为四种使用情况:  第一种:start with 子节点ID='...' connect ...
    99+
    2024-04-02
  • C++ 递归与尾递归:性能差异和优化实践探讨
    c++++ 中标准递归会产生栈空间和时间开销,而尾递归不会。优化实践包括识别尾递归、转化为尾递归和启用编译器支持。尾递归比标准递归性能更高,因为它避免了创建额外活动记录和相关的开销。 ...
    99+
    2024-05-04
    c++ 递归 优化实践
  • Mysql树形表的两种查询方案(递归与自连接)
    你有没有遇到过这样一种情况: 一张表就实现了一对多的关系,并且表中每一行数据都存在“爷爷-父亲-儿子-…”的联系,这也就是所谓的树形结构 对于这样的表很显然想要通过查询来实现价值绝对是不能只靠sel...
    99+
    2023-09-30
    mysql 数据库
  • MyBatis实现两种查询树形数据的方法详解(嵌套结果集和递归查询)
    目录方法一:使用嵌套结果集实现1,准备工作2,实现代码方法二:使用递归查询实现    树形结构数据在开发中十分常见,比如:菜单数、组织树, 利用&nbs...
    99+
    2024-04-02
  • mysql实现递归查询的方法
    小编给大家分享一下mysql实现递归查询的方法,希望大家阅读完这篇文章后大所收获,下面让我们一起去探讨吧!mysql实现递归查询的方法:首先创建表,并初始化数据;然后向下递归,利用【find_in_set(...
    99+
    2024-04-02
  • Mysql8.0递归查询的简单用法
    这篇文章主要介绍“Mysql8.0递归查询的简单用法”,在日常操作中,相信很多人在Mysql8.0递归查询的简单用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Mysql8.0递归查询的简单用法”的疑惑有所...
    99+
    2023-06-20
  • MySQL递归查询的方法有哪些
    在MySQL中,可以使用以下方法来实现递归查询: 使用存储过程:可以通过编写存储过程来实现递归查询。存储过程可以递归地调用自身来...
    99+
    2024-04-30
    MySQL
  • MySQL递归查询的3种实现方式实例
    目录1.建表脚本1.1.建表2.递归查询三种实现方式2.1. 方式一 创建自定义函数实现递归查询2.1.1. 查询子节点的函数 查询时  包含自身 2.1.2. ...
    99+
    2024-04-02
  • Mysql树形递归查询的实现方法
    前言 对于数据库中的树形结构数据,如部门表,有时候,我们需要知道某部门的所有下属部分或者某部分的所有上级部门,这时候就需要用到mysql的递归查询 最近在做项目迁移,Oracle版本的迁到Mysql版本,遇...
    99+
    2024-04-02
  • Mysql8.0递归查询的简单用法示例
    前言 本文使用Mysql8.0的特新实现递归查询,文中给出了详细的实例代码,下面话不多说了,来一起看看详细的介绍吧 Mysql8.0递归查询用法 表数据如下 +--------+-...
    99+
    2024-04-02
  • C++ 递归的异步编程:并发性和性能考虑
    在现代 c++++ 中,递归异步编程采用语言的函数式特性和并发性原语,将异步任务分解成递归调用形式实现并发性,从而提供更高的吞吐量、响应性和资源利用率。然而,需要考虑调用和内存开销的性能...
    99+
    2024-04-30
    c++ 递归
  • MySQL实现递归查询的方法有哪些
    MySQL中实现递归查询的方法有以下几种:1. 使用存储过程:可以在存储过程中使用递归的方式进行查询。在每次递归调用时,将查询到的结...
    99+
    2023-09-11
    MySQL
  • mysql递归子节点查询的方法是什么
    在MySQL中,递归子节点查询可以通过使用递归查询语句来实现。MySQL本身没有提供递归查询的功能,但可以通过使用存储过程或视图来模...
    99+
    2023-10-25
    mysql
  • oracle两个表查询差集的方法是什么
    要查询两个表的差集,可以使用Oracle中的MINUS操作符。MINUS操作符用于从第一个查询结果中减去第二个查询结果,返回在第一个查询结果中存在但在第二个查询结果中不存在的行。例如,假设有两个表A和B,你想查询A表中存在但B表中不存在...
    99+
    2023-08-09
    oracle
  • MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)
    A:首先先看下一个简单的面试题斐波那契数列计算数组{1,1,2,3,5,8.......} 第30位值规律:1 1 从第三项开始,每一项都是前两项之和    有两种实现方式 第一种方式:public ...
    99+
    2023-05-31
    mybatis 递归 联动
  • jpa实现多对多的属性时查询的两种方法
    目录jpa多对多的属性查询第一:采用JPQL方式第二:采用specification 方法JPA,HQL多对多的查询语句Hql语句另外一种写法jpa多对多的属性查询 第一:采用JPQ...
    99+
    2024-04-02
  • mysql递归查询所有子级的方法是什么
    在MySQL中,可以使用递归查询(Recursive Query)来查询所有子级。MySQL并不直接支持递归查询,但可以通过使用`W...
    99+
    2023-09-11
    mysql
  • MySQL 对查询的结果集添加自增序号,两种写法
    在MySQL中,当我们所要查询的结果集没有ID字段时,为方便前台展示等业务需求,需要添加一个自增的序号字段(ID)。语法如下: SELECT (@i:=@i+1) 别名1,表字段信息  FROM 表名, (SELECT @i...
    99+
    2023-09-03
    mysql 数据库
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作