代码之家  ›  专栏  ›  技术社区  ›  Patrick Harrington

为什么SQL ANSI-92标准不能比ANSI-89更好地被采用?

  •  99
  • Patrick Harrington  · 技术社区  · 16 年前

    在我工作过的每一家公司,我都发现人们仍在按照ANSI-89标准编写SQL查询:

    select a.id, b.id, b.address_1
    from person a, address b
    where a.id = b.id
    

    而不是ANSI-92标准:

    select a.id, b.id, b.address_1
    from person a
    inner join address b
    on a.id = b.id
    

    对于这样一个非常简单的查询,可读性没有很大的区别,但是对于大型查询,我发现将连接条件与表中的列表组合在一起可以更容易地看到我在连接中可能遇到的问题,并让我将所有筛选保留在WHERE子句中。更不用说,我觉得外部连接比Oracle中的(+)语法更直观。

    当我试图向人们宣传ANSI-92时,使用ANSI-92比使用ANSI-89有什么具体的性能优势吗?我会自己尝试,但我们这里的甲骨文设置不允许我们使用解释计划-不希望人们尝试优化他们的代码,是吗?

    16 回复  |  直到 7 年前
        1
  •  70
  •   Bill Karwin    11 年前

    根据Peter Gulutzan和Trudy Pelzer的“SQL性能调整”,在他们测试的六个或八个RDBMS品牌中,SQL-89和SQL-92连接在优化或性能上没有区别。可以假定大多数RDBMS引擎在优化或执行查询之前将语法转换为内部表示,因此人类可读的语法没有区别。

    我还尝试传播SQL-92语法。16年后,它被批准,是时候人们开始使用它了!所有品牌的SQL数据库现在都支持它,所以没有理由继续使用讨厌的 (+) Oracle语法或 *= Microsoft/Sybase语法。

    至于为什么很难打破SQL-89开发人员的习惯,我只能假设有一个很大的“金字塔基础”,即程序员通过复制和粘贴、使用书籍、杂志文章或其他代码库中的古老示例进行编码,而这些人并没有抽象地学习新的语法。有些人模式匹配,有些人死记硬背。

    不过,我逐渐看到人们使用SQL-92语法的频率比我以前更高。我从1994年开始就在网上回答SQL问题。

        2
  •  15
  •   Community Jaime Torres    7 年前

    嗯,ansi092标准包括一些非常糟糕的语法。 Natural Joins 是一个,而using子句是另一个。imho,向表中添加一列不应该破坏代码,而是以一种最令人震惊的方式破坏自然连接。最好的打破方法是通过编译错误。例如,如果选择*某处,则添加一列 能够 编译失败。下一个失败的最佳方法是运行时错误。更糟糕的是,你的用户可能会看到它,但它仍然给你一个很好的警告,你已经打破了一些东西。如果使用ansi92并使用自然联接编写查询,那么它不会在编译时中断,也不会在运行时中断,查询只会突然开始产生错误的结果。这些类型的虫子是阴险的。报告出错,可能的财务披露不正确。

    对于那些不熟悉自然连接的人。它们对两个表中存在的每个列名联接两个表。当你有一个4列的键并且你厌倦了输入它的时候,这真的很酷。当table1有一个名为description的已有列,并且在table2中添加了一个名为,噢,我不知道,类似于mmm,description之类的无害列时,问题就出现了,现在您要在一个自由格式的varchar2(1000)字段中加入这两个表。

    除上述问题外,using子句还可能导致完全的歧义。在另一个 SO post ,有人显示了这个ANSI-92 SQL并请求帮助阅读它。

    SELECT c.* 
    FROM companies AS c 
    JOIN users AS u USING(companyid) 
    JOIN jobs AS j USING(userid) 
    JOIN useraccounts AS us USING(userid) 
    WHERE j.jobid = 123
    

    这完全是模棱两可的。我在公司和用户表中都放置了一个userid列,没有任何抱怨。如果公司中的userid列是最后一个修改该行的人的id呢?

    我是认真的,有人能解释为什么这种含糊不清是必要的吗?为什么要直接纳入标准?

    我认为比尔是正确的,有大量的开发人员通过编码复制/粘贴到那里。事实上,当涉及到ANSI-92时,我可以承认我是那种人。我见过的每个示例都显示了多个连接嵌套在括号中。诚实,这使得在SQL中挑选表充其量是困难的。但后来一个sql92的福音主义者解释说,这实际上会强制执行一个连接命令。JESUS…我看到的所有那些复制粘贴程序现在实际上都在强制执行一个连接顺序——这项工作最好留给优化器95%的时间。 尤其地 复制品/贴纸

    托马拉克说的没错,

    人们不会转换到新的语法 因为它在那里

    它必须给我一些东西,我看不出有什么好处。如果有好处的话,消极的一面就是一个太大而不可忽视的信天翁。

        3
  •  14
  •   Tomalak    16 年前

    我想到了几个原因:

    • 人们是出于习惯才这么做的
    • 人们懒惰,喜欢“老式”的连接,因为他们不需要打字。
    • 初学者经常在使用SQL-92连接语法时遇到问题。
    • 人们不会仅仅因为新语法的存在就转向新语法。
    • 人们不知道新语法(如果您想这样称呼它)的好处,主要是它使您能够筛选表 之前 你做一个外部连接,而不是在它之后,当你所拥有的只是WHERE子句时。

    对于我来说,我使用SQL-92语法来完成所有的连接,并尽可能地转换代码。这是一种更清洁、更可读、更强大的方法。但是很难说服别人使用这种新样式,因为他们认为这样做会在不改变查询结果的情况下影响他们的输入工作。

        4
  •  10
  •   Roger Bold    15 年前

    响应上述自然连接和使用post。

    为什么你会看到使用这些的必要性——它们在ANSI-89中不可用,并且在ANSI-92中被添加为我只能看到的快捷方式。

    我永远不会离开Join to Chance,并且总是指定表/别名和ID。

    对我来说,唯一的方法就是ANSI-92。它更加冗长,并且语法不受ansi-89追随者的喜爱,但是它将您的连接与您的过滤巧妙地分离开来。

        5
  •  5
  •   HLGEM    16 年前

    首先,我要说的是,在SQL Server中,外部联接语法(==)始终不能给出正确的结果。有时它将其解释为交叉联接而不是外部联接。所以现在有一个很好的理由停止使用它。而且,外部联接语法是一个不推荐使用的功能,在SQL Server 2008之后的下一个SQL Server版本中将不会出现。你仍然可以做内在的连接,但是为什么在地球上会有人想要呢?它们不清楚,维护起来困难得多。您不容易知道什么是联接的一部分,什么才是WHERE子句。

    我认为您不应该使用旧语法的一个原因是,了解联接以及它们的作用和不作用对于任何编写SQL代码的人来说都是至关重要的一步。如果不彻底理解联接,就不应该编写任何SQL代码。如果您很好地理解它们,您可能会得出这样的结论:ansi-92语法更清晰,更容易维护。我从来没有遇到过一个SQL专家,他在使用旧语法之前没有使用过ANSI-92语法。

    我遇到或处理过的大多数使用旧代码的人,确实不理解连接,因此在查询数据库时会遇到麻烦。这是我的个人经历,所以我不是说这总是真的。但作为一名数据专家,多年来我不得不修复太多的垃圾,以至于不敢相信。

        6
  •  4
  •   Scot McDermid    12 年前

    我在学校教过ANSI-89,在工业界工作了几年。然后我离开了DBMS这个神奇的世界8年。但后来我回来了,这个新的ANSI 92的东西正在教。我已经学习了连接语法,现在我实际教授SQL,并推荐新的连接语法。

    但是,我看到的缺点是相关的子查询在考虑到ANSI92连接时似乎没有意义。当连接信息包含在where和相关子查询中时,在where中“joined”所有的查询看起来都是正确和一致的。在ansi 92中,表联接条件不在where中,子查询“join”是,语法似乎不一致。另一方面,试图“修复”这种不一致可能只会使情况变得更糟。

        7
  •  2
  •   Charles Bretana    16 年前

    我不知道答案。这是一场重新开始的战争(比Mac PC或其他计算机的程度要低)

    一种猜测是,直到最近,Oracle(可能还有其他供应商)才采用了ANSI-92标准(我认为它是在Oracle V9中,或是其他版本),因此,对于仍在使用这些版本的公司中工作的DBA/DB开发人员(或者希望代码可以在可能使用这些版本的服务器上移植),他们必须按旧标准…

    真的很遗憾,因为新的连接语法可读性更高,而旧的语法会在多个文档化的场景中生成错误(不正确)的结果。

    • 具体来说,外部连接 是条件筛选谓词 在与联接无关的列上 表位于 加入。
        8
  •  2
  •   JPLemme    16 年前

    惯性和实用性。

    ANSI-92 SQL就像触摸输入。从理论上讲,有一天它可能会使一切变得更好,但现在我可以用四个手指更快地打字了。我需要向后走才能向前走,不能保证会有回报。

    写SQL大约占我工作的10%。如果我需要ansi-92sql来解决ansi-89sql无法解决的问题,那么我将使用它。(事实上,我在Access中使用它。)如果一直使用它可以帮助我更快地解决现有的问题,我会花时间来吸收它。但是,我可以在不考虑语法的情况下快速生成ansi-89sql。我得到报酬来解决问题——思考SQL语法是在浪费我的时间和我雇主的钱。

    总有一天,年轻的蚱蜢,你会为你使用ansi-92 SQL语法的行为辩护,反对年轻人抱怨你应该使用sql3(或其他任何东西)。然后你就会明白了。-)

        9
  •  2
  •   Community Jaime Torres    7 年前

    我有一个最初为SQL Server 6.5编写的查询,它不支持SQL 92联接语法,即。

    select foo.baz
    from foo
      left outer join bar
      on foo.a = bar.a
    

    而是写为

    select foo.baz
    from foo, bar
    where foo.a *= bar.a
    

    查询已经存在一段时间了,相关数据的积累使查询运行得太慢,大约需要90秒才能完成。当这个问题出现时,我们已经升级到了SQL Server 7。

    在对索引和其他复活节教育进行了大量研究之后,我将连接语法改为符合SQL 92。查询时间下降到3秒。

    有一个很好的理由可以改变。

    转载自 here .

        10
  •  1
  •   PhiLho    16 年前

    我可以从一个普通的开发人员的角度来回答,我只知道足够多的SQL来理解这两种语法,但是每次我需要插入时,我仍然会在谷歌上搜索插入的确切语法…:-p(我不整天做SQL,只是不时地解决一些问题。)

    实际上,我发现第一种形式更直观,在两个表之间没有明显的层次结构。事实上,我用可能是旧书的方式学习了SQL,展示了第一种形式,可能没有帮助…;-)
    我发现的第一个参考文献 数据源 在Google中搜索(它主要为我返回法语答案…)首先显示旧的表单(然后解释第二个表单)。

    只是对“为什么”问题给出一些提示…^^我应该读一本关于这个主题的现代好书。如果有人有建议…

        11
  •  1
  •   BenAlabaster    16 年前

    我不能代表所有的学校说话,但是在我的大学里,当我们做课程的SQL模块时,他们没有教ANSI-92,他们教ANSI-89——关于一个旧的VAX系统!直到我开始在Access中挖掘,使用查询设计器构建了一些查询,然后挖掘SQL代码,我才接触到ANSI-92。意识到我不知道它是如何完成连接的,或者语法的含义,我开始深入挖掘,以便能够理解它。

    考虑到现有的文档在很多情况下并不完全直观,而且人们倾向于坚持他们所知道的,而且在许多情况下,为了完成他们的工作,他们不努力学习超过他们所需要的任何东西,很容易理解为什么采用这些文档需要这么长时间。

    当然,也有一些技术福音主义者喜欢修补和理解,而且往往是那些采用“更新”原则并试图改变其他原则的类型。

    奇怪的是,在我看来,很多程序员从学校毕业后就不再进步了;他们认为因为这就是他们所学的,所以这就是他们所做的。直到你摘下你的眼罩,你才意识到学校只是为了教你基础知识,给你足够的理解,让你自己学习其余的东西,实际上你几乎没有触及到要知道的东西的表面;现在你的工作就是继续走这条路。

    当然,这只是我根据自己的经验提出的意见。

        12
  •  1
  •   magallanes    10 年前

    1)编写外部联接的标准方法,而不是*=或(+)=

    2)自然连接

    3)在数据库引擎中,ANSI-92趋向于更为优化。

    4)手动优化:

    假设我们有下一个语法(ansi-89):

    (1)select * from TABLE_OFFICES to,BIG_TABLE_USERS btu
    where to.iduser=tbu.iduser and to.idoffice=1
    

    它可以写为:

    (2)select * from TABLE_OFFICES to
    inner join BIG_TABLE_USERS btu on to.iduser=tbu.iduser
    where to.idoffice=1
    

    而且:

    (3)select * from TABLE_OFFICES to
    inner join BIG_TABLE_USERS btu on to.iduser=tbu.iduser and to.idoffice=1
    

    它们(1)、(2)、(3)都返回相同的结果,但是它们的优化方式不同,这取决于数据库引擎,但大多数都会:

    • (1)由数据库引擎决定优化。
    • (2)它连接两个表,然后对每个办公室进行筛选。
    • (3)它使用IDoffice过滤大表用户,然后加入两个表。

    5)查询时间越长,就越不混乱。

        13
  •  1
  •   hol    8 年前

    人们使用ANSI-89的原因来自于我对年轻老程序员、受训人员和应届毕业生的实践经验:

    • 他们从现有的代码(而不是书本)中学习SQL,从代码中学习ANSI-89。
    • ANSI-89因为打字比较少
    • 他们不考虑这个问题,使用一种或其他风格,甚至不知道这两者中的哪一种被认为是新的或旧的,也不在乎
    • 代码也是与下一个程序员进行通信的想法是不存在的。他们认为他们和电脑交谈,而电脑不在乎。
    • “干净编码”的艺术是未知的。
    • 特别是编程语言和SQL的知识太差,以致于他们把在别处找到的东西复制粘贴在一起。
    • 个人偏好

    我个人更喜欢使用ansi-92,有时更改我在ansi-89语法中看到的每个查询,只是为了更好地理解手头上的SQL语句。但我意识到,与我一起工作的大多数人都不够熟练,无法在许多表上编写连接。它们尽可能好地编码,并使用它们第一次遇到SQL语句时记忆的内容。

        14
  •  0
  •   Jonathan    16 年前

    Oracle根本没有很好地实现ANSI-92。我遇到了几个问题,尤其是因为Oracle应用程序中的数据表中有很多列。如果连接中的列数超过了1050列(这在应用程序中很容易实现),那么您将得到一个完全没有逻辑意义的错误:

    ORA-01445: cannot select ROWID from a join view without a key-preserved table.
    

    重新编写查询以使用老式的连接语法会使问题消失,这似乎直接指向了ansi-92连接的实现。

    在我遇到这个问题之前,我一直是ASNI-92的坚定支持者,因为这样做的好处是减少了意外交叉连接的机会,而这对于老式语法来说太容易了。

    然而,现在,我发现坚持下去要困难得多。他们指出Oracle的糟糕实现,并说“我们会按自己的方式来做,谢谢。”

        15
  •  0
  •   Evan Carroll    7 年前

    下面是比较SQL-89和SQL-92的几点,并清除其他答案中的一些误解。

    1. NATURAL JOINS 是个可怕的主意。它们是隐式的,需要表的元信息。SQL-92的任何功能都不需要这么简单地使用它们 忽略它们 . 他们与这次讨论无关。
    2. USING 是个好主意,它有两种效果:
      1. 它只从equijoin在结果集中生成一列。
      2. 它执行一个健全的、健全的惯例。在SQL-89中,有人在编写列 id 在两张桌子上。在联接表之后,这将变得模糊,并且需要显式的别名。此外, 几乎可以肯定的是,连接上的s具有不同的数据。如果你和某人一起去公司,现在你必须给他取一个别名。 身份证件 person_id 和其中一个 身份证件 company_id ,否则联接将生成两个不明确的列。使用表的代理键的全局唯一标识符是标准奖励的惯例 使用 .
    3. SQL-89语法是隐式的 CROSS JOIN . 一 交叉连接 不减少集合,它隐式地增加集合。 FROM T1,T2 是一样的 FROM T1 CROSS JOIN T2 ,这会产生一个笛卡尔连接,而这通常不是您想要的。有选择性地将其减少到远处 WHERE 条件意味着在设计过程中你更容易出错。
    4. QL—899 , 和SQL-92显式 JOIN S具有不同的优先级。 加入 具有更高的优先级。更糟的是, some databases like MySQL got this wrong for a very long time. . 因此,混合这两种样式是一个坏主意,而现在更流行的样式是SQL-92样式。
        16
  •  0
  •   onedaywhen    7 年前

    一个新的SQL标准继承了以前的标准,也就是“兼容性的枷锁”。所以“old”/“comma-separated”/“unqualified”联接样式是完全有效的SQL-92 Sytax。

    现在,我认为SQL-92 NATURAL JOIN 是你唯一需要的加入。例如,我认为它优于 inner join 因为它不会生成重复的列-在 SELECT 要消除列歧义的子句!但是我不能期望改变每个人的心意,所以我需要与编码人员合作,他们将继续采用我个人认为是遗留连接样式的方式(他们甚至可能将范围变量称为“别名”!)这是团队合作的本质,而不是在真空中操作。

    对SQL语言的批评之一是,使用一些语义等价的语法(一些使用关系代数,一些使用关系演算),可以获得相同的结果,在这些语法中,选择“最好的”一个简单地归结为个人风格。所以我对“老风格”的加入和我现在一样感到舒服 INNER . 我是否会花时间把它们改写为 NATURAL 取决于上下文。

    推荐文章