SQL Server 2017与PostgreSQL 12在子查询重写上有何不同

风敏大大_2115

风敏大大_2115

2026-08-31

537人浏览

原创

sql server 2017子查询重写依赖优化器自动展开,cte不物化;postgresql 12默认物化cte、禁止limit子查询、严格要求标量子查询单行,两者在null处理、别名规则及重写可控性上差异显著。

sql server 2017与postgresql 12在子查询重写上有何不同

SQL Server 2017的子查询重写行为受ANSI SQL兼容性影响大

SQL Server 2017默认使用ANSI SQL标准的严格解析规则,对子查询中未明确限定的列名(尤其是ORDER BY、TOP、OFFSET/FETCH)会直接报错,而不是尝试推断上下文。比如在FROM子句中用派生表却没加别名,会触发Msg 102, Level 15, State 1, Line X: Incorrect syntax near ')'。

它还会主动将某些简单IN子查询(尤其含常量或单表)内联为JOIN或SEMI JOIN,但仅限于优化器判定“无相关性”时;一旦子查询引用外部表字段(即相关子查询),就基本不重写,而是走嵌套循环执行计划。

  • 不支持WITH子句中定义后在多个后续语句复用(CTE只作用于紧邻的单个语句)
  • EXISTS子查询里的SELECT *会被优化器忽略字段列表,但SELECT 1更稳妥,避免意外触发列解析
  • 若子查询含GROUP BY且外部查询有ORDER BY,必须显式给派生表加别名,否则报错

PostgreSQL 12默认启用子查询物化(Materialization)策略

PostgreSQL 12引入了enable_material和materialize参数控制是否将子查询结果缓存为临时行集。默认开启,意味着即使一个WHERE EXISTS (SELECT ...)子查询被多次调用,也可能只执行一次并复用结果——这和SQL Server的逐次执行完全不同。

