SQL是声明性的吗?


22

我之所以问,是因为我在SQL中看到的许多问题总计为:“这很慢。如何加快速度”?还是教程说明“以这种方式而不是以这种方式这样做,因为它更快”。

在我看来,SQL的很大一部分是知道如何执行表达式,并从中选择性能更好的表达式样式。这与声明性编程的一个方面不符-只是让系统决定要如何最好地执行计算,而只需指定计算应产生的内容。

SQL引擎不应该不在乎您是否使用过它inexists或者join它是否确实是声明性的,是否应该仅在合理的时间内通过三种方法中的任何一种为您提供正确的答案?最近的帖子提示了最后一个示例,该帖子是我在开始段落中提到的类型。

指标

我想我可以使用的最简单的示例涉及为表创建索引。w3schools.com上的 “ gumph” 甚至试图将其解释为用户出于性能原因看不到的某种东西。它们的描述似乎将SQL索引置于非声明式阵营中,并且出于纯性能的原因,通常将它们手工添加。

是不是他们的某个地方是理想的SQL DB,它比其余所有声明性都强得多,但是因为那是一个好人却没有听说的SQL DB?


@FrustratedWithFormsDesigner:我确切地知道那是什么意思。 select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)。看看如何用an exists或a 重述它应该是微不足道的join
梅森·惠勒2013年

使用类似的推理,我猜想正则表达式是一种更具说明性的表达方法,因为我很少看到性能问题回答“您应该以这种方式编写以获得更好的性能”。我动了脑筋,几乎能记住一些与慢速正则表达式中的负向后或向前断言有关的问题,答案是用另一种方式重写正则表达式,以在更短的时间内完成相同的事情。
Paddy3118 2013年

性能是实现细节。如果查询处理器开发人员认为这是当务之急,那么几乎任何IN实现的性能都可以与EXISTS和JOIN相媲美或更好。
JustinC 2013年

1
@JustinC,考虑到性能导向的SQL问题和所谓的声明性语言的提示,这似乎不仅仅是一个细节。
Paddy3118 2013年

声明性编程语言没有明确的定义,因此谈论毫无意义。有些语言比其他语言更高级。
gardenhead '16

Answers:


21

SQL在理论上是声明性的。但是您知道他们对理论与实践之间的区别怎么说...

从本质上讲,“声明式编程”的概念从来没有真正有效,在拥有基于AI的编译器能够查看代码并回答“此代码的意图是什么”这一问题之前,它可能永远不会有效。聪明地,就像编写它的人一样。每种声明性语言的核心是一大堆命令式代码,它们在没有AI的帮助下疯狂地试图解决该问题。

通常,它的效果出奇地好,因为最常见的情况是常见情况,编写该语言实现的人员知道并找到了很好的处理方法。但是随后您遇到了实现者未考虑的极端情况,并且看到了性能迅速下降,因为解释器被迫采用更多字面意义的代码并以效率较低的方式对其进行处理。


3
从来没有真正有效吗?SQL,LINQ,Knockout.js,Prolog和ELM语言。您可能要再次检查。目前,我主要使用声明性技术。
brian 2013年

5
@brian:当您遇到一个没人想到的边缘情况时,它们都很快退化。我想我应该说“ 在一般情况下永远不会真正有效”。
梅森惠勒

您的回复何时设置为降级,因为它如何存储在SQL Server数据库中?:)我很少碰到任何在框架内无法解决的极端情况。我知道您来自哪里,但是对于99%的声明式代码多么有益和容易理解,这些极端的案例并没有给我带来太多痛苦。这就像说Clojure或F#不好一样,因为您必须使用可变类型来解决问题。
brian 2013年

11
@brian:I rarely hit an edge case in any of them that couldn't be solved within the framework.是的,这就是重点:必须找出一种在框架内解决它们的方法,因为该框架不够聪明,无法以您最初声明的方式为您解决。
梅森惠勒2013年

那么选择...进行更新呢?这似乎是当务之急。
Jesvin Jose

6

我几天前经过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

1
重写存在联接的示例很有趣。我试图给SQL开发人员留下深刻印象的一条经验法则是,使用DISTINCT会产生代码异味-查询或数据模型很可能是错误的,应寻求另一种方法。
David Aldridge
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.