44

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

  1. 表名匹配主键名和描述键
  2. 模式按功能区域划分
  3. 尽可能避免使用复合主键(使用唯一约束)
  4. Camel Case 表名和字段名
  5. 不要使用 tbl_ 为表添加前缀,也不要使用 SP_ 为 procs 添加前缀(没有匈牙利符号)
  6. OLTP 数据库应该至少在 BCNF / 4NF
4

30 回答 30

19
  • 使用相同的前缀命名类似的目标存储过程,例如,如果您有 3 个用于 Person 的存储过程。这样,人员的所有内容都集中在一个地方,您可以轻松找到它们,而无需查看所有 proc 来找到它们。
    • 人物更新
    • 人物删除
    • 个人创建
  • 当您拥有包含相关数据的表组时,对表执行类似的操作。例如:
    • 发票标头
    • 发票行
    • 发票行详细信息
  • 如果您可以选择数据库中的模式,请使用它们。更好看:
    • 发票.Header
    • 发票.行.项目
    • Invoice.Line.Item.Details
    • 个人更新
    • 个人删除
    • 个人.创建
  • 除非没有其他合理的方法可以实现该目标,否则不要使用触发器。
  • 给字段名称一个有意义的前缀,这样您就可以知道它们来自哪个表,而无需有人解释。这样,当您看到引用的字段名称时,您可以轻松判断它来自哪个表。
  • 对包含相似数据的字段使用一致的数据类型,即不要将电话号码作为数字存储在一个表中,而将 varchar 存储在另一个表中。事实上,不要将它存储为数字,如果我遇到一个负数的电话号码,我会很生气。
  • 不要在表/字段名称中使用空格或其他晦涩的字符。它们应该完全是字母数字 - 或者如果我有我的 druthers,除了下划线之外完全是字母。我目前正在开发一个继承系统,其中表和字段名称包含空格、问号和感叹号。让我每天都想杀死设计师!
  • 不要使用语法关键字作为对象名称,这会导致尝试从中检索数据时头疼。我讨厌必须将对象名称包装为 [index] 这是两个不必要的字符,我不需要输入该死的你!
于 2009-06-10T15:11:34.723 回答
13

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

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

如果您在创建时拼写错误,请在发现后立即修复。不必花费数年时间记住在此表中 UserName 确实是 Usernmae。当没有太多针对它编写的代码时,它更容易修复。

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

于 2009-06-10T15:26:22.587 回答
11

将每个人的意见放在一个列表中。

命名标准

  • 模式按功能区域命名(产品、订单、运输)
  • 没有匈牙利表示法:对象名称中没有类型名称(没有 strFirstName)
  • 不要对对象名称使用已注册的关键字
  • 对象名称中不能有空格或任何特殊字符(字母数字 + 下划线是唯一允许的)
  • 以自然的方式命名对象(FirstName 而不是 NameFirst)
  • 表名应与主键名称和描述字段匹配(SalesType – SalesTypeId、SalesTypeDescription)
  • 不要以 tbl_ 或 sp_ 作为前缀
  • 对象名称的名称代码(CustomerSearch、CustomerGetBalance)
  • CamelCase 数据库对象名称
  • 列名应该是单数
  • 表名可以是复数
  • 为所有约束提供企业名称 (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)
于 2009-06-30T19:11:04.283 回答
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 子句足够长,我将把它分成每行一个字段。

于 2009-06-10T15:13:29.867 回答
9
  • 命名所有约束
于 2009-06-10T15:22:05.497 回答
8

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

于 2009-06-10T15:15:59.457 回答
7

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