但它对子查询重写的保守性更高:不会把IN自动转成JOIN,也不会把NOT IN重写为NOT EXISTS(这点极易引发NULL逻辑错误)。你得手动改写,否则性能可能陡降。

  • 相关子查询中若含LIMIT,PostgreSQL 12会拒绝执行(报ERROR: LIMIT # is not allowed in subqueries),而SQL Server允许
  • 派生表(FROM (SELECT ...) AS t)必须带AS别名,且别名不能省略括号——FROM (SELECT 1) t合法,FROM (SELECT 1) t(x)也合法,但FROM (SELECT 1) t在某些旧客户端驱动下可能失败
  • UNION子查询作为派生表时,PostgreSQL要求所有分支列名/类型一致,SQL Server则按第一个分支隐式推导

两者对CTE的处理差异直接决定子查询能否被“拆解重用”

SQL Server 2017把CTE当作语法糖,优化器通常展开(inline)为等价子查询,除非显式用OPTION (USE HINT('DISABLE_OPTIMIZER_ROWGOAL'))之类干预;这意味着CTE定义多次,实际可能执行多次——和写成多个相同子查询没区别。

PostgreSQL 12则默认将CTE视为“优化边界”,即WITH t AS (SELECT ...)之后,只要t被引用多次,就会物化一次结果供复用(除非加MATERIALIZED或NOT MATERIALIZED强制指定)。这是真正意义上的“子查询重写为可复用中间结果”。

  • SQL Server里WITH后面不能跟RECURSIVE关键字(虽支持递归CTE,但关键词是可选的);PostgreSQL 12必须写WITH RECURSIVE才启用递归,否则报错
  • PostgreSQL中CTE可定义后立即用INSERT/UPDATE/DELETE修改其基础表,SQL Server不允许——CTE只是只读逻辑视图
  • 两者都不允许在CTE定义中引用自身(非递归场景),但PostgreSQL报错更早(PARSE阶段),SQL Server拖到EXECUTE阶段才报

最容易踩坑的是NULL感知与空结果集行为

SQL Server 2017在NOT IN (subquery)遇到子查询返回NULL时,整个条件恒为UNKNOWN,导致查不到任何行——这是ANSI SQL标准行为,但开发者常误以为是“空结果”。PostgreSQL 12同样如此,但错误更隐蔽:如果子查询本身因权限或WHERE过滤为空,NOT IN仍返回空集,而NOT EXISTS才真正表达“不存在匹配项”。

  • SQL Server中SELECT * FROM t WHERE id IN (SELECT id FROM s WHERE flag = 1),若s中无flag = 1的行,结果为空;PostgreSQL同理,但若s表被GRANT限制,还可能抛权限错误而非静默空结果
  • PostgreSQL 12对SELECT子句中的标量子查询(如SELECT (SELECT name FROM users WHERE id = t.user_id))要求必须返回0或1行,否则报more than one row returned by a subquery used as an expression;SQL Server则取第一行(不报错),行为不一致
  • 两者都支持LATERAL(SQL Server叫APPLY),但PostgreSQL 12的LATERAL可出现在WHERE或ORDER BY中,SQL Server的CROSS APPLY只能在FROM里

关键点不在“谁重写得更多”,而在于重写是否可控、是否可预测。SQL Server偏向让优化器替你决定,PostgreSQL偏向让你明确声明意图——前者省事但难调试,后者啰嗦但可追溯。真正在意子查询行为的场景(比如报表SQL迁移、性能调优),必须逐条验证执行计划,不能依赖“看起来一样”。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
postgresql常用命令
postgresql常用命令

postgresql常用命令psql、createdb、dropdb、createuser、dropuser、\l、\c、\dt、\d table_name、\du、\i file_name、\e和\q等。本专题为大家提供postgresql相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.10

233

5

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

4529

19

postgresql常用命令有哪些
postgresql常用命令有哪些

postgresql常用命令psql、createdb、dropdb、createuser、dropuser、\l、\c、\dt、\d table_name、\du、\i file_name、\e和\q等。更详细的postgresql常用命令,大家可以访问下面的文章。

2023.11.16

647

3

postgresql常用命令介绍
postgresql常用命令介绍

postgresql常用命令有\l、\d、\d5、\di、\ds、\dv、\df、\dn、\db、\dg、\dp、\c、\pset、show search_path、ALTER TABLE、INSERT INTO、UPDATE、DELETE FROM、SELECT等。想了解更多postgresql的相关内容,可以阅读本专题下面的文章。

2023.11.20

1396

6

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

2026.02.12

460

19

PostgreSQL 性能优化与查询执行计划实战
PostgreSQL 性能优化与查询执行计划实战

本专题深入解析PostgreSQL性能优化核心,聚焦查询执行计划的实战应用。通过EXPLAIN命令精准定位瓶颈,结合索引策略、SQL改写与参数调优,系统提升查询效率。从执行计划解读到性能调优全流程,助你掌握数据库性能诊断与优化实战能力。

2026.05.08

150

10

PostgreSQL 在 Next.js / Go 全栈架构中的工程化实践
PostgreSQL 在 Next.js / Go 全栈架构中的工程化实践

本文详解如何利用Next.js(搭配Drizzle ORM)与Go后端构建高性能应用,充分发挥PG在JSONB非结构化存储与pgvector向量检索上的优势。从数据建模到Docker容器化部署,打造支持AI时代的“One Database”工程化解决方案。

2026.05.08

901

10

PostgreSQL高级特性、内核机制与现代数据架构
PostgreSQL高级特性、内核机制与现代数据架构

本专题从MVCC并发控制与WAL日志等内核机制出发,详解JSONB、PostGIS及pgvector等高级特性。探讨如何利用单一引擎支撑关系型、向量及图数据等现代数据架构需求,助您掌握构建高并发、智能化应用的核心技术。

2026.05.08

244

10

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

5631

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.8万人学习