SQL子查询的感悟[亲测有效]

SQL子查询的感悟[亲测有效]今天在听陈华军老师的课时;感触颇多。其中讲到“不同执行计划的选择(子查询)”这一栏。我们在平时工作也经常要用到子查询。有哪些思路来优化这种子查询呢? 例如我们今天实验的表结构 表T1 有10000条记

SQL子查询的感悟

今天在听陈华军老师的课时;感触颇多。其中讲到“不同执行计划的选择(子查询)这一栏。我们在平时工作也经常要用到子查询。有哪些思路来优化这种子查询呢?

例如我们今天实验的表结构

  • 表T1 有10000条记录;并在id字段创建btree索引
  • 表T2 有1000条记录
postgres=# create table t1(id int primary key, info text, reg_time timestamp);
CREATE TABLE
postgres=# create table t2(id int, name text);
CREATE TABLE
postgres=# insert into t1 select generate_series(1, 10000),"lottu", now();
INSERT 0 10000
postgres=# insert into t2 select (random()*1000)::int, "lottu"||id  from generate_series(1,1000) id;
INSERT 0 1000
postgres=# create index ind_t1_id on t1(id);
CREATE INDEX

代码100分

实验对象SQL;

代码100分select * from t1 where id in (select id from t2);

SQL语法改造

我们先看下这SQL的执行计划

postgres=# explain (analyze,verbose,costs,timing) select * from t1 where id in (select id from t2);
                                                             QUERY PLAN                                                             
----------------------------------------------------------------------
 Merge Join  (cost=54.25..99.73 rows=628 width=18) (actual time=1.319..2.365 rows=628 loops=1)
   Output: t1.id, t1.info, t1.reg_time
   Inner Unique: true
   Merge Cond: (t1.id = t2.id)
   ->  Index Scan using ind_t1_id on public.t1  (cost=0.29..337.29 rows=10000 width=18) (actual time=0.014..0.421 rows=997 loops=1)
         Output: t1.id, t1.info, t1.reg_time
   ->  Sort  (cost=53.97..55.54 rows=628 width=4) (actual time=1.298..1.387 rows=628 loops=1)
         Output: t2.id
         Sort Key: t2.id
         Sort Method: quicksort  Memory: 54kB
         ->  HashAggregate  (cost=18.50..24.78 rows=628 width=4) (actual time=0.730..0.877 rows=628 loops=1)
               Output: t2.id
               Group Key: t2.id
               ->  Seq Scan on public.t2  (cost=0.00..16.00 rows=1000 width=4) (actual time=0.013..0.267 rows=1000 loops=1)
                     Output: t2.id
 Planning Time: 0.454 ms
 Execution Time: 2.507 ms
(17 rows)

从该执行计划可以看到很多信息;

  • 其中获取的行数只有628条;
  • 执行时间是2.507ms;
  • 两表之间采用Merge Join;由于t2表没有索引且无须存放;需要使用内存进行排序。

若采用join的方式

如果子查询被循环执行导致SQL慢,可尝试改成等价的join;

代码100分postgres=# explain (analyze,verbose,costs,timing) select t1,* from t1 , t2 where t1.id = t2.id ;
                                                             QUERY PLAN                                                             
------------------------------------------------------------------------------------------------------------------------------------
 Merge Join  (cost=66.11..117.17 rows=1000 width=72) (actual time=0.601..2.184 rows=1000 loops=1)
   Output: t1.*, t1.id, t1.info, t1.reg_time, t2.id, t2.name
   Merge Cond: (t1.id = t2.id)
   ->  Index Scan using ind_t1_id on public.t1  (cost=0.29..337.29 rows=10000 width=60) (actual time=0.021..0.726 rows=997 loops=1)
         Output: t1.*, t1.id, t1.info, t1.reg_time
   ->  Sort  (cost=65.83..68.33 rows=1000 width=12) (actual time=0.573..0.721 rows=1000 loops=1)
         Output: t2.id, t2.name
         Sort Key: t2.id
         Sort Method: quicksort  Memory: 71kB
         ->  Seq Scan on public.t2  (cost=0.00..16.00 rows=1000 width=12) (actual time=0.013..0.226 rows=1000 loops=1)
               Output: t2.id, t2.name
 Planning Time: 0.288 ms
 Execution Time: 2.421 ms
(13 rows)

性能有点提升;其实两个SQL之间不等价;因为T2有重复id;导致最后的结果集是1000条;而非上面的628.

采用array的方式改写

postgres=# explain (analyze,verbose,costs,timing) select * from t1 where id = any(array(select id from t2));
                                                        QUERY PLAN                                                         