于 2009-06-10T17:00:37.530 回答
7
  1. 不要在字段名称中使用类型名称。年长的人会记得 lpszFieldName 的旧 MS 标准和随之而来的愚蠢。

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

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

  4. 没有下划线

  5. 不要使用“索引”等普通关键字

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

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

  8. 任何类型的循环都应该被怀疑地看待。通常有更好的基于集合的方式。

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

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

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

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

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

  14. 支持多对多关系的链接表在名称中包含两个链接表。例如,SchoolsGrades。通过表名很容易判断它的作用。

  15. 始终如一。如果你从一个约定的路径开始,除非你愿意重构所有以前的工作,否则不要半途而废。这应该制止任何“如果......不是很好”的想法,这些想法最终会导致混乱和大量的返工。

  16. 打字前三思。你真的需要那个表、字段、存储过程或视图吗?你确定它没有被其他地方覆盖吗?在添加之前获得共识。如果由于某种原因您必须将其取出,请先与您的团队交谈。我一直在 DBA 每天进行重大更改而不考虑开发人员的地方。这不好玩。

于 2009-06-10T15:18:18.610 回答
6

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

Intellisense 和 GUI 工具使找出列的类型变得很简单,所以我认为这没有必要。

于 2009-06-10T15:09:44.323 回答
5

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

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

于 2009-06-10T15:21:32.457 回答
5

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

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

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

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

  • 查找空模式

  • 查找没有主键的表

  • 查找没有任何索引的表

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

  • 查找特定于系统的问题 - 需要归档的表、不属于正常每月或每日处理的异常、具有或不具有默认值的某些常见列名(例如,CreateDate)。

  • 寻找非确定性 UDF

  • 查找 TODO 注释以确保数据库中的代码没有未经测试或预发布的代码。

所有这些都可以自动化,让您全面了解系统健康状况。

于 2009-06-10T15:56:56.240 回答
3

A few likes and dislikes.

My opinion is prefixes are horrible in every aspect. I currently work on a system where the tables are prefixed, and the columns within the tables are prefixed with 2 letter table name acronyms, I waste at least 30 mins each day working on this database because the acronym isn't logical. If you want to denote something with a prefix use a schema owner instead.

Using NVarchar from the start of a project if there is even a slight hint that down the line the text data will need to support multi lingual chars. Upgrading large databases because of lack of forward planning and thinking is a pain and wastes time.

Splitting each condition within a where clause onto a new line for readability (in and not in statements wrapped in brackets and tabbed in.) I think this is the important standard for me.

I worked at one company where a standard was that comma's must always be placed at the start of a line when performing parameter or variable declarations. This apparently made it more readable however I found it a complete nightmare.

于 2009-06-10T16:53:15.783 回答
3

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

于 2009-06-10T15:08:51.967 回答
3

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

于 2009-06-10T15:13:40.413 回答
2

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

于 2009-06-10T15:07:04.030 回答
2

除了归一化为 3NF 或 BCNF(有关此问题的更多信息)之外,我发现以下内容很有用:

  • 将表命名为复数名词
  • 将列命名为单数

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

  • 组合键没有任何问题,只要 3NF 或 BCNF 的规则仍然成立。在许多情况下(例如“多对多”情况),这是完全可取的。
  • 避免在列名中重复表名。无论如何,peoplePersonID 最好写成 table.column,并且可读性更强,因此可以自我记录。People.PersonID 至少对我来说更好。
  • ON DELETE CASCADE 应该非常小心地使用。
  • 请记住,NULL 意味着以下两种情况之一:未知或不适用。
  • 还要记住 NULL 对连接有有趣的影响,所以练习你的 LEFT、RIGHT 和 FULL 外连接。
于 2009-06-10T15:11:36.550 回答
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 连接到查询中?” 该结构不需要很长时间来应用或更新,我发现它节省了很多时间。我们花在阅读代码上的时间多于编写代码。

于 2009-06-10T16:22:12.630 回答
2

其他一些(尽管很小)评论要靠墙扔...

SQL Server 数据库架构可用于组织表和存储过程以及控制安全性。

每个事务表都应始终跟踪创建记录的人员和时间,并在单独的列中更新记录。我见过简单地使用“更新日期”的实现,这可能会导致未来的审计挑战。

对具有离线/同步要求的项目的所有行使用 GUID 作为行标识符。

