当前位置: 首页 > news >正文

子查询总拖慢查询?把它变成连接就能解决?


url: /posts/79c590fbd87ece535b11a71c9667884f/
title: 子查询总拖慢查询?把它变成连接就能解决?
date: 2025-10-21T03:54:12+08:00
lastmod: 2025-10-21T03:54:12+08:00
author: cmdragon

summary:
子查询是嵌套在其他SQL语句中的查询,分为标量、行、列和表子查询。相关子查询依赖外部查询变量,性能较差,而非相关子查询独立执行。PostgreSQL优化器通过子查询扁平化将子查询转换为更高效的连接操作。连接操作包括内连接、外连接和交叉连接,优化器基于成本模型选择连接顺序和方法,如嵌套循环、哈希和排序合并连接。通过改写子查询为连接或使用LATERAL连接,可以显著提升查询性能。

categories:

  • postgresql

tags:

  • 基础入门
    • PostgreSQL
  • 子查询
  • 连接优化
  • SQL性能优化
  • LATERAL连接
  • 查询改写

cmdragon_cn.png cmdragon_cn.png

扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长

发现1000+提升效率与开发的AI工具和实用程序:https://tools.cmdragon.cn/

一、子查询:从基础到进阶

子查询是嵌套在其他SQL语句中的查询,相当于“查询里的查询”。PostgreSQL支持多种类型的子查询,我们可以根据返回结果的结构和依赖关系来分类。

1.1 子查询的基本类型

根据返回结果的维度,子查询可以分为四类:

  • 标量子查询:返回单个值(一行一列),常用于SELECTWHEREHAVING子句中。例如:
    -- 查询所有商品的最高价格,作为单独列返回
    SELECT product_name, price, (SELECT MAX(price) FROM products) AS max_price
    FROM products;
    
  • 行子查询:返回一行多列,需用括号包裹列组合。例如:
    -- 查找与管理员邮箱匹配的用户(假设id和name唯一)
    SELECT * FROM users 
    WHERE (id, name) = (SELECT id, name FROM admins WHERE email = 'admin@example.com');
    
  • 列子查询:返回一列多行,常用于INANYALL运算符后。例如:
    -- 查找购买过金额超过100元订单的用户
    SELECT name FROM users 
    WHERE id IN (SELECT user_id FROM orders WHERE amount > 100);
    
  • 表子查询:返回多行多列,需作为临时表(别名)使用,常用于FROM子句中。例如:
    -- 查找总订单金额超过1000元的用户
    SELECT * FROM (SELECT user_id, SUM(amount) AS total FROM orders GROUP BY user_id
    ) AS order_totals 
    WHERE total > 1000;
    
1.2 相关子查询 vs 非相关子查询

根据是否依赖外部查询的变量,子查询分为:

  • 非相关子查询:子查询不引用外部查询的任何列,只执行一次。例如上文中的“查找购买过金额超过100元订单的用户”,子查询SELECT user_id FROM orders WHERE amount > 100独立于外部的users表。
  • 相关子查询:子查询引用了外部查询的列,每次外部查询的行都会触发子查询执行。例如:
    -- 查找有订单金额超过100元的用户(相关子查询依赖u.id)
    SELECT name FROM users u 
    WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.amount > 100);
    
    相关子查询的性能通常更差——想象一下,如果你有1000个用户,子查询就要执行1000次
1.3 PostgreSQL对子查询的处理:扁平化与去相关

PostgreSQL的查询优化器(Query Optimizer)会尝试将可优化的子查询转换为更高效的连接操作,这个过程叫子查询扁平化(Subquery Flattening)。例如,对于非相关的IN子查询:

-- 原写法:IN子查询
SELECT name FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 100);

优化器会将其“扁平化”为等价的内连接:

-- 优化后:内连接(自动去重)
SELECT DISTINCT u.name 
FROM users u 
JOIN orders o ON u.id = o.user_id 
WHERE o.amount > 100; 

为什么要这么做?因为连接操作的执行计划(如哈希连接、嵌套循环)通常比子查询更高效,尤其是当子查询返回大量结果时。

但不是所有子查询都能被扁平化——比如相关子查询返回多列的子查询,优化器无法直接转换,这时需要我们手动改写(后面会讲)。

二、连接优化:理解连接的“底层逻辑”

连接是SQL中组合多个表

http://www.dtcms.com/a/511344.html

相关文章:

  • YOLOv3 核心笔记
  • 谷歌发布首个隐私安全模型VaultGemma
  • 什么情况下可能会导致 Redis 阻塞?
  • 保姆级教程vscode创建uniapp vue3+ts+pinia项目并实现自动导入、打包功能
  • 网站标题改动网络安全工程师工作内容
  • 外贸公司网站制作公司wordpress 视频播放器插件
  • 【时时三省】(C语言基础)文件读写的出错检测
  • Visual Basic 使用公共对话框
  • Amazon Bedrock助力飞书深诺:打造电商广告智能分类的“核心引擎”
  • Android App Startup 库使用说明文档,初始化不再用Application了...
  • 【鸿蒙开发手册】重生之我要学习鸿蒙HarmonyOS开发
  • 市面上的开源 AI 智能体平台使用体验
  • 2025重庆国际工业自动化及机器人展览会将带来那些新技术新体验?
  • 电商网站的建设背景找素材去哪个网站
  • 厦门杏林建设企业网站网络营销的优势有哪些
  • 个人信息出境认证办法
  • 复杂结构数据挖掘(三)关联规则挖掘实验
  • Vue3 + Vite 生产环境缓存更新问题及自动检测方案详解
  • D3QN + 优先经验回放(PER)实现全解析:从数据树到训练循环(附伪代码与流程图)
  • 查公司的国家网站有哪些域名备案时网站名称
  • ES6+新特性:ES7(二)
  • 嵌入式开发中的YUV知识点详解
  • 【文献阅读】当代MOF与机器学习
  • Java 文档注释
  • 免费网站推广渠道西安网站建设成功建设
  • 有一个服务器,用于提供HTTP服务,但是需要限制每个用户在任意的100秒内只能请求60次,怎么实现这个功能
  • 云原生周刊:Helm 十年,成就 Kubernetes 的生态中枢
  • 线段树学习
  • 单页 网站 模板wordpress腾讯云对象存储
  • 【论文阅读】Pore-scale modeling of complex transport phenomena in porous media