• KingbaseES 数据库连接


    一、数据准备:
    1. create table student(
    2. id int ,
    3. s_name varchar(20),
    4. t_id int
    5. );
    6. create table teacher(
    7. id int ,
    8. t_name varchar(20)
    9. );
    10. insert into student values (1,'zhangsan',3) , (2,'lisi',2) , (3,'wangwu',1), (4,'zhaoliu',4) ;
    11. insert into teacher values(1, 'zhaolaoshi'),(2, 'qianlaoshi'),(3, 'sunlaoshi'),(6, 'lilaoshi');
    12. 以上为准备数据。
    13. 以下为测试准备SQL,不需要执行。
    14. create index student_tid_idx on student(t_id);
    15. create index student_id_idx on student(id);
    16. create index teacher_id_idx on teacher(id);
    17. reindex table student;
    18. reindex table teacher;
    19. set enable_seqscan to off;
    20. set enable_hashjoin to off;
    21. set enable_mergejoin to off;
    22. drop index student_tid_idx;
    23. drop index student_id_idx;
    24. drop index teacher_id_idx;
    二、数据库连接种类
    1.自然连接

    不需要指定连接列,也不需要使用on语句,默认按照相同列名进行筛选。

    select * from student natural join teacher;

    1. demo=# select * from student natural join teacher;
    2. id | s_name | t_id | t_name
    3. ----+----------+------+------------
    4. 1 | zhangsan | 3 | zhaolaoshi
    5. 2 | lisi | 2 | qianlaoshi
    6. 3 | wangwu | 1 | sunlaoshi
    7. (3 行记录)
    2.内连接
    (1)隐式语法

    select * from student s,teacher t where s.t_id = t.id;

    1. demo=# select * from student s,teacher t where s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. (3 行记录)
    (2)显示语法

    写法1:

    select * from student s inner join teacher t on s.t_id = t.id;

    1. demo=# select * from student s inner join teacher t on s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. (3 行记录)

    写法2:

    select * from student s join teacher t on s.t_id = t.id;

    1. demo=# select * from student s join teacher t on s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. (3 行记录)
    3.外连接
    (1)左外连接

    写法1:

    select * from student s left join teacher t on s.t_id = t.id;

    1. demo=# select * from student s left join teacher t on s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. 4 | zhaoliu | 4 | |
    8. (4 行记录)

    写法2:

    select * from student s left outer join teacher t on s.t_id = t.id;

    1. demo=# select * from student s left outer join teacher t on s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. 4 | zhaoliu | 4 | |
    8. (4 行记录)

    写法3:

    select * from student s,teacher t where s.t_id = t.id(+);

    1. demo=# select * from student s,teacher t where s.t_id = t.id(+);
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. 4 | zhaoliu | 4 | |
    8. (4 行记录)
    (2)右外连接

    写法1:

    select * from student s right join teacher t on s.t_id = t.id;

    1. demo=# select * from student s right join teacher t on s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. | | | 6 | lilaoshi
    8. (4 行记录)

    写法2:

    select * from student s right outer join teacher t on s.t_id = t.id;

    1. demo=# select * from student s right outer join teacher t on s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. | | | 6 | lilaoshi
    8. (4 行记录)

    写法3:

    select * from student s,teacher t where s.t_id(+) = t.id;

    1. demo=# select * from student s,teacher t where s.t_id(+) = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. | | | 6 | lilaoshi
    8. (4 行记录)
    (3)全外连接

    写法1:

    select * from student s full join teacher t on s.t_id = t.id;

    1. demo=# select * from student s full join teacher t on s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. | | | 6 | lilaoshi
    8. 4 | zhaoliu | 4 | |
    9. (5 行记录)

    写法2:

    select * from student s full outer join teacher t on s.t_id = t.id;

    1. demo=# select * from student s full outer join teacher t on s.t_id = t.id;
    2. id | s_name | t_id | id | t_name
    3. ----+----------+------+----+------------
    4. 3 | wangwu | 1 | 1 | zhaolaoshi
    5. 2 | lisi | 2 | 2 | qianlaoshi
    6. 1 | zhangsan | 3 | 3 | sunlaoshi
    7. | | | 6 | lilaoshi
    8. 4 | zhaoliu | 4 | |
    9. (5 行记录)
    4.半连接

    写法1:

    select * from student s where exists (select * from teacher t where s.t_id = t.id) ;

    1. demo=# select * from student s where exists (select * from teacher t where s.t_id = t.id) ;
    2. id | s_name | t_id
    3. ----+----------+------
    4. 1 | zhangsan | 3
    5. 2 | lisi | 2
    6. 3 | wangwu | 1
    7. (3 行记录)

    写法2:

    select * from student s where s.t_id in (select id from teacher t) ;

    1. demo=# select * from student s where s.t_id in (select id from teacher t) ;
    2. id | s_name | t_id
    3. ----+----------+------
    4. 1 | zhangsan | 3
    5. 2 | lisi | 2
    6. 3 | wangwu | 1
    7. (3 行记录)
    5.反半连接

    写法1:

    select * from student s where not exists (select * from teacher t where s.t_id = t.id) ;

    1. demo=# select * from student s where not exists (select * from teacher t where s.t_id = t.id) ;
    2. id | s_name | t_id
    3. ----+---------+------
    4. 4 | zhaoliu | 4
    5. (1 行记录)

    写法2:

    select * from student s where s.t_id not in (select id from teacher t) ;

    1. demo=# select * from student s where s.t_id not in (select id from teacher t) ;
    2. id | s_name | t_id
    3. ----+---------+------
    4. 4 | zhaoliu | 4
    5. (1 行记录)
    三、数据库连接方法:
    1.嵌套循环连接
    (1)嵌套循环连接

    嵌套循环连接是最基础的连接操作,任何连接条件都可以使用这种连接方式,但这种连接方式代价过高,因此PG中很少使用这种连接方式,更多的会使用以下几种嵌套循环连接的变种。

    (2)物化嵌套循环连接

    嵌套循环连接每读取一条左表(外表)中的元组时,都需要扫描右表(内表)中的所有元组,为每条外表记录做内表全扫描,这个过程代价高昂,
    PG支持对内表做临时物化,并存储在内存或者临时文件中,在处理内表元组时,临时元组比缓冲区管理器更为高效,特别是内表比较小的时候,
    可以全部载入内存时,我们将这种连接方式称之为物化嵌套循环连接

    1. demo=# explain (analyze , buffers) select * from student s , teacher t ;
    2. QUERY PLAN
    3. -------------------------------------------------------------------------------------------------------------------
    4. Nested Loop (cost=0.00..9714.75 rows=774000 width=128) (actual time=0.014..0.020 rows=16 loops=1)
    5. Buffers: shared hit=2
    6. -> Seq Scan on teacher t (cost=0.00..19.00 rows=900 width=62) (actual time=0.007..0.007 rows=4 loops=1)
    7. Buffers: shared hit=1
    8. -> Materialize (cost=0.00..22.90 rows=860 width=66) (actual time=0.001..0.002 rows=4 loops=4)
    9. Buffers: shared hit=1
    10. -> Seq Scan on student s (cost=0.00..18.60 rows=860 width=66) (actual time=0.002..0.003 rows=4 loops=1)
    11. Buffers: shared hit=1
    12. Planning Time: 0.045 ms
    13. Execution Time: 0.037 ms
    14. (10 行记录)
    (3)外表索引嵌套循环连接

    如果右表(内表)上有索引,且该索引能用于搜索满足连接条件的元组,那么计划器会为考虑使用索引进行直接搜索,以代替顺序扫描。
    这种叫作索引嵌套循环连接

    1. set enable_seqscan to off;
    2. set enable_hashjoin to off;
    3. set enable_mergejoin to off;
    4. create index teacher_id_idx on teacher(id);
    5. reindex table teacher;
    1. demo=# explain (analyze , buffers) select * from student s , teacher t where s.t_id = t.id and t.id = 1;
    2. QUERY PLAN
    3. ---------------------------------------------------------------------------------------------------------------------------------
    4. Nested Loop (cost=10000000000.13..10000000009.21 rows=1 width=128) (actual time=0.013..0.014 rows=1 loops=1)
    5. Buffers: shared hit=3
    6. -> Seq Scan on student s (cost=10000000000.00..10000000001.05 rows=1 width=66) (actual time=0.006..0.007 rows=1 loops=1)
    7. Filter: (t_id = 1)
    8. Rows Removed by Filter: 3
    9. Buffers: shared hit=1
    10. -> Index Scan using teacher_id_idx on teacher t (cost=0.13..8.15 rows=1 width=62) (actual time=0.004..0.005 rows=1 loops=1)
    11. Index Cond: (id = 1)
    12. Buffers: shared hit=2
    13. Planning Time: 0.119 ms
    14. Execution Time: 0.031 ms
    15. (11 行记录)
    (4)外表索引扫描物化嵌套循环连接

    在索引嵌套循环连接的定义基础上,将内表(右表)物化,注:内表需要有索引

    1. set enable_seqscan to off;
    2. create index teacher_id_idx on teacher(id);
    3. reindex table teacher;
    1. demo=# explain (analyze , buffers) select * from student s inner join teacher t on s.t_id = t.id and t.id <=6;
    2. QUERY PLAN
    3. ---------------------------------------------------------------------------------------------------------------------------------------
    4. Nested Loop (cost=10000000000.13..10000000009.25 rows=1 width=128) (actual time=0.016..0.021 rows=3 loops=1)
    5. Join Filter: (s.t_id = t.id)
    6. Rows Removed by Join Filter: 13
    7. Buffers: shared hit=3
    8. -> Seq Scan on student s (cost=10000000000.00..10000000001.04 rows=4 width=66) (actual time=0.005..0.005 rows=4 loops=1)
    9. Buffers: shared hit=1
    10. -> Materialize (cost=0.13..8.15 rows=1 width=62) (actual time=0.001..0.002 rows=4 loops=4)
    11. Buffers: shared hit=2
    12. -> Index Scan using teacher_id_idx on teacher t (cost=0.13..8.15 rows=1 width=62) (actual time=0.004..0.005 rows=4 loops=1)
    13. Index Cond: (id <= 6)
    14. Buffers: shared hit=2
    15. Planning Time: 0.173 ms
    16. Execution Time: 0.041 ms
    17. (13 行记录)
    (5)外表索引扫描索引嵌套循环连接

    在索引嵌套循环连接的基础上,外表(左表)和内表(右表)上都有索引,且索引可以用于连接条件

    1. set enable_seqscan to off;
    2. set enable_hashjoin to off;
    3. set enable_mergejoin to off;
    4. create index student_tid_idx on student(t_id);
    5. create index teacher_id_idx on teacher(id);
    6. reindex table student;
    7. reindex table teacher;
    1. demo=# explain (analyze , buffers) select * from student s inner join teacher t on s.t_id = t.id and t.id <=6;
    2. QUERY PLAN
    3. ----------------------------------------------------------------------------------------------------------------------------------
    4. Nested Loop (cost=0.26..16.31 rows=1 width=128) (actual time=0.013..0.019 rows=3 loops=1)
    5. Buffers: shared hit=9
    6. -> Index Scan using teacher_id_idx on teacher t (cost=0.13..8.15 rows=1 width=62) (actual time=0.006..0.007 rows=4 loops=1)
    7. Index Cond: (id <= 6)
    8. Buffers: shared hit=2
    9. -> Index Scan using student_tid_idx on student s (cost=0.13..8.15 rows=1 width=66) (actual time=0.001..0.001 rows=1 loops=4)
    10. Index Cond: (t_id = t.id)
    11. Buffers: shared hit=7
    12. Planning Time: 0.242 ms
    13. Execution Time: 0.038 ms
    14. (10 行记录)
    2.归并连接
    (1)归并连接

    内外表按照连接条件进行排序后,再进行连接,与嵌套循环连接不同的是,归并连接只适用于自然连接与等值连接

    1. set enable_hashjoin to off;
    2. set enable_mergejoin to on;
    3. set enable_seqscan to on;
    1. demo=# explain (analyze , buffers) select * from student s, teacher t where s.t_id = t.id and t.id > 1;
    2. QUERY PLAN
    3. ----------------------------------------------------------------------------------------------------------------
    4. Merge Join (cost=2.15..2.21 rows=3 width=29) (actual time=0.017..0.019 rows=2 loops=1)
    5. Merge Cond: (s.t_id = t.id)
    6. Buffers: shared hit=2
    7. -> Sort (cost=1.08..1.09 rows=4 width=15) (actual time=0.008..0.009 rows=4 loops=1)
    8. Sort Key: s.t_id
    9. Sort Method: quicksort Memory: 25kB
    10. Buffers: shared hit=1
    11. -> Seq Scan on student s (cost=0.00..1.04 rows=4 width=15) (actual time=0.004..0.004 rows=4 loops=1)
    12. Buffers: shared hit=1
    13. -> Sort (cost=1.07..1.08 rows=3 width=14) (actual time=0.005..0.005 rows=3 loops=1)
    14. Sort Key: t.id
    15. Sort Method: quicksort Memory: 25kB
    16. Buffers: shared hit=1
    17. -> Seq Scan on teacher t (cost=0.00..1.05 rows=3 width=14) (actual time=0.003..0.003 rows=3 loops=1)
    18. Filter: (id > 1)
    19. Rows Removed by Filter: 1
    20. Buffers: shared hit=1
    21. Planning Time: 0.112 ms
    22. Execution Time: 0.038 ms
    23. (19 行记录)
    (2)物化归并

    在归并连接定义的基础上,将内表(右表)物化的归并

    (3)外表索引扫描归并

    归并连接定义的基础上,外表有索引,且索引适用于连接条件

    1. set enable_seqscan to off;
    2. create index teacher_id_idx on teacher(id);
    3. reindex table teacher;
    1. demo=# explain (analyze , buffers) select * from student s , teacher t where s.t_id = t.id and t.id>1;
    2. QUERY PLAN
    3. ------------------------------------------------------------------------------------------------------------------------------------
    4. Merge Join (cost=10000000001.21..10000000009.30 rows=3 width=29) (actual time=0.017..0.020 rows=2 loops=1)
    5. Merge Cond: (s.t_id = t.id)
    6. Buffers: shared hit=3
    7. -> Sort (cost=10000000001.08..10000000001.09 rows=4 width=15) (actual time=0.009..0.009 rows=4 loops=1)
    8. Sort Key: s.t_id
    9. Sort Method: quicksort Memory: 25kB
    10. Buffers: shared hit=1
    11. -> Seq Scan on student s (cost=10000000000.00..10000000001.04 rows=4 width=15) (actual time=0.004..0.005 rows=4 loops=1)
    12. Buffers: shared hit=1
    13. -> Index Scan using teacher_id_idx on teacher t (cost=0.13..12.18 rows=3 width=14) (actual time=0.004..0.004 rows=3 loops=1)
    14. Index Cond: (id > 1)
    15. Buffers: shared hit=2
    16. Planning Time: 0.122 ms
    17. Execution Time: 0.042 ms
    18. (14 行记录)
    (4)外表索引扫描物化归并

    在外表索引扫描归并连接的基础定义上,将内表物化的连接

    (5)外表索引扫描索引归并连接

    在外表索引扫描归并连接的基础上,内表也有索引,且索引可以用于连接条件

    1. create index teacher_id_idx on teacher(id);
    2. create index student_tid_idx on student(t_id);
    3. reindex table teacher;
    4. reindex table student;
    1. demo=# explain (analyze , buffers) select * from student s , teacher t where s.t_id = t.id and t.id>1;
    2. QUERY PLAN
    3. -----------------------------------------------------------------------------------------------------------------------------------
    4. Merge Join (cost=0.26..20.40 rows=3 width=29) (actual time=0.010..0.013 rows=2 loops=1)
    5. Merge Cond: (s.t_id = t.id)
    6. Buffers: shared hit=4
    7. -> Index Scan using student_tid_idx on student s (cost=0.13..12.19 rows=4 width=15) (actual time=0.003..0.004 rows=4 loops=1)
    8. Buffers: shared hit=2
    9. -> Index Scan using teacher_id_idx on teacher t (cost=0.13..12.18 rows=3 width=14) (actual time=0.003..0.003 rows=3 loops=1)
    10. Index Cond: (id > 1)
    11. Buffers: shared hit=2
    12. Planning Time: 0.269 ms
    13. Execution Time: 0.033 ms
    14. (10 行记录)
    3.散列连接
    (1)内存散列连接

    与归并连接类似,散列连接只能适用于自然连接与等值连接,内存散列连接是在work_mem中处理,散列表区域被称为处理批次,一个处理批
    次会有多少散列槽,被称为桶,桶的数量由nodeHash.c中定义的ExecChooseHashTableSize函数确定,且桶的数量总是2的整数次幂

    1. set enable_hashjoin to on;
    2. set enable_mergejoin to on;
    3. set enable_seqscan to on;
    1. demo=# explain (analyze , buffers) select * from student s, teacher t where s.t_id = t.id;
    2. QUERY PLAN
    3. ----------------------------------------------------------------------------------------------------------------
    4. Hash Join (cost=1.09..2.19 rows=4 width=29) (actual time=0.020..0.023 rows=3 loops=1)
    5. Hash Cond: (s.t_id = t.id)
    6. Buffers: shared hit=2
    7. -> Seq Scan on student s (cost=0.00..1.04 rows=4 width=15) (actual time=0.007..0.008 rows=4 loops=1)
    8. Buffers: shared hit=1
    9. -> Hash (cost=1.04..1.04 rows=4 width=14) (actual time=0.006..0.007 rows=4 loops=1)
    10. Buckets: 1024 Batches: 1 Memory Usage: 9kB
    11. Buffers: shared hit=1
    12. -> Seq Scan on teacher t (cost=0.00..1.04 rows=4 width=14) (actual time=0.002..0.003 rows=4 loops=1)
    13. Buffers: shared hit=1
    14. Planning Time: 0.067 ms
    15. Execution Time: 0.042 ms
    16. (12 行记录)
    (2)带倾斜的混合散列连接

    在内存散列定义的基础只上,如果内表的元组无法全部载入内存单个处理批次时,PG就用创建多个批次,只工作区中只分配一个批次,其它批次
    都以临时文件的形式创建,属于某个批次的元组将通过临时元组存储功能写入相应的文件中

  • 相关阅读:
    算法刷题第一天:二分查找
    Android系统启动流程分析
    java8-使用流-2
    2023考研常识之全国考研初试成绩基本分区要求是如何界定的?
    台达PLC出现故障该怎么进行远程维护和程序上下载?
    java基于springboot英语学习网站
    EvilAppleJuice(邪恶苹果汁)-ESP32C3项目(iphone疯狂弹窗)
    【pytorch源码分析--torch执行流程与编译原理】
    A Comprehensive Survey on Graph Neural Networks
    Spring源码分析-2 Spring的简单使用和原理分析
  • 原文地址:https://blog.csdn.net/lyu1026/article/details/126900050