于 2009-06-10T15:25:10.593 回答
2
  • 表格以单数、小写、无下划线、无前缀命名
  • 字段也是小写,没有下划线,没有前缀
  • 以“st_”为前缀的存储过程(排序很好)
  • 被视为表的视图没有前缀
  • 为特殊报告等创建的视图具有“v”前缀
  • 为性能而创建的索引视图具有“ixv”前缀
  • 所有索引都有有目的的名称(没有自动命名)
  • 强烈倾向于使用 uniqueidentifier(顺序递增)而不是 int IDENTITY 作为代理键
  • 不要人为地将 VARCHAR/NVARCHAR 字段限制为 100 或 255。给他们喘息的空间。这不是 1980 年代,字段没有存储到它们的最大长度。
  • 3NF 最低标准
  • 更喜欢连接表而不是列级外键:随着系统随着时间的推移而增长,许多 1:m 假设受到挑战。
  • 始终使用代理键,而不是自然键作为主键。所有关于“自然”密钥(SSN、用户名、电话号码、内部代码等)的假设最终都会受到挑战。
于 2009-06-10T15:45:38.180 回答
1

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

不恰当地使用数据库会导致领域模型贫乏、代码可测试性差和不必要的性能问题。

于 2010-02-10T16:16:28.640 回答
1

13-评估您的查询

确实如此。有时你得不到你想要的。

对我来说,用它们的确切内容和(对我们)用清晰的西班牙语命名表和字段总是有用的,并使用大驼峰大小写,没有空格:

用户名:NombreUsuario

名:阿佩里多帕特诺

第二姓:ApellidoMaterno

等等等等

于 2009-06-10T15:40:58.877 回答
1

避免愚蠢的缩写约定,例如积极鼓励像 EMP_ID_CONV_FCTR_WTF_LOL_WAK_A_WAK_HU_HU 这样的怪物的综合缩写字典。这条规则的灵感来自我以前见过的一套真实的指导方针。

于 2009-06-30T19:45:28.973 回答
1

MVP Aaron Bertrand 的“我的存储过程”最佳实践“清单”

于 2009-06-30T20:20:45.907 回答
1

在 MS-SQL 中,我一直拥有 dbo 拥有的对象,并且我在对这些对象的调用前加上 dbo。

太多次我看到我们的开发人员想知道为什么他们不能调用他们无意中拥有的对象。

于 2009-06-11T11:44:38.707 回答
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 个表时,可以提供很多帮助。

于 2009-06-30T20:28:04.720 回答
1

用“数据库”来表示“SQL 产品”,我的回答是,“太多了,不胜枚举。你可以写一本关于这个主题的整本书。” 令人高兴的是,有人拥有。

我们使用 Joe Celko 的 SQL 编程风格 (ISBN 978-0120887972):“本书是启发式和规则、提示和技巧的集合,将帮助您提高 SQL 编程风格和熟练程度,并用于格式化和编写可移植、可读、可维护的SQL 代码。”

这种方法的优点包括:

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

在实践中,我们确实偏离了书中的规定,但令人惊讶的是很少。

于 2009-06-11T11:24:54.403 回答
1

记录一切;wiki 类型的文档易于设置并且软件是免费的。

确保您首先了解界面,然后再设计数据库。大多数情况下,最好知道您将要使用的数据如何工作,然后设计数据库。大多数糟糕的数据库设计发生在事情发展不提前的时候。

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

花时间考虑如何定义具有标准数据库类型的字段或定制类型的类型是预先整理好的事情。

作为文档的一部分,包括应用程序的注意事项列表和注意事项列表,其中包括您喜欢的讨厌的功能光标、触发器。

定期审查。

于 2009-06-10T15:18:29.280 回答
1

我在这里遵循许多与其他人相同的约定,但我想说一些尚未说的事情。

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

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

每当我执行 INSERT INTO...SELECT 时,我都会为 SELECT 部分中的所有列设置别名,以匹配 INSERT INTO 部分中的列名,以便更容易维护并查看事情如何匹配。

于 2010-02-10T16:00:08.817 回答
0

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

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

于 2009-06-10T15:13:02.317 回答
0

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

People Table
PEO_PersonID
PEO_FirstName 
...

这有助于使更大的查询更具可读性。并加入更有意义:

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

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

于 2009-06-10T15:15:40.970 回答