你最常用的数据库标准是什么?

44

我有一些想法,这些想法是我随着时间积累下来的,但我真的想知道在建模数据库时让您感到顺畅的原因:

  1. 表名与主键名称和描述键匹配
  2. 按功能区划分模式
  3. 尽可能避免使用组合主键(使用唯一约束)
  4. 驼峰式命名表名和字段名
  5. 不要为表添加tbl_前缀,也不要为过程添加SP_前缀(不使用匈牙利标记法)
  6. OLTP数据库应至少符合BCNF / 4NF​​。

1
尽可能避免使用复合主键,你会为此付出多大的努力?我不会付出太多。另外,“使用唯一索引”——你是指“唯一约束”吗(提示:并非所有 SQL 产品都使用索引),还是你有特定的产品想法? - onedaywhen
4
由于我的回答被人们投反对票,我很快就会删除它,所以我会把这个放在评论里。 "规范化" 是您可以采用的最佳标准之一。 - Lance Roberts
@Tapoi:为什么不做第五个?我不是说这样做是错的,只是想知道(躲起来,因为我们公司是这样做的)。 - Kieran Senior
3
根据我的经验,经常使用复合主键会让你陷入一个情况,即两个表之间进行八次键连接,深度达到四级。如果不使用代码生成器编写SQL,这样的表会很烦琐。我建议使用唯一约束。 - Raj More
5
标准的好处在于有很多可以选择的! - araqnid
显示剩余5条评论
30个回答

19
  • 为具有相同前缀的存储过程取类似的名称,例如,如果您有3个与Person相关的存储过程,则将它们全部分组在一起,这样您就可以轻松查找到它们,而不必浏览所有存储过程来查找它们。
    • PersonUpdate(人员更新)
    • PersonDelete(人员删除)
    • PersonCreate(人员创建)
  • 当您拥有与相关数据相关的表组时,请执行类似的操作。例如:
    • InvoiceHeaders(发票标头)
    • InvoiceLines(发票行)
    • InvoiceLineDetails(发票行详细信息)
  • 如果您的数据库中有模式选项,则使用它们。这样更好看:
    • Invoice.Header(发票标头)
    • Invoice.Line.Items(发票行项目)
    • Invoice.Line.Item.Details(发票行项目详情)
    • Person.Update(人员更新)
    • Person.Delete(人员删除)
    • Person.Create(人员创建)
  • 除非没有其他合理的方法来实现该目标,否则不要使用触发器。
  • 给字段名称加上有意义的前缀,这样您可以知道它们来自哪个表,而不需要其他人进行解释。这样,当您看到引用字段名称时,就可以轻松地知道它来自哪个表。
  • 对于包含类似数据的字段,请使用一致的数据类型,例如不要将电话号码在一个表中存储为数值,而在另一个表中存储为varchar。实际上,不要将其存储为数值,如果我遇到负电话号码,我会很生气。
  • 不要在表/字段名称中使用空格或其他模糊字符。它们应该完全由字母数字组成 - 或者如果我按照自己的意愿,完全由字母组成,除了下划线。我目前正在处理一个继承的系统,其中表和字段名称包含空格、问号和感叹号。让我每天都想杀死设计师!
  • 不要将语法关键字用作对象名称,这将导致从中检索数据时出现问题。我讨厌将对象名称包装为[index],这是我无需输入的两个无谓字符,见鬼!

