每个优秀的数据库/SQL开发人员都应该能够回答的问题

66

我正在阅读每个出色的.Net开发人员都应该能回答的问题,并对这个问题的内容和方法印象深刻,所以本着同样的精神,我提出了这个针对数据库/SQL开发人员的问题。

你认为一个好的数据库/SQL程序员应该能够回答哪些问题?

22个回答

31

不同类型的JOIN:

  • INNER JOIN(内部连接)
  • LEFT和RIGHT OUTER JOIN(左外连接和右外连接)
  • FULL JOIN(全连接)
  • CROSS JOIN(交叉连接)

请参阅Jeff Atwood的JOIN可视化解释

  • 什么是键?候选键?主键?备用键?外键?
  • 什么是索引,它如何帮助你的数据库?

  • 有哪些可用的数据类型,什么时候使用哪些?


8
如果你不彻底理解连接操作,那么你就不能成为一名数据库程序员。这将是第一个问题,如果答案错误,我就不会再问其他问题了。 - HLGEM
2
一般来说,理解集合论是成为优秀的SQL开发人员的先决条件。因此,我还会将并集和交集添加到您的列表中。 - Logicalmind
6
加入新的表格?这并不是一个好的方法,一个大而复杂的非规范化的单体表格就可以应对... :p - OMG Ponies
5
不要贬低集合论者——理解并使用并集和交集并不等同于“理解集合论”。 - klochner
2
在询问不同类型的连接时,不要要求面试者解释它们,而是提出一组需要面试者使用每个连接来解决的问题。许多“数据库开发人员”可以解释连接,但不能编写它们或知道何时应用它们。 - Samuel Neff
显示剩余3条评论

28

这是我在这里的答案再版,作为涵盖主题的通用指南。

基础知识


  1. 从表中选择列
  2. 聚合函数1: COUNT, SUM, MAX/MIN
  3. 聚合函数2: DISTINCT, GROUP BY, HAVING

中级


  1. JOIN: ANSI-89和ANSI-92语法
  2. UNION vs UNION ALL
  3. NULL处理: COALESCE 和本地NULL处理
  4. 子查询: IN, EXISTS, 和内联视图
  5. 子查询: 相关子查询
  6. WITH语法: 子查询分解/CTE
  7. 视图

