Den*_*nys 4 postgresql subquery postgresql-9.4
我有一个疑问:
update product_product
set (write_date, default_code) = (LOCALTIMESTAMP, 'update')
where product_tmpl_id in (
select distinct product_tmpl_id
from product_template
where type='import');
Run Code Online (Sandbox Code Playgroud)
而且需要7个小时才能完成。但是,当我执行子查询时:
select distinct product_tmpl_id
from product_template
where type='import';
Run Code Online (Sandbox Code Playgroud)
我收到错误:
列“product_tmpl_id”不存在
product_tmpl_id
表中没有列product_template
。
这是我的错误。第一个查询应该是:
update product_product set (write_date,default_code) = (LOCALTIMESTAMP,'update')
where product_tmpl_id in
(select distinct id from product_template where type='import');
Run Code Online (Sandbox Code Playgroud)
它只需要几秒钟即可运行。
所以我的问题如下:
结果select version();
是
PostgreSQL 9.4.3 on x86_64-unknown-linux-gnu,
compiled by gcc (Debian 4.9.2-10) 4.9.2, 64-bit
Run Code Online (Sandbox Code Playgroud)
为什么第一个查询没有失败?
因为这是有效的 SQL。
首先,考虑SELECT
对不引用该表中任何列的表运行 a 是有效的。
SELECT DISTINCT 'foo'
FROM product_template
WHERE type = 'import';
Run Code Online (Sandbox Code Playgroud)
foo
如果存在与该WHERE
子句匹配的任何行,则上面将返回单行结果。
其次考虑在子查询中引用外部表中的列是有效的(这是相关子查询工作所必需的)。
如果列名未通过表引用限定,则将在内部范围内(如果可能)和外部范围(否则)进行解析。在你的情况下product_template
没有这样的列,所以它被解析为属于product_product
.
作为最佳实践,明确列所属的表。如果子查询如下编写,它将无法编译并警告您错误。
IN (SELECT DISTINCT pt.product_tmpl_id
FROM product_template pt
WHERE pt.type = 'import');
Run Code Online (Sandbox Code Playgroud)
它到底做了什么?
这取决于。如果FROM product_template WHERE type = 'import';
返回零行那么你很幸运,这相当于
update product_product
set (write_date, default_code) = (LOCALTIMESTAMP, 'update')
where product_tmpl_id = null; /*Never true*/
Run Code Online (Sandbox Code Playgroud)
可能你并不幸运,它确实返回了至少一行。在这种情况下,您运行了以下等效项
update product_product
set (write_date, default_code) = (LOCALTIMESTAMP, 'update')
where product_tmpl_id = product_tmpl_id;
Run Code Online (Sandbox Code Playgroud)
这相当于
update product_product
set (write_date, default_code) = (LOCALTIMESTAMP, 'update')
where product_tmpl_id IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)
为什么要运行这么长时间?
我想首先它更新了表中的所有行。
我也不确定 Postgres 中的执行计划会是什么样的。
在最坏的情况下,它可能会选择与where
from匹配的所有行product_template
,传入相关参数,然后DISTINCT
对外部product_product
表中的每一行执行结果。