我的SQL DELETE语句中的子查询会多次执行吗?该如何优化?
关于你的DELETE语句子查询执行次数及修复方案
子查询是否会逐行执行?
你写的这个子查询是标量子查询(仅返回单个patient_id值),主流SQL引擎(包括你使用的练习平台)都会将其优化为仅执行一次,不会针对patients表的每一行重复运行。它会先计算出偏移10条后的第一个patient_id,再用这个值作为条件执行删除操作。
数据删除导致子查询结果变化的问题?
你的原语句其实不会出现这个问题——子查询的结果在DELETE执行前就已经确定,删除过程中不会重新计算这个临界值。不过原语句存在一个潜在风险:如果patient_id存在重复值,会误删本应保留的行(比如第10条和第11条的patient_id相同,>=条件会把第10条也删掉)。
修复方案
方案1:用窗口函数精准保留前N行
通过ROW_NUMBER()窗口函数标记行号,只保留行号≤10的记录,避免id重复带来的误删问题:
DELETE FROM patients WHERE patient_id NOT IN ( SELECT patient_id FROM ( SELECT patient_id, ROW_NUMBER() OVER (ORDER BY patient_id) AS row_num FROM patients ) AS ranked_patients WHERE row_num <= 10 );
嵌套子查询是为了兼容部分不允许在DELETE语句中直接引用窗口函数的数据库。
方案2:用CTE(公共表表达式)简化写法
如果你的数据库支持CTE(比如PostgreSQL、MySQL 8.0+),可以用更清晰的逻辑实现:
WITH ranked_patients AS ( SELECT patient_id, ROW_NUMBER() OVER (ORDER BY patient_id) AS row_num FROM patients ) DELETE FROM patients WHERE patient_id IN ( SELECT patient_id FROM ranked_patients WHERE row_num > 10 );
这两种方案都会先一次性计算出所有要保留/删除的行,再执行删除操作,既避免了删除过程中数据变化影响结果的问题,也适配了patient_id重复的场景。
内容的提问来源于stack exchange,提问作者Tom Huntington
相关产品推荐
相关产品推荐