高级主题


  • 函数, 存储过程, 包
  • 数据透视: CASE & PIVOT 语法
  • 分层查询
  • 游标: 隐式和显式
  • 触发器
  • 动态SQL
  • 物化视图
  • 查询优化: 索引
  • 查询优化: 执行计划
  • 查询优化: 分析
  • 数据建模: 标准化, 1到3
  • 数据建模: 主键 & 外键
  • 数据建模: 表约束
  • 数据建模: 关联表
  • 全文搜索
  • XML
  • 隔离级别
  • 实体关系图(ERDs),逻辑和物理模型
  • 事务处理:提交(COMMIT)、回滚(ROLLBACK)、错误处理

  • 6
    就我个人而言,我认为“高级”项中的几个应该放在“中级”或者“熟练”的范畴里。例如规范化、分区、查询/索引提示、复制、锁定和死锁等所有我们不愿意面对的复杂内容。不过,这是一份很好的清单! - Aaronaught
    @Aaronaught:分区和复制更偏向于数据库管理员。我在隔离级别方面进行了一定的涵盖,涉及到了锁定问题。 - OMG Ponies
    胡说八道。我不相信标签;无论你是否接受这个头衔,你都是一个数据库管理员。 ;) - Aaronaught
    4
    如果我有权限的话,我就是一名数据库管理员(DBA):p - OMG Ponies
    4
    基本上,我会把交易放在首要位置——如果你不知道该怎么做,那么保存的任何数据都是不可信的。 - mmmmmm
    不幸的是,每个人都认为隔离级别是一个高级话题,但它是基础,每个在处理具有并发访问的数据库的人都应该熟悉它。当然,提交回滚也是如此。 - René Nyffenegger

    12

    以下是几个问题:

    • 什么是规范化,为什么它很重要?
    • 在哪些情况下需要对数据进行反规范化处理?
    • 什么是事务,为什么它很重要?
    • 什么是参照完整性,为什么它很重要?
    • 当报告数据库性能较慢时,应该采取哪些步骤进行调查?

    8

    什么是SQL注入,如何预防?

    什么是光标,何时使用它(或不使用),为什么?


    8
    我发布了这个答案,是因为Erwin Smout发布了一个答案,他的回答非常错误,这表明可能需要特别防范它。
    Erwin建议:
    “为什么每个SELECT语句总是包含DISTINCT?”
    更合适的问题是:如果有人声称:“每个SELECT语句总是包含DISTINCT”,你会如何评论这个声明?
    如果候选人无法驳斥这个声明,则说明他们:
    · 不理解该声明的问题。
    · 缺乏批判性思维能力。
    · 缺乏传达技术问题的能力。
    记录如下:
    1. 假设您的查询正确,且不返回任何重复项,则包括DISTINCT只会强制RDBMS检查您的结果(零效益和大量额外处理)。
    2. 假设您的查询不正确,并且返回重复项,则包括DISTINCT仅会隐藏问题(同样需要进行额外处理)。最好发现问题并修复您的查询...这将使其运行更快。

    他们可能已经阅读了C.J.Dates的《深入数据库》,他主张默认使用DISTINCT。(请参见books.google.com第52页。) - schlenk
    我今天也在想同样的事情...+1 - Shawn

    5

    我会提供一些糟糕的查询语句,并询问他们如何进行性能调优。

    我会询问关于集合论的问题。如果你不理解集合操作,就无法有效地查询关系型数据库。

    我会给他们一些游标示例,并询问他们如何重写这些示例以使它们基于集合。

    如果工作涉及导入和导出,我会询问有关SSIS(或其他用于执行此操作的工具)的问题。如果涉及编写报告,我希望知道他们是否理解聚合和分组(以及使用的任何报告工具,如Crystal Reports或SSRS)。

    我会询问以下三个查询之间结果的区别:

    select  a.field1
            , a.field2
            , b.field3
    from table1 a
    join table2 b
        on a.id = b.id
    where a.field5 = 'test'
        and b.field3 = 1
    
    select  a.field1
            , a.field2
            , b.field3
    from table1 a
    left join table2 b
        on a.id = b.id
    where a.field5 = 'test'
        and b.field3 = 1
    
    select  a.field1
            , a.field2
            , b.field3
    from table1 a
    left join table2 b
        on a.id = b.id and b.field3 = 1
    where a.field5 = 'test'
    

    我承认我的错误:最后两者有什么区别?我认为它们实际上是一样的。 - Decent Dabbler
    最后两个将返回不同的结果,前两个将返回相同的结果。在where子句中对表b设置条件会将其转换为内连接,因为整个结果集必须满足该条件,如果表b中没有匹配记录,则无法满足条件(除非该条件类似于where b.id is null)。我无法告诉你我有多少次不得不修复这种代码(事实上,就在今天早上)。 - HLGEM
    2
    我可以告诉你它们的共同点:它们都有奇怪的逗号放置方式(我理解其中的原因,但需要一点时间来适应)。 - devuxer

    5

    在我们公司,我们不会问很多任何一个记忆好的人都能回答的SQL问题,而是创建了一个SQL开发者测试。该测试旨在让候选人设计一个具有规范化和RI考虑因素、检查约束等的可靠模式,并能够创建一些查询来生成我们所需的结果集。他们根据我们给他们的简要设计规范来完成所有这些工作。他们被允许在家里完成这项任务,并在合理范围内需要多少时间就可以用多少时间。


    5

    聚集索引和非聚集索引有什么区别?

    另一个我想问的问题不针对特定服务器:

    死锁是什么?


    4
    据我所知,该术语仅适用于MySQL和SQL Server。 - OMG Ponies
    1
    太对了。这是特定于数据库的。其他数据库也有相同的功能。Oracle有索引组织表,与聚集索引相同。不仅如此,在包括表中每个列的非聚集索引和聚集索引之间几乎没有区别。我认为问题的真正重点在于看这个人是否了解索引类型的不同物理存储特性。 - Logicalmind
    @Mark Canlas:Oracle不区分,它们都是“索引”-没有聚集/非聚集。如果该列没有索引,则自动为主键创建索引。 - OMG Ponies
    @Mike Woodhouse: 我了解SQL Server是基于Sybase的,但仍然只有三个数据库产品使用这个术语。仅仅说它并不适用于所有情况。 - OMG Ponies
    3
    趣闻:包括语法和术语在内的索引整个概念,在SQL标准中并未具体规定!这是一项实现细节。厂商之间的相似性如此之高,实属令人惊讶。 - Bill Karwin
    显示剩余2条评论

    4

    不要使用的原因及原因:

    SELECT *
    

    1
    我经常这样做。这样可以节省打字时间,而且我不必记住列名。这有什么问题吗? - gary
    3
    @Gary: 风险是返回不必要的数据,隐藏列名更改错误... - OMG Ponies
    4
    @gary,不应在生产代码中使用,因为如果基础数据结构发生更改,它将破坏您的查询。话虽如此,我和其他开发人员一样有时会这样做,但仅当我知道系统完全受我的控制时。 - Cruachan
    1
    如果您有文本/ blob 列并返回多行,则会对系统造成不必要的负担。 - Disillusioned
    4
    除非您维护包括每个列的大型索引,否则“SELECT *”将阻止使用覆盖索引进行有效的索引操作。这是最重要的原因! - Aaronaught
    在 exists 子句中使用 select * 是完全有效的。一些开发人员在这种情况下使用 select 1,但是关系型数据库管理系统将同样进行优化。因此,select 1 是一种初步(且错误)的优化方式。 - Jordão

    3
    一个有趣的问题涉及到关系除法,或者如何表达“对于所有”的关系,这需要嵌套not exists子句。
    这个问题直接来自这个链接
    给定以下表示可以飞行飞机和存放在机库中的飞机的飞行员表:
    create table PilotSkills (
      pilot_name char(15) not null,
      plane_name char(15) not null
    )
    
    create table Hangar (
      plane_name char(15) not null
    )
    

    选择能够驾驶机库中每架飞机的飞行员姓名。

    答案:

    select distinct pilot_name
    from PilotSkills as ps1 
    where not exists (
      select * from hangar
      where not exists (
        select * from PilotSkills as ps2 where 
          ps1.pilot_name = ps2.pilot_name and 
          ps2.plane_name = hangar.plane_name
      )
    )
    

    或者...

    选择所有在标记为最受欢迎的10种编程语言的问题中接受了答案的堆栈溢出用户。

    (假设有一个Accepted_Answers视图和一个包含所需标签的Target_Language_Tags表的可能)答案是:

    select distinct u.user_name
    from Users as u
    join Accepted_Answers as a1 on u.user_id = a1.user_id
    where not exists (
      select * from Target_Language_Tags t
      where not exists (
        select * 
          from Accepted_Answers as a2
          join Questions as q on a2.question_id = q.question_id
          join Question_Tags as qt on qt.question_id = q.question_id 
        where 
          qt.tag_name = t.tag_name and
          a1.user_id = a2.user_id
      )
    )
    

    这绝对是一个有趣的问题。然而,我怀疑有多少公司需要他们的开发人员每天处理这样的情况。 - Disillusioned
    1
    很好,但我认为回答这个问题展示了相当多的逻辑推理能力,这对于一个优秀的数据库开发人员来说是必不可少的。 - Jordão

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接