@balabaster:我也这样做。这有助于保持事物的井然有序。往往情况下,你会有多个搜索函数,如PersonGetByPersonId、PersonGetByName、PersonGetByOderId、PersonGetByCity等等。在代码前缀中加入实体名称可以使其更加紧凑。 - Raj More
@balabaster:表名和列名中有问号和感叹号?我好久没见过了。我理解你的感受,伙计! - Raj More
打开数据库看到100个usp_Insert...存储过程,真是太棒了! - blu
为什么对触发器有负面评价? - leora
@oo 有很多原因:它们很难调试,会引起不必要的混乱,并且除非你知道它们存在并/或去寻找它们,否则它们会引起其他无法解释的副作用。因此,我只在它们应该使用的情况下使用它们,以防止未来开发人员/数据库管理员产生混淆的现象。并不是我特别不喜欢触发器,我只是意识到接替我的开发人员,我希望让他们的生活尽可能简单。 - BenAlabaster
我喜欢这些,尽管我不同意“给字段名称加上有意义的前缀”的标准。如果你有足够多的表格,那么前缀要么被缩写到无用,要么就太长了,每次输入列名时都会感到厌烦。查询将告诉您该列来自哪个表。或者,您可以在查询中放置一个列别名,以逐案处理此问题。 - Jeff Siver

13

还有一件事情我还没有看到提到:

永远不要使用数据库关键词作为对象名称。您不希望每次使用它们时都要进行限定。

如果你在创建时拼写错误,那么在注意到错误后立即纠正。不要花费多年时间去记住在这个表中,UserName实际上是Usernmae。在代码量不大的时候修改它会更加容易。

永远不要使用暗示连接(逗号语法),总是明确指定连接。


就像我们模式中的Branches.branchID一样...我已经习惯了这个,但在开始时给我带来了很大的头痛。该模式被两个非常不同的产品使用,因此重命名并不是一个真正的选项。但我同意你的看法。尽快修正拼写错误! - Peter Perháč
我认为我们仍然在其中一张表中有一个名为“care_hire_driver_id”的主键...几年过去了:o - araqnid
2
+1 对于隐式连接,我已经厌倦了修复那样的查询。 - SqlACID
1
老实说,我发现“隐式连接”更简单、更易于使用。你可以立即看到你从哪些表中进行选择,因为它们直接列在一起,例如“FROM table1, table2”。只要在where子句中首先指定连接字段,就没有问题,例如“WHERE table1.id=table2.table1id AND ...”。 - DisgruntledGoat
1
哦,还有要记得的是,与您的命名系统不同的表/字段名称(例如,“Users”表的复数,但“Message”表的单数)也算作拼写错误,并应尽快修复。 - DisgruntledGoat

11
将所有人的输入整合成一个列表。 命名规范
  • 按功能区域(产品、订单、运输等)命名模式
  • 不使用匈牙利命名法:对象名称中不包含类型名称(例如,不要使用strFirstName)
  • 不要在对象名称中使用已注册的关键字
  • 对象名称中不要有空格或任何特殊字符(只允许字母数字和下划线)
  • 以自然方式命名对象(例如,使用FirstName而不是NameFirst)
  • 表名应与主键名称和描述字段匹配(SalesType-SalesTypeId、SalesTypeDescription)
  • 不要以tbl_或sp_为前缀
  • 根据对象名称命名代码(例如,CustomerSearch、CustomerGetBalance)
  • 数据库对象名称使用驼峰命名法
  • 列名称应为单数形式
  • 表名可以是复数形式
  • 给所有约束命名业务名称(例如,MustEnterFirstName)
数据类型
  • 在各个表之间使用相同的变量类型(例如,邮政编码-在一个表中使用数字,在另一个表中使用varchar不是一个好主意)
  • 对于客户信息(姓名、地址等),使用nNVarChar类型,因为你永远不知道何时可能需要跨国界
