我几天前经过SQL优化后就想到了这一点。我认为我们可以同意,SQL是Wikipedia定义中的“声明性语言”:
表示计算逻辑而不描述其控制流程的编程范例
如果您认为完成了多少工作(查看统计信息,确定索引是否有用,进行嵌套,合并或哈希联接等),我们必须承认我们只给出了高级逻辑,数据库负责所有低层控制流逻辑。
同样在这种情况下,有时数据库优化器需要用户提供一些“提示”以提供最佳结果。
“声明性”语言的另一个常见定义是(我找不到权威来源):
表示不需要计算的步骤即可表达所需计算结果的编程范例(也缩写为“描述什么,而不是如何描述”)
如果我们接受此定义,则会遇到OP描述的问题。
第一个问题是SQL为我们提供了多种等效的方式来定义“相同的结果”。可能这是必不可少的邪恶:我们赋予一种语言更多的表达能力,就越有可能以不同的方式表达同一件事。
例如,曾经有人要求我优化此查询:
SELECT Distinct CT.cust_type, ct.cust_type_description
from customer c
INNER JOIN
Customer_type CT on c.cust_type=ct.cust_type;
由于类型比客户少很多,并且cust_type
客户表上有一个索引,因此我将其重写为:
SELECT CT.cust_type, ct.cust_type_description
from Customer_type CT
Where exists ( select 1 from customer c
Where c.cust_type=ct.cust_type);
在这种特定情况下,当我问开发人员他想达到什么目标时,他告诉我“我想要拥有至少一个客户的所有客户类型”,顺便说一句,正是可以描述优化程序查询的方式。
因此,如果我可以找到一个等效且更有效的查询,为什么优化器无法做到这一点?
我最好的猜测是,这主要有两个原因:
SQL表达逻辑:
由于SQL表示高级逻辑,我们是否真的希望优化器“使我们和我们的逻辑“精明”?如果不是一直要我迫使优化器选择最有效的执行路径,我会热情地喊“是”。我认为这个想法可能是为了让优化器尽力而为(也修改了我们的逻辑),但是当某些事情变得疯狂时,我们给了我们一个“提示机制”来进行救援(这就像在刹车时踩了刹车)自动驾驶汽车)。
更多选择=更多时间
甚至最好的RDBMS优化器也不会测试所有可能的执行路径,因为它们必须非常快:如果我需要每100ms选择一次最佳路径,将查询从100ms优化为10ms有多好?这就是优化程序尊重我们的“高级逻辑”的原因。如果它还应该测试所有等效的SQL查询,则优化器时间可能会增长多次。
查询重写no RDBMS实际能够执行的另一个很好的例子是(来自此有趣的博客文章)
SELECT t1.id, t1.value, SUM(t2.value)
FROM mytable t1
JOIN mytable t2
ON t2.id <= t1.id
GROUP BY t1.id, t1.value;
比可以这样写(需要分析功能)
SELECT id, value, SUM(t1.value) OVER (ORDER BY id)
FROM mytable
select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)
。看看如何用anexists
或a 重述它应该是微不足道的join
。