Sql 为了避免重复的绑定变量,针对这样的子选择进行连接是一种糟糕的形式吗?
下面是一个简化的示例查询,使用“传统”方式完成(在PostgreSQL 8.3中测试的示例查询): 问题是,将同一个bind变量传递两次是很麻烦的(对于更复杂的查询,当需要六次或更多次时,更是如此) 当然,SQL允许在同一查询中多次使用同一绑定变量:Sql 为了避免重复的绑定变量,针对这样的子选择进行连接是一种糟糕的形式吗?,sql,join,subquery,bind-variables,Sql,Join,Subquery,Bind Variables,下面是一个简化的示例查询,使用“传统”方式完成(在PostgreSQL 8.3中测试的示例查询): 问题是,将同一个bind变量传递两次是很麻烦的(对于更复杂的查询,当需要六次或更多次时,更是如此) 当然,SQL允许在同一查询中多次使用同一绑定变量: PREPARE b AS SELECT * FROM users WHERE uid=$1 OR parent=$1; EXECUTE b(0); 但是许多DB API层不支持(或者不容易),因此使用这种方法更加麻烦 我可以通过针对子选择
PREPARE b AS SELECT *
FROM users
WHERE uid=$1
OR parent=$1;
EXECUTE b(0);
但是许多DB API层不支持(或者不容易),因此使用这种方法更加麻烦
我可以通过针对子选择添加连接来解决此问题,例如:
PREPARE c AS SELECT uids.*
FROM users
JOIN (SELECT $1::INT AS uid) AS x ON true
WHERE uids.uid=x.uid
OR uids.parent=x.uid;
EXECUTE c(0);
Explain表明,后一个选项具有最复杂的执行计划,但是,至少在本例中,它的执行速度始终比a快,而几乎不比b慢(尽管准备查询比其他两个选项中的任何一个都要长)
所以我的问题是:
对于更复杂的查询,这种连接/子选择构造被认为是好的还是坏的形式,以避免重复绑定变量?不是对您的问题的直接回答,但在这种特殊情况下,您应该能够像这样重写查询:
PREPARE b AS SELECT *
FROM users
WHERE $1 IN (uid, parent);
EXECUTE b(0);
事实上,这在这种情况下是可行的(在我真正关心的更复杂的情况下是行不通的:),但即使如此,如果我没有弄错的话(如果我的基本测试是准确的话),它也不会在
uid
和parent
列上使用索引。@Flimzy从逻辑上讲,它应该与uid=$1或parent=$1
相同,因此,它应该以同样的方式执行。话虽如此,也许您已经发现了ProsGreSQL查询优化器的一些特性?在任何情况下,我都建议测量真实的数据量——我不是PostgreSQL优化器方面的专家,但许多DBMS甚至在索引可用的情况下也会在小表上进行表扫描。事实上。。。我在一张大桌子上做了测试。但是,不幸的是,这不是唯一改变的变量,所以我不能确定我的测试是否有效。这是一个很好的策略来保持我的秘密。
PREPARE b AS SELECT *
FROM users
WHERE $1 IN (uid, parent);
EXECUTE b(0);