在代码中
  • 关键字需大写
  • 不要使用隐式连接(逗号语法) - 总是使用明确的INNER JOIN / OUTER JOIN
  • 每行一个JOIN
  • 每行一个WHERE子句
  • 避免循环 - 使用基于集合的逻辑替换
  • 使用表名的简称作为别名,而不是A,B,C等
  • 除非没有其他选择,否则避免使用触发器
  • 避免使用游标(参见http://www.sqlservercentral.com/articles/T-SQL/66097/

文档

  • 创建数据库图表
  • 创建数据字典

规范化和引用完整性

  • 尽可能使用单列主键。在必要时使用唯一约束。
  • 始终强制执行引用完整性
  • 避免使用ON DELETE CASCADE
  • OLTP至少应为4NF
  • 将每个一对多关系视为潜在的多对多关系
  • 非用户生成的主键
  • 构建基于插入的模型而不是基于更新的模型
  • PK到FK必须是相同的名称(Employee.EmployeeId与EmployeeSalary.EmployeeId是相同的字段)
  • 除非存在双重连接(Person.PersonId连接到PersonRelation.PersonId_Parent和PersonRelation.PersonId_Child),否则不要这样做

维护:运行定期脚本以查找

  • 没有表的架构
  • 孤立的记录
  • 没有主键的表
  • 没有索引的表
  • 非确定性UDF
  • 备份,备份,备份

做好以下几点:

  • 保持一致性
  • 立即修复错误
  • 阅读Joe Celko的SQL编程风格(ISBN 978-0120887972)

10

我对 Oracle 的标准如下:

  • 关键字始终为大写;
  • 数据库对象名称始终为小写;
  • 使用下划线代替空格(即不会使用 SQL Server 上常见的驼峰命名惯例);
  • 主键通常都被命名为“id”;
  • 强制执行引用完整性;
  • 整数值(包括表 id)通常都是 NUMBER(19,0)。这是因为这样可以适应 64 位有符号整数,从而允许使用 Java 的 long 类型,而无需使用更为繁琐的 BigInteger;
  • 尽管将“_number”附加到某些列名中是错误的,但此类列的类型将为 VARCHAR2 而非数字类型。数字类型仅保留用于主键和进行算术运算的列;
  • 我总是使用技术主键;
  • 每个表都将拥有自己的序列以用于生成键。该序列的名称将为“_seq”。

在 SQL Server 中,唯一的修改是对于数据库对象名称使用驼峰命名(例如 PartyName 而非 party_name)。

查询通常会按多行编写,每行只包含一个子句或条件:

SELECT field1, field2, field2
FROM tablename t1
JOIN tablename2 t2 ON t1.id = t2.tablename_id
WHERE t1.field1 = 'blah'
AND t2.field2 = 'foo'

如果SELECT子句够长,我会把每个字段拆成一行。


几乎完全使用Oracle,我必须在每个方面都同意您的观点。然而,相对于输入许多下划线,我发现使用驼峰命名法更加友好。我们有一个第三方系统,在其模式中有大约200个表,他们选择不使用下划线。例如,PROJECTTASKTYPE而不是PROJECT_TASK_TYPE,尽管这样有点难以阅读,但我必须承认这样查询更容易。 - Peter Perháč
3
对于 SQL Server,我们也使用“old_school_names”。除此之外,我们的主要区别是我更喜欢将“tablename_id”作为主键,而不仅仅是“id”,这虽然有些冗余,但有时很有用;它还意味着大多数情况下,表 A 和表 B 之间的链接是在具有相同名称的列上进行的,例如:purchase.purchase_type_id = purchase_type.purchase_type_id。我们还指定表名应该是单数形式,而不是复数形式(“purchase”而不是“purchases”)。 - araqnid
我的架构师说他想在联接表的名称不明显时使用下划线。例如,如果客户和产品通过OrderId连接到订单,则我们可以设置!但是,如果产品和类别连接,并且没有业务名称用于连接,则我们将得到Product_Category和Product_Category_Id。(SQL Server) - Raj More

9
  • 列出所有的约束条件

1
我喜欢给约束条件起有意义的名称的想法。 - Raj More

8

定期备份数据库是十分重要的,请不要忘记。


2
我会更进一步。每天备份,每周还原。始终要仔细检查您是否能够实际还原备份,否则您将在困难时期发现您的备份不足够好。 - Raj More

7
  1. 不要在字段名中使用类型名称。老一辈的人可能还记得旧的MS标准lpszFieldName和随之而来的愚蠢。

  2. 使用描述性的字段名,遵循正常语言习惯。例如,“FirstName”而不是“NameFirst”

  3. 字段名中的每个单词都大写

  4. 不要使用下划线

  5. 不要使用常规关键字,如“Index”

  6. 不要在任何对象类型前缀中加入任何内容。例如,我们不使用tblCustomers或spCustomersGet。这些不允许进行良好的排序并且提供零价值。

  7. 使用模式定义数据库的不同区域。例如sales.Customers和hr.Employees。这将消除大多数人使用的前缀。

  8. 任何类型的循环都应该受到怀疑。通常有更好的基于集合的方法。

  9. 对于复杂的连接,请使用视图。

  10. 尽可能避免复杂的连接。拥有一个CustomerPhoneNumbers表可能更美观,但是说实话,我们真的需要存储多少电话号码?只需将字段添加到Customers表中。您的数据库查询速度会更快,而且更容易理解。

  11. 如果一个表将一个字段称为“EmployeeId”,那么每个引用它的表都应该使用该名称。它不需要被称为CustomerServiceRepId,只因为它在扩展表中。

  12. 几乎所有的表都有“s”结尾。例如:Customers,Orders等。毕竟,表保存了许多记录...

  13. 使用分析工具评估您的查询、索引和外键关系。即使是为您生成的那些。你可能会感到惊讶。

  14. 支持多对多关系的链接表在名称中同时包含两个链接表。例如,SchoolsGrades。通过表名非常容易知道它的作用。

  15. 保持一致。如果您开始按照约定走下去,请不要半途而废,除非您愿意重构所有以前的工作。这应该阻止任何“这样做不好吗?”的想法,这会导致混淆和大量的重复工作。

  16. 在键入之前请先思考。您真的需要那个表、字段、sproc或视图吗?您确定它没有被其他地方覆盖吗?在添加之前获得共识。如果由于某种原因必须将其取出,请先与团队交谈。我曾经在某些地方,DBA每天都会进行破坏性的更改,而不考虑开发人员。这不好玩。


13
强烈不同意第十条,这通常是一种很糟糕的做法,你必须改变表结构才能添加新的电话类型。有些人需要存储的电话号码数量可能会让你感到惊讶。不过我非常赞同第八条。 - HLGEM
5
+1给第10条。你不能夸大过度规范化的成本。 - Andomar
1
@Joe,我会在前缀中加入一些有意义的信息。例如,responsibleEmployeeId或assistantEmployeeId。 - Nathan Koop
2
@Tapori,我同意第10点可能在一定程度上取决于系统要求。但是,我认为你的例子不太好。对于通话记录,最好将实际电话号码放在历史记录表中,地址也是如此。它应该在订单表中。原因是即使有人从您的“电话”或“地址”表中删除记录,这可以保持您的历史记录完好无损。重复数据?可能是,但是您的数据更容易报告,并且这些字段中的数据永远不应更改。 - NotMe
1
通过将电话号码保存在与实际通话记录相同的记录中,您的UI /数据层可以管理主客户帐户中的电话号码,而不必考虑损坏历史记录。地址和订单也是如此。 - NotMe
显示剩余10条评论

7

如果数据库是为特定应用程序而设计的,请建立一个版本表,以便可以检查数据库发布与代码发布之间的匹配情况(除其他原因外)。


6

我总是尽量避免在字段名中使用类型 —— “sFirstName”,“sLastName”或“iEmployeeID”。虽然它们一开始匹配,但如果有任何变化,它们就会失去同步,以后更改这些名称会带来巨大的麻烦,因为您必须同时更改依赖对象。

Intellisense和GUI工具使得查找列的类型非常容易,因此我认为这并不是必要的。


5

WITH子句真正有助于将查询分解为易于管理的部分。

此外,对于查询执行计划的效率也非常有帮助。


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