---------------------------------------------------------------------------------------------------------------------------
 Index Scan using ind_t1_id on public.t1  (cost=16.29..59.03 rows=10 width=18) (actual time=0.418..1.108 rows=628 loops=1)
   Output: t1.id, t1.info, t1.reg_time
   Index Cond: (t1.id = ANY ($0))
   InitPlan 1 (returns $0)
     ->  Seq Scan on public.t2  (cost=0.00..16.00 rows=1000 width=4) (actual time=0.014..0.127 rows=1000 loops=1)
           Output: t2.id
 Planning Time: 0.106 ms
 Execution Time: 1.178 ms
(8 rows)

结果跟SQL1是等价的;用时只有1.178ms;且未用内存;效果最优。选它准没错

思路转换

前面我们t2表只有1000条记录,且id小于1000;若我们t2表有1000000条甚至更多;且ID也没有限制。

select * from t1 where id in (select id from t2 where id <= 1000);
或者
with t as
(select id from t2 where id <= 1000)
select t1.* from t1 where id in (select id from t);

我相信很多人还是会采用这种写法。这些写不好;虽然你一个SQL搞定;但是效率慢。这是有人说你可以在t2表建个索引;这个是可以的;效率确实提升很多。若t2没有这个索引;你没必要单独为这个需求创建一个索引。

我建议可以用一个子表用来存放

select id from t2 where id <= 1000);

子表:你可以用临时表/表/物化视图。

这样的优势;减少多次扫描t2表的数据块;只要扫描一次即可

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/8393.html

(0)
上一篇 2023-02-28 19:30
下一篇 2023-02-28

相关推荐

  • JDBC-用程序操作数据库「建议收藏」

    JDBC-用程序操作数据库「建议收藏」一、JDBC JDBC:Java Database Connectivity 驱动:每个数据库厂商对JDBC的接口的实现类。 二、JDBC程序的开发步骤 1、引入驱动jar 2、编写代码 三、JDB…

    2023-02-14
    167
  • 用Python创建并管理线程的完整指南

    用Python创建并管理线程的完整指南现代编程需要对多任务处理有一个更好的理解,因为处理器的核心数已经增加,多线程编程已经成为一种常见而重要的技能。Python提供了非常优秀的线程支持,使开发者可以轻松地创建并管理线程。

    2024-08-03
    30
  • Python工程师解读星空代码

    Python工程师解读星空代码如今,在计算机编程中,Python语言已成为前端开发、数据分析、人工智能领域流行的语言之一。Python作为一个功能强大的高级编程语言,可以应用在多个领域。其中,它在a href=”https://www.starrysky.org/” target=”_blank” rel=”noopener”星空/a项目中也大放异彩。Python工程师的任务就是理解并优化这些代码,使其更加高效、可读和易于维护。

    2024-06-09
    47
  • Python元素呼叫:简化元素查找和操作

    Python元素呼叫:简化元素查找和操作a href=”https://beian.miit.gov.cn/”苏ICP备2023018380号-1/a Copyright www.python100.com .Some Rights Reserved.

    2023-12-31
    108
  • MySQL的工作流程及常用工具简介——MySQL数据库软件的使用「建议收藏」

    MySQL的工作流程及常用工具简介——MySQL数据库软件的使用「建议收藏」一. MySQL的工作流程 (1)操作系统用户启动MySQL服务。 (2)MySQL服务启动期间,首先将配置文件中的参数信息读入服务器内存。 (3)根据MySQL配置文件的参数信息或者编译MySQL…

    2023-02-08
    164
  • centos7u盘安装_mips 龙芯

    centos7u盘安装_mips 龙芯UOS 20(统一操作系统)的安装方法同样适用于深之度的Deepin V20和Debian 10 Buster 一、安装数据库 sudo apt install mariadb-server 二、初…

    2022-12-23
    149
  • Database | 浅谈Query Optimization (1)[亲测有效]

    Database | 浅谈Query Optimization (1)[亲测有效]综述 由于SQL是声明式语言(declarative),用户只告诉了DBMS想要获取什么,但没有指出如何计算。因此,DBMS需要将SQL语句转换成可执行的查询计划(Query Plan)。但是对同样的

    2023-04-10
    187
  • NSS支持的数据库「建议收藏」

    NSS支持的数据库「建议收藏」NSS,简写自Name Service Switch。我把它译为“名字服务中心”。 在*nix操作系统中,NSS是C语言库(Library C或者glibc)的一部分,用以寻找名字。比如说,我们运行…

    2022-12-17
    142

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注