我是来自 Oracle SQL 背景的 Impala 新手。我的任务是从性能的角度改进现有的 SQL 脚本。现有脚本在 where 子句中包含以下内容
colA > 0 and colB - colA > 10
我相当确定第一部分
colA > 0
只是为了防止对第二部分进行评估。我之所以持此观点,是因为在运行此脚本的上下文中,无论是否为colB - colA > 10
,colA > 0
的评估都可以继续进行。很难在互联网上找到这些信息,chatGPT 的免费版本不确定所以我认为我们可以看一下源代码并尝试在这里找到一些东西
让我们从 sql-scanner(jflex 中的 Lexer)开始:sql-scanner.flex
public static void init(TReservedWordsVersion reservedWordsVersion) {
// initilize keywords
keywordMap = new LinkedHashMap<>();
keywordMap.put("&&", SqlParserSymbols.KW_AND);
keywordMap.put("add", SqlParserSymbols.KW_ADD);
keywordMap.put("aggregate", SqlParserSymbols.KW_AGGREGATE);
keywordMap.put("all", SqlParserSymbols.KW_ALL);
keywordMap.put("alter", SqlParserSymbols.KW_ALTER);
keywordMap.put("analytic", SqlParserSymbols.KW_ANALYTIC);
keywordMap.put("and", SqlParserSymbols.KW_AND);
这里可以看到在Impala中不能使用“&”,其次是“and”和“&&”解析为同一个关键字——KW_AND
这表明在 Impala 中只使用短路“and”,但让我们深入挖掘
在 sql 解析器中我发现了这个:sql-parser
compound_predicate ::=
expr:e1 KW_AND expr:e2
{: RESULT = new CompoundPredicate(CompoundPredicate.Operator.AND, e1, e2); :}
| expr:e1 KW_OR expr:e2
{: RESULT = new CompoundPredicate(CompoundPredicate.Operator.OR, e1, e2); :}
| KW_NOT expr:e
{: RESULT = new CompoundPredicate(CompoundPredicate.Operator.NOT, e, null); :}
| NOT expr:e
{: RESULT = new CompoundPredicate(CompoundPredicate.Operator.NOT, e, null); :}
;
这表明 KW_AND 及其操作数被转换为 CompoundPredicate(CompoundPredicate.Operator.AND, e1, e2)
在这个文件中我发现了这个:AndPredicate
// (<> && false) is false, (true && NULL) is NULL
BooleanVal AndPredicate::GetBooleanValInterpreted(
ScalarExprEvaluator* eval, const TupleRow* row) const {
DCHECK_EQ(children_.size(), 2);
BooleanVal val1 = children_[0]->GetBooleanVal(eval, row);
if (!val1.is_null && !val1.val) return BooleanVal(false); // short-circuit
BooleanVal val2 = children_[1]->GetBooleanVal(eval, row);
if (!val2.is_null && !val2.val) return BooleanVal(false);
if (val1.is_null || val2.is_null) return BooleanVal::null();
return BooleanVal(true);
}
这可能证实它是短路的,但我认为你应该谨慎对待我的发现。
如果你想看到更多,你可以尝试挖掘北斗七星,我认为我的回答是一个很好的起点:)
SQL标准没有定义
AND
是否应该短路,它只定义了真值表。
这是有道理的。考虑这个例子:
where person.gender = 'male' and person.age > 50
对于短路,RDBMS 必须从左到右评估
AND
条件...程序员 type 代码的顺序。
这意味着 RDBMS 无法使用其关于数据的知识来找到更好的评估顺序(例如,当年龄列上有索引或年龄比性别更具选择性时)。如果 where 子句涉及多个表,那么程序员的决定就变得更加困难:
where order.date = '2023-05-12' and customer.city = 'seattle'
在没有短路的情况下,RDBMS 负责找到执行查询的最佳方法。