您最有用的数据库标准是什么?

时间:2009-06-10 15:04:59

标签: sql database standards entity-relationship

我有一些想法,有些是我随着时间积累的,但我真的想知道在建模数据库时是什么让事情顺利进行:

  1. 表名与主键名称和说明密钥
  2. 相匹配
  3. 架构按功能区划分
  4. 尽可能避免使用复合主键(使用唯一约束)
  5. Camel Case表名和字段名
  6. 不要使用tbl_为表添加前缀,或者使用SP_(没有匈牙利语表示法)触发前缀
  7. OLTP数据库应至少在BCNF / 4NF中

30 个答案:

答案 0 :(得分: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存储在另一个表中。事实上,不要将其存储为数字,如果我遇到负面电话号码,我会生气。
  • 不要在表/字段名称中使用空格或其他模糊字符。它们应该完全是字母数字 - 或者如果我有我的druthers,除了下划线之外完全按字母顺序排列。我目前正在研究一个继承的系统,其中表和字段名称包含空格,问号和感叹号。让我想每天杀死设计师!
  • 不要使用语法关键字作为对象名称,这会导致头痛试图从中检索数据。我讨厌将对象名称包装为[index],这是两个不必要的字符,我不需要输入该死的你!

答案 1 :(得分:13)

我还没有提到过一件事:

绝不使用数据库关键字作为对象名称。您不希望每次使用它们时都必须对它们进行限定

如果您在创建时拼错了某些内容,请在发现后立即修复。不要花费数年时间来记住在这个表中UserName真的是Usernmae。当没有太多针对它的代码时,修复起来要容易得多。

永远不要使用隐含连接(逗号语法),始终指定连接。

答案 2 :(得分:11)

将每个人的输入放在一个列表中。

命名标准

  • 架构按功能区域(产品,订单,运输)命名
  • 没有匈牙利表示法:对象名称中没有类型名称(无strFirstName)
  • 不要将注册关键字用于对象名称
  • 对象名称中没有空格或任何特殊字符(Alphanumber + Underscore是唯一允许的内容)
  • 以自然方式命名对象(FirstName而非NameFirst)
  • 表名称应与主键名称和描述字段匹配(SalesType - SalesTypeId,SalesTypeDescription)
  • 不要以tbl_或sp_
  • 作为前缀
  • 按对象名称编码的代码(CustomerSearch,CustomerGetBalance)
  • CamelCase数据库对象名称
  • 列名应为单数
  • 表名可以是多个
  • 为所有约束提供商家名称(MustEnterFirstName)

数据类型

  • 跨表使用相同的变量类型(邮政编码 - 一个表中的数字和另一个表中的varchar不是一个好主意)
  • 使用nNVarChar获取客户信息(姓名,地址)等。您永远不知道何时可以进入跨国公司。

代码

  • 关键字始终在大写中
  • 绝不使用隐含连接(逗号语法) - 始终使用显式INNER JOIN / OUTER 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)

