prepared SQL语句可以被数据库改写吗?
Can prepared SQL statement be rewritten by the database?
我有这个看起来相当无辜的 JDBC 代码:
String sql = "UPDATE table_name SET column2 = column1";
try (PreparedStatement statement = dbConnection.prepareStatement(sql)) {
statement.executeUpdate();
}
dbConnection.commit();
当在 PostgreSQL 上 运行ning 时,我注意到 实际 运行ning 查询(从 PostgreSQL 中可见)如下:
UPDATE table_name SET column2 = i.column1 FROM table_name i
问题是重写的查询 多 更昂贵:
# explain update table_name set column2 = i.column1 from table_name i;
QUERY PLAN
-------------------------------------------------------------------------------
Update on table_name (cost=0.00..3586127424.55 rows=206294914809 width=166)
-> Nested Loop (cost=0.00..3586127424.55 rows=206294914809 width=166)
-> Seq Scan on table_name (cost=0.00..15453.97 rows=454197 width=156)
-> Materialize (cost=0.00..19942.96 rows=454197 width=10)
-> Seq Scan on table_name i (cost=0.00..15453.97 rows=454197 width=10)
(5 rows)
而不是
# explain update table_name set column2 = column1;
QUERY PLAN
------------------------------------------------------------------------
Update on table_name (cost=0.00..15453.97 rows=454197 width=156)
-> Seq Scan on table_name (cost=0.00..15453.97 rows=454197 width=156)
(2 rows)
重写的查询花费了几乎无限的时间 运行 而非重写的查询在几分钟甚至几秒钟内完成。
问题:
- 数据库(我假设)重写查询是否很常见?
- 如果是,PostgreSQL怎么会蠢到搬起石头砸自己的脚?这是已知错误吗?
- 如何避免查询重写 - 在数据库级别但最好是 JDBC 级别?
有些数据库实际上会重写代码(尽管这不是数据库起作用,而是 java -- java 了解如何在建立有效连接后转换代码)但是您的query 是误导 Postgres 的东西。
Postgres 完全按照您的要求执行,因为该查询实际上应该影响数据库中的所有行。但如果您的计划有所不同,那么您应该让我们知道您的目标是什么
我认为 这在某种程度上与原始查询
UPDATE table_name SET column2 = column1
没有WHERE
声明。
一旦我将查询更改为
UPDATE table_name SET column2 = column1 WHERE 1=1
,它就像我期望的那样工作。
抱歉,这不是 scientific/referenced 解释,但希望这仍然对某些人有所帮助。我之前出于不同的目的使用过这个技巧(一些遗留数据库需要 WHERE
子句)并且它似乎也适用于这种情况。
我有这个看起来相当无辜的 JDBC 代码:
String sql = "UPDATE table_name SET column2 = column1";
try (PreparedStatement statement = dbConnection.prepareStatement(sql)) {
statement.executeUpdate();
}
dbConnection.commit();
当在 PostgreSQL 上 运行ning 时,我注意到 实际 运行ning 查询(从 PostgreSQL 中可见)如下:
UPDATE table_name SET column2 = i.column1 FROM table_name i
问题是重写的查询 多 更昂贵:
# explain update table_name set column2 = i.column1 from table_name i;
QUERY PLAN
-------------------------------------------------------------------------------
Update on table_name (cost=0.00..3586127424.55 rows=206294914809 width=166)
-> Nested Loop (cost=0.00..3586127424.55 rows=206294914809 width=166)
-> Seq Scan on table_name (cost=0.00..15453.97 rows=454197 width=156)
-> Materialize (cost=0.00..19942.96 rows=454197 width=10)
-> Seq Scan on table_name i (cost=0.00..15453.97 rows=454197 width=10)
(5 rows)
而不是
# explain update table_name set column2 = column1;
QUERY PLAN
------------------------------------------------------------------------
Update on table_name (cost=0.00..15453.97 rows=454197 width=156)
-> Seq Scan on table_name (cost=0.00..15453.97 rows=454197 width=156)
(2 rows)
重写的查询花费了几乎无限的时间 运行 而非重写的查询在几分钟甚至几秒钟内完成。
问题:
- 数据库(我假设)重写查询是否很常见?
- 如果是,PostgreSQL怎么会蠢到搬起石头砸自己的脚?这是已知错误吗?
- 如何避免查询重写 - 在数据库级别但最好是 JDBC 级别?
有些数据库实际上会重写代码(尽管这不是数据库起作用,而是 java -- java 了解如何在建立有效连接后转换代码)但是您的query 是误导 Postgres 的东西。 Postgres 完全按照您的要求执行,因为该查询实际上应该影响数据库中的所有行。但如果您的计划有所不同,那么您应该让我们知道您的目标是什么
我认为 这在某种程度上与原始查询
UPDATE table_name SET column2 = column1
没有WHERE
声明。
一旦我将查询更改为
UPDATE table_name SET column2 = column1 WHERE 1=1
,它就像我期望的那样工作。
抱歉,这不是 scientific/referenced 解释,但希望这仍然对某些人有所帮助。我之前出于不同的目的使用过这个技巧(一些遗留数据库需要 WHERE
子句)并且它似乎也适用于这种情况。