答案 3 :(得分: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子句足够长,我将每行分割出一个字段。

答案 4 :(得分:9)

  • 命名所有约束

答案 5 :(得分:8)

不要忘记定期备份数据库。

答案 6 :(得分:7)

如果数据库适用于特定应用程序,请使用版本表,以便可以根据代码版本(以及其他原因)检查数据库版本。

答案 7 :(得分:7)

  1. 请勿在字段名称中使用类型名称。年长的人会记住lpszFieldName的旧MS标准以及随之而来的愚蠢。

  2. 使用符合常规语言约定的描述性字段名称。例如“FirstName”而不是“NameFirst”

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

  4. 没有下划线

  5. 请勿使用普通关键字,例如“索引”

  6. 不要在ANYTHING前加上对象类型。例如,我们不使用tblCustomers或spCustomersGet。这些不允许良好的分类并提供零值。

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

  8. 任何形式的循环都应该被怀疑。通常有一种更好的基于集合的方式。

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

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

  11. 如果一个表调用字段“EmployeeId”,那么引用它的EVERY SINGLE TABLE应该使用该名称。它不需要被称为CustomerServiceRepId,因为它位于扩展表中。

  12. 几乎所有表都有“s”结尾。例如:客户,订单等。毕竟表中包含许多记录......

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

  14. 链接支持多对多关系的表在名称中都有链接表。例如,SchoolsGrades。通过表名告诉它它的作用非常容易。

  15. 一致。如果你开始遵循惯例的一条路径,除非你愿意重构以前的所有工作,否则不要中途换马。这应该扼杀任何“如果......不会很好”的想法,最终导致混乱和大量的返工。

  16. 在输入之前先想想。你真的需要那张桌子,场地,杂物或视图吗?你确定它不在其他地方吗?在添加之前获得一致意见。如果由于某种原因您必须将其取出,请先与您的团队联系。我一直在DBA每天都在不考虑开发人员的情况下做出改变的地方。这不好玩。

答案 8 :(得分:6)

我总是尽量不使用字段名称中的类型 - “sFirstName”,“sLastName”或“iEmployeeID”。虽然它们最初匹配,但如果发生变化,它们将不同步,以后更改这些名称会非常头疼,因为您还必须更改依赖对象。

Intellisense和GUI工具使得找出列的类型变得微不足道,所以我觉得这不是必需的。

答案 9 :(得分:5)

确保每个varchar / nvarchar选择都合适。

确保每个NULLable列选择都是合适的 - 尽可能避免使用NULLable列 - 允许NULL应该是合理的位置。

无论您在此处的建议中使用何种其他规则,我都会在数据库中创建一个可以定期运行的存储过程,以确定您拥有的任何规则或标准的系统运行状况(其中一些是一点点SQL-Server):

  • 在任何由于某种原因无法使用DBMS系统的参照完整性的情况下查找孤立记录(在我的系统中,我有一个进程表和一个测试表 - 所以我的system_health SP查找没有测试的进程,因为我只有单向FK关系)

  • 查找空架构

  • 查找没有主键的表格

  • 查找没有任何索引的表格

  • 查找没有文档的数据库对象(我们使用SQL Server扩展属性将文档放入数据库中 - 此文档可以像一样精细)。

    < / LI>
  • 查找特定于系统的问题 - 需要归档的表,不是正常月度或日常处理的异常,具有或不具有默认值的某些常见列名(比如CreateDate)。

  • 寻找非确定性UDF

  • 查找TODO注释,以确保数据库中的代码不会以某种方式具有未经测试或预发布的代码。

所有这一切都可以自动生成,让您全面了解系统健康状况。

答案 10 :(得分:5)

WITH子句确实有助于将查询分解为可管理的部分。

它还有助于提高查询执行计划的效率。

答案 11 :(得分:3)

每个人都以相同的基本格式编写SQL查询(视图,存储过程等)。它确实有助于开发/维护工作。

答案 12 :(得分:3)

一些喜欢和不喜欢。

我的观点是前缀在每个方面都很糟糕。我目前正在使用一个系统,其中表格是前缀,并且表格中的列以2个字母的表格名称首字母缩写为前缀,我每天浪费至少30分钟来处理此数据库,因为首字母缩略词不合逻辑。如果要表示带前缀的内容,请改为使用架构所有者。

如果项目一开始就有一点点暗示文本数据需要支持多语言字符,那么从项目开始使用NVarchar。由于缺乏前瞻性规划和思考而升级大型数据库是一种痛苦和浪费时间。

将where子句中的每个条件拆分到一个新行上以便于阅读(包括在括号和选项卡中的语句中,而不是。)我认为这是我的重要标准。

我曾在一家公司工作,其标准是在执行参数或变量声明时,必须始终将逗号放在行的开头。这显然使它更具可读性,但我发现它是一个完整的噩梦。

答案 13 :(得分:3)

一致的命名标准。让每个人都在同一页面上,使用相同的格式(无论是Camel Case,特定前缀等)都有助于能够准确地维护系统。

答案 14 :(得分:2)

其他一些人(虽然很小)发表评论反对意见......

SQL Server数据库模式对于组织表和存储过程以及控制安全性都很有用。

每个事务表应始终跟踪创建记录的人员和时间,以及在单独的列中更新记录。我看到实施只是简单地使用了“更新日期”,这可能导致未来的审计挑战。

对于具有脱机/同步要求的项目的所有行,请使用GUID作为行标识符。

答案 15 :(得分:2)

良好的数据库设计和规范化

答案 16 :(得分:2)

除了对3NF或BCNF的规范化(更多关于this question中的规范化),我发现以下内容是有用的:

  • 将表格命名为复数名词
  • 将列命名为sigular

所以“People”表有一个“PersonID”列。

  • 复合键没有任何问题,只要3NF或BCNF的规则仍然有效。在许多情况下(例如“多对多”情况),这是完全可取的。
  • 避免在列名中重复表名。无论如何,peoplePersonID更好地写成table.column,并且更具可读性,因此可以自我记录。至少对我来说,People.PersonID更好。
  • ON DELETE CASCADE应该非常小心
  • 请记住,NULL意味着两件事之一:要么是未知的,要么是不适用的。
  • 还要记住,NULL对连接有一些有趣的影响,所以练习你的LEFT,RIGHT和FULL外连接。

答案 17 :(得分:2)

表格格式化的SQL。

select a.field1, b.field2
from       any_table   a
inner join blah        b on b.a_id       = a.a_id
inner join yet_another y on y.longer_key = b.b_id
where a.field_3         > 7
and   b.long_field_name < 2;

部分原因是使用统一长的别名(在这个例子中,这里,a,b和y都是长度为1)。

通过这种格式化,我可以更快地回答常见问题,例如“什么表是'a'的别名?”和“哪些字段将表T连接到查询?”该结构不需要很长时间才能应用或更新,我发现它可以节省大量时间。我们花更多时间阅读代码而不是写代码。

答案 18 :(得分:2)

  • 表以单数,小写,无下划线,无前缀
  • 命名
  • 字段也是小写,没有下划线,没有前缀
  • 以“st_”为前缀的存储过程(排序很好)
  • 被视为表格的视图没有前缀
  • 为特殊报告等创建的视图具有“v”前缀
  • 为效果创建的索引视图具有“ixv”前缀
  • 所有索引都有目的名称(无自动命名)
  • 强烈优先选择uniqueidentifier(使用顺序递增)而不是代理键的IDENTITY
  • 不要人为地将VARCHAR / NVARCHAR字段限制为100或255.给它们留出空间。这不是20世纪80年代,字段没有填充到最大长度。
  • 3NF最低标准
  • 首选将表连接到列级外键:随着系统的不断增长,许多1:m的假设都会受到挑战。
  • 始终使用代理键而非自然键作为主键。关于“自然”密钥(SSN,用户名,电话号码,内部代码等)的所有假设最终都会受到质疑。

答案 19 :(得分:1)

13-评估您的查询

这是真的。有时候你没有得到你想要的东西。

对我而言,以明确的西班牙语和使用Upper Camel Case的方式命名表格和字段以及它们的确切内容和(对我们而言)总是有用的,没有空格:

用户名:NombreUsuario

姓氏:ApellidoPaterno

第二姓:ApellidoMaterno

等等

答案 20 :(得分:1)

以“数据库”来表示“SQL产品”,我的回答是“太多了。你可以写一整本关于这个主题的书。”很幸运,有人有。

我们使用Joe Celko的SQL编程风格(ISBN 978-0120887972):“本书是一系列启发式和规则,提示和技巧,可帮助您提高SQL编程风格和熟练程度,以及格式化和编写便携式,可读,可维护的SQL代码。“

这种方法的优点包括:

  • 这家伙比我更了解这种事情(还有另外一本关于SQL启发式的书吗?!);
  • 工作已经完成,例如我可以把这本书交给团队中的人阅读和参考;
  • 如果有人不喜欢我的编码风格,我可以责怪别人;
  • 我最近通过推荐另一本Celko书获得了大量的代表:)

在实践中,我们确实偏离了“书”的处方,但很少出人意料。

答案 21 :(得分:1)

在MS-SQL中,我总是拥有dbo所拥有的对象,并使用dbo为这些对象添加前缀。

很多次我看到我们的开发人员想知道为什么他们不能称他们无意中拥有的物品。

答案 22 :(得分:1)

记录一切;维基类型文档易于设置,软件是免费的。

确保首先了解界面并设计数据库。大多数情况下,了解您将要使用的数据如何工作然后设计数据库要好得多。最糟糕的数据库设计是因为事情不是在前面发展而发生的。

然后定义您要使用的数据库标准和版本。定义代码元素的标准(视图,函数等),数据库命名;列,表的命名约定;列的类型约定;编码模板。

花时间考虑如何为字段或定制类型定义具有标准数据库类型的类型是一个很好的事情,可以提前进行整理。

作为您的文档的一部分,包括应用程序列表以及应用程序的dos,其中包括您喜欢的首选功能游标,触发器。

定期检讨。

答案 23 :(得分:1)

避免使用愚蠢的缩写惯例,例如积极鼓励像EMP_ID_CONV_FCTR_WTF_LOL_WAK_A_WAK_HU_HU这样的怪物的缩写的综合词典。这条规则启发了我之前见过的一套真实的指导方针。

答案 24 :(得分:1)

答案 25 :(得分:1)

  

表名与主键名和描述键

相匹配

最近,经过多年的同意,我跳了船,现在每张桌子上都有一个“ID”栏。

是的,我知道,在链接表格时它是不明确的!但是将ProductID链接到ProductID也是如此,所以,为什么要额外输入?

此:

SELECT p.Name, o.Quantity FROM Products p, Orders o WHERE o.ProductID = p.ID

略胜一筹:

SELECT p.Name, o.Quantity FROM Products p, Orders o WHERE o.ProductID = p.ProductID

请注意,两者都需要表或别名前缀。但是,我不仅打字稍微少一点(在具有长描述性名称的数十个表中加倍,并且在数据密集型应用程序中快速加起来),但它也使得更容易知道哪个表是每个连接中的父表,其中,在查询中加入8-10个表时,可以提供相当多的帮助。

答案 26 :(得分:1)

我在这里遵循了很多相同的约定,但我想说一些尚未说过的事情。

无论您是喜欢表格的复数名称还是单数名称,都要保持一致。选择其中一个,但不要同时使用它们。

表中的主键与表的名称相同,后缀为_PK。外键与其对应的主键具有相同的名称,但后缀为_FK。例如,Product表的主键名为Product_PK;在Order表中,相应的外键是Product_FK。我从我的另一位DBA朋友那里挑选了这个习惯,到目前为止,我很喜欢它。

每当我执行INSERT INTO ... SELECT时,我将SELECT部分​​中的所有列别名以匹配INSERT INTO部分中列的名称,以便更容易维护并查看事物是如何匹配的。

答案 27 :(得分:1)

最重要的标准是:默认情况下没有数据库。我发现太多的开发人员为一个项目抓住了一个数据库,在没有一个项目的情况下生活会更容易(至少还有)。它只是工具箱中的一个工具,并不是每个问题都是钉子。

不恰当地使用数据库会导致域模型贫乏,代码严重不可测试以及不必要的性能问题。

答案 28 :(得分:0)

除了#5之外,我同意你放在那里的所有东西。我经常为表和存储过程使用前缀,因为我们开发的系统有许多不同的功能区域,所以我倾向于在表和sprocs前面加上一个标识符,允许它们根据区域在Management Studio中很好地组合他们属于。

示例:cjso_Users,cjso_Roles,然后你有routing_Users,routing_Roles。这可能听起来像是数据的复制,但实际上两个不同的用户/角色表用于系统的完全独立的功能(cjso将用于基于客户的电子商务应用程序,而路由将代表使用路由的员工和分销商)系统)。

答案 29 :(得分:0)

我喜欢我们的表命名约定:

People Table
PEO_PersonID
PEO_FirstName 
...

这有助于使更大的查询更具可读性。和连接更有意义:

Select * -- naughty!
From People
Join Orders on PEO_PersonID = ORD_PersonID
--...

我想的不是命名约定,而是命名的一致性。