什么是你最有用的数据库标准?
我有一些想法,有些是我一直积累下来的,但是我真的很想知道在build模数据库时,什么能让你顺利进行。
- 表名与主键名称和说明键匹配
- 模式是由function区
- 尽可能避免使用复合主键(使用唯一约束)
- 骆驼案例表名称和字段名称
- 不要使用tbl_前缀表,要么使用SP_(没有匈牙利符号)
- OLTP数据库应该至less在BCNF / 4NF中
- 命名相似的目标存储过程与相同的前缀,例如,如果你有3人存储过程。 这样,人的一切都集中在一个地方,你可以很容易地find他们,而不必通过你所有的过程来find他们。
- PersonUpdate
- PersonDelete
- PersonCreate
- 当你有相关数据的表组时,对表做类似的事情。 例如:
- InvoiceHeaders
- InvoiceLines
- InvoiceLineDetails
- 如果您有数据库中的模式选项,请使用它们。 看到更好:
- Invoice.Header
- Invoice.Line.Items
- Invoice.Line.Item.Details
- Person.Update
- Person.Delete
- Person.Create
- 除非没有其他合理的方法来实现这个目标,否则不要使用触发器。
- 给字段名称一个有意义的前缀,这样你就可以知道他们来自哪个表,而无需解释。 这样,当你看到一个字段名称引用,你可以很容易地告诉它来自哪个表。
- 为包含相似数据的字段使用一致的数据types,即不要将电话号码存储为一个表中的数字,将varchar存储在另一个表中。 事实上,不要把它存储为数字,如果我遇到一个负面的电话号码,我会发疯。
- 不要在表格/字段名称中使用空格或其他模糊字符。 它们应该完全是字母数字的 – 或者如果我有我的打字员,除了下划线之外完全是字母的。 我目前正在inheritance系统的表和字段名称中包含空格,问号和感叹号。 使我想要每天杀死devise师!
- 不要使用语法关键字作为对象名称,它会导致头痛,试图从中检索数据。 我讨厌把对象名称作为[索引],这是两个不必要的字符,我不需要input该死的你!
有一件事我还没有看到提到:
切勿将数据库关键字用作对象名称。 你不想每次使用它们时都要限制它们
如果您在创build时拼错了某些内容,请在注意到之后立即修复它。 不要花费数年的时间记住,在这个表中UserName实际上是Usernmae。 当没有太多的代码被写入时,修复起来更容易。
不要使用隐式连接(逗号语法),总是指定连接。
把每个人的意见放在一起。
命名标准
- 模式以function区域命名(产品,订单,运输)
- 无匈牙利符号:对象名称中没有types名称(不含strFirstName)
- 不要使用注册关键字作为对象名称
- 对象名称中没有空格或特殊字符(只允许使用字母数字+下划线)
- 以自然的方式命名对象(名字而不是NameFirst)
- 表名称应匹配主键名称和说明字段(SalesType – SalesTypeId,SalesTypeDescription)
- 不要以tbl_或sp_开头
- 按对象名称的名称代码(CustomerSearch,CustomerGetBalance)
- CamelCase数据库对象名称
- 列名应该是单数
- 表名可能是复数
- 为所有约束提供商业名称(MustEnterFirstName)
数据types
- 跨表使用相同的variablestypes(Zip代码 – 一个表中的数字和另一个表中的varchar不是一个好主意)
- 使用nNVarChar作为客户信息(姓名,地址)等,你永远不知道你什么时候可以去跨国公司
在代码中
- 关键字始终在大写
- 永远不要使用隐含的连接(逗号语法) – 总是使用显式的INNER JOIN / OUTER JOIN
- 每行一个JOIN
- 每行一个WHERE子句
- 没有循环 – 用基于集合的逻辑代替
- 使用简短的表格名称作为别名,而不是A,B,C
- 避免触发,除非没有追索权
- 避免像鼠疫这样的游标(阅读http://www.sqlservercentral.com/articles/T-SQL/66097/ )
文档
- 创build数据库图
- 创build一个数据字典
规范化和参照完整性
- 尽可能使用单列主键。 根据需要使用唯一的约束
- 参照完整性将始终强制执行
- 避免ON DELETE CASCADE
- OLTP必须至less为4NF
- 评估每一个一对多的关系,作为一个潜在的多对多关系
- 非用户生成的主键
- build立基于插入的模型,而不是基于更新
- PK到FK必须是相同的名称(Employee.EmployeeId是与EmployeeSalary.EmployeeId相同的字段)
- 除了有双连接(Person.PersonIdjoin到PersonRelation.PersonId_Parent和PersonRelation.PersonId_Child)
维护:运行定期脚本来查找
- 架构没有表格
- 孤儿logging
- 没有主键的表
- 没有索引的表
- 非确定性UDF
- 备份,备份,备份
好,
- 始终如一
- 现在修复错误
- 阅读Joe Celko的SQL编程风格(ISBN 978-0120887972)
我的Oracle标准是:
- 关键词总是在大写;
- 数据库对象名称始终为小写;
- 下划线将replace空格(即,不会有任何在SQL Server上常见的驼峰惯例);
- 主键总是被命名为“id”;
- 参照诚信将被强制执行;
- 整数值(包括表ID)通常总是NUMBER(19,0)。 原因是这将适合一个64位有符号的整数,从而允许使用Java longtypes而不是更笨拙的BigInteger;
- 尽pipe将“_number”附加到某些列名称是错误的,但是这样的列的types将是VARCHAR2而不是数字types。 数字types是保留给你做算术的主键和列;
- 我总是使用技术主键; 和
- 每个表都有自己的密钥生成序列。 该序列的名称将是_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子句足够长,我将把它分成每行一个字段。
- 命名所有约束
不要忘记定期备份数据库。
-
不要在字段名称中使用types名称。 老年人会记住lpszFieldName的旧MS标准和随之而来的愚蠢。
-
使用描述性字段名称遵循正常的语言约定。 例如“FirstName”而不是“NameFirst”
-
字段名称中的每个单词都是大写的
-
没有下划线
-
不要使用普通的关键字,如“索引”
-
不要在对象types前面添加任何前缀。 例如,我们不使用tblCustomers或spCustomersGet。 这些不允许良好的分类和提供零价值。
-
使用模式来定义数据库的单独区域。 如销售。客户和hr.Employees。 这将摆脱人们使用的大多数前缀。
-
应该怀疑任何types的回路。 通常有一个更好的基于集合的方式。
-
使用视图进行复杂的连接。
-
尽可能避免复杂的连接。 有一个CustomerPhoneNumbers表可能会更令人满意, 但说实话,我们真的需要存储多less个电话号码? 只需将这些字段添加到客户表。 您的数据库查询速度会更快,而且更容易理解。
-
如果一个表调用一个字段“EmployeeId”,那么引用它的每个单一表都应该使用这个名字。 它不需要仅仅因为它在扩展表中而被称为CustomerServiceRepId。
-
几乎所有的表格都以“s”结尾。 例如:客户,订单等所有的表格后,拥有许多logging…
-
使用分析工具评估您的查询,索引和外键关系。 即使是那些可能为你生成的。 你可能会感到惊讶。
-
链接支持多对多关系的表都有名称中的链接表。 例如,SchoolsGrades。 表名称很容易辨别它的作用。
-
始终如一。 如果你用惯例开始一条路,除非你愿意重构所有以前的工作,否则不要马匹半途更换。 这应该使任何“如果……”的想法最终导致混乱和大量的返工,这是不好的。
-
在打字之前想一想。 你真的需要那张桌子,场地,杂物还是观景? 你确定它不在其他地方? 添加之前先获得共识。 如果由于某种原因你必须把它拿出来,先和你的团队谈谈。 我一直在DBA的日常突破变化,而不考虑开发的地方。 这并不好玩。
如果数据库是针对某个特定的应用程序的,则需要有一个版本表,以便可以根据代码版本(除其他原因)检查数据库版本。
我总是尽量不要使用字段名称中的types – “sFirstName”,“sLastName”或“iEmployeeID”。 尽pipe它们一开始就相匹配,但如果事情发生了变化,它们将会不同步,并且稍后更改这些名称是一件非常头疼的事情,因为您还必须更改相关对象。
智能感知和graphics用户界面工具使得找出列的types是微不足道的,所以我不觉得这是必要的。
WITH子句确实有助于将查询分解成可pipe理的部分。
这对于查询的执行计划的效率也是非常有帮助的。
确保每个varchar / nvarcharselect都是合适的。
确保每个NULLable列的select是合适的 – 尽可能避免NULLable列允许NULL应该是合理的位置。
无论您使用这些build议中的任何其他规则,我都会在数据库中创build一个可以定期运行的存储过程,以确定您拥有的任何规则或标准的系统健康状况(其中一些是SQL – 服务器特定):
-
在DBMS系统的参照完整性由于某种原因而无法使用的情况下(在我的系统中,我有一个进程表和一个testing表 – 因此我的system_health SP在没有testing的情况下查找进程,因为我只有一个单向FK关系)
-
寻找空的模式
-
查找没有主键的表格
-
查找没有任何索引的表
-
在没有文档的情况下查找数据库对象(我们使用SQL Server扩展属性将文档放到数据库中 – 本文档可以与列一样细致)。
-
查找系统特定的问题 – 需要归档的表格,不属于正常的每月或每天处理的例外情况,某些具有或不具有默认值的常见列名(例如CreateDate)。
-
寻找非确定性的UDF
-
查找TODO注释以确保数据库中的代码不会以某种方式具有未经testing或预发布的代码。
所有这些都可以自动化,从而为您提供系统健康状况的全面信息。
每个人都以相同的基本格式编写SQL查询(视图,存储过程等)。 它确实有助于下一步的开发/维护工作。
一致的命名标准。 让每个人在同一页面上,使用相同的格式(无论是骆驼案例,特定的前缀等)有助于能够准确地维护一个系统。
有一些喜欢和不喜欢。
我的意见是前言在各方面都是可怕的。 我目前正在使用一个系统,在这个系统中前缀表,并且表中的列前面加上2个字母的表名缩写,我每天浪费至less30分钟工作在这个数据库,因为缩写是不合逻辑的。 如果你想用一个前缀来表示某个东西,那就改用一个模式所有者。
从项目的开始使用NVarchar,如果甚至有一点提示,文本数据将需要支持多语言字符。 由于缺乏前瞻性规划和思考而升级大型数据库是一个痛苦和浪费时间。
将where子句中的每个条件拆分到一个新的行中以便于阅读(in和in括在括号和tab中)。我认为这是我的重要标准。
我曾经在一家公司工作过,在这个公司里,当执行参数或variables声明时,逗号必须始终放在行首。 这显然使它更可读,但我发现它是一个完整的噩梦。
除了归一化为3NF或BCNF(更多关于这个问题 ),我发现以下是有用的:
- 名称表作为复数名词
- 命名为sigular的列
所以一个“People”表有一个“PersonID”列。
- 复合键没有问题,只要3NF或BCNF的规则依然成立。 在许多情况下(如“多对多”的情况),这是完全可取的。
- 避免在列名中重复表名。 peoplePersonID最好写成table.column,而且更可读,因此自我logging。 People.PersonID至less对我来说更好。
- ON DELETE CASCADE应该非常小心地使用 。
- 请记住,NULL意味着两件事之一:要么是未知的,要么是不适用的。
- 还要记住NULL对连接有影响,所以练习你的左,右,和全外连接。
一些其他人(尽pipe很小)的评论扔在墙上…
SQL Server数据库模式可用于组织表和存储过程以及控制安全性。
每个事务处理表应始终跟踪谁创buildlogging以及何时将logging更新到单独的列中。 我已经看到实施,只是使用“更新date”,这可能导致未来的审计挑战。
对于具有脱机/同步要求的项目,为所有行使用GUID作为行标识符。
良好的数据库devise和规范化 。
- 表格以单数,小写,无下划线,无前缀命名
- 字段也是小写,没有下划线,没有前缀
- 以“st_”为前缀的存储过程(很好地sorting)
- 被视为像表一样的视图没有前缀
- 为特殊报告等创build的视图具有“v”前缀
- 为性能创build的索引视图具有“ixv”前缀
- 所有的索引都有目的的名字(没有自动命名)
- 强烈希望uniqueidentifier(连续增量)超过int IDENTITY代理键
- 不要人为地限制VARCHAR / NVARCHAR域为100或255.给他们一口气。 这不是20世纪80年代,田地不储存填充到他们的最大长度。
- 3NF最低标准
- build议将列表连接到列级别的外键:随着时间的推移,许多1:m的假设会受到挑战。
- 始终使用代理键而不是自然键作为主键。 所有有关“自然”键(SSN,用户名,电话号码,内部代码等)的假设最终都会受到挑战。
表格格式的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)。
通过这种格式化,我可以更快地回答常见的问题,比如“哪个表被别名”?“ 和“哪些字段将表T连接到查询中?” 结构不需要很长的时间来应用或更新,我发现它节省了大量的时间。 我们花更多时间阅读代码,而不是写它。
logging一切; 维基types文件很容易设置和软件是免费的。
确保你先了解接口,然后再devise数据库。 大多数情况下,知道要使用的数据需要如何工作,然后devise数据库,会好很多。 大多数坏的数据库devise都是随着事情的发展而变化的。
然后定义你将要工作的数据库标准和版本。 为代码元素(视图,函数等)定义标准,数据库命名; 列,表的命名约定; 列的types约定; 编码模板。
花时间考虑如何为字段定义具有标准数据库types的types,或者定制types是预先分类的好事情。
作为您的文档的一部分,包括一系列不应该包括您最喜欢的function游标,触发器的应用程序的dos。
定期审查。
13 – 评估您的查询
确实如此。 有时你没有得到你想要的东西。
对于我来说,用明确的西class牙语来命名表格和字段是非常有用的,对于我们来说,使用上层骆驼案例(没有空格)
用户名:NombreUsuario
第一个姓氏:ApellidoPaterno
第二个姓氏:ApellidoMaterno
等等
以“数据库”的意思是“SQL产品”,我的回答是“太多提及,你可以写一本关于这个主题的书。 令人高兴的是,有人有。
我们使用Joe Celko的SQL编程风格(ISBN 978-0120887972):“这本书收集了启发式规则,提示和技巧,可以帮助您提高SQL编程风格和熟练程度,以及格式化和编写便携,可读,可维护SQL代码“。
这种方法的优点是包括:
- 这个人比我更了解这种东西(还有另外一本关于SQL启发式的书吗?
- 工作已经完成了,例如我可以把这本书交给团队中的某个人阅读和参考;
- 如果有人不喜欢我的编码风格,我可以责怪别人;
- 我最近通过推荐另外一本Celko书籍,得到了一个代表负荷:)
在实践中,我们确实偏离了“书”的处方,但却很less。
在MS-SQL中,我总是拥有dbo拥有的对象,并且用dbo将这些对象的前缀调用。
我看过我们的开发者太多次,想知道为什么他们不能称他们无意中拥有的东西。
避免愚蠢的缩写惯例,如积极鼓励像EMP_ID_CONV_FCTR_WTF_LOL_WAK_A_WAK_HU_HU这样的缩略词的综合字典。 这条规则激发了我以前见过的一套真正的指导方针。
MVP Aaron Bertrand的“我的存储过程”最佳实践“清单”
表名与主键名称和说明键匹配
我刚刚经过多年的同意,跳船,现在每桌上都有一个“身份证”栏。
是的,我知道,当连接表是不明确的! 但是,将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
请注意,两者都需要表或别名前缀。 但是,不仅我input的内容稍微less一点(在数十个具有长描述性名称的表中进行扩展,而且在数据密集型应用程序中快速加起来),而且还使得更容易知道每个联接中的哪个表是父表,当在查询中join8-10个表格时,可以帮助很多。
我跟这里的其他人一样遵循着同样的约定,但是我想说一些还没说过的话。
无论您喜欢复数名称还是单数名称,都要保持一致。 select一个或另一个,但不要同时使用。
表中的主键与表名具有相同的名称,后缀为_PK。 外键与其对应的主键具有相同的名称,但后缀为_FK。 例如,Product表的主键称为Product_PK; 在Order表中相应的外键是Product_FK。 我从另一位DBA的朋友那里挑选了这个习惯,到目前为止我很喜欢它。
每当我做一个INSERT INTO … SELECT时,我将SELECT部分中的所有列别名匹配INSERT INTO部分的列名称,以便更容易维护并查看事情的匹配情况。
最重要的标准是:默认情况下没有数据库。 我发现有太多的开发人员为了那些没有一个(至less还有)的生活将会变得更容易的项目抓取一个数据库。 这只是工具箱中的工具,并不是每个问题都是钉子。
数据库使用不当导致贫血域模型,严重的可testing代码和不需要的性能问题。
我同意所有你放在那里的东西,除了#5。 我经常使用表和存储过程的前缀,因为我们开发的系统具有许多不同的function区域,所以我会倾向于在表和sprocs前添加一个标识符,以便在Management Studio中基于哪个区域很好地进行分组他们属于。
例如:cjso_Users,cjso_Roles,然后你有routing_Users,routing_Roles。 这可能听起来像数据复制,但实际上两个不同的用户/angular色表是用于完全独立的系统function(cjso将用于基于客户的电子商务应用,而路由select将代表使用路由的雇员和分销商系统)。
我喜欢我们的表格命名约定:
People Table PEO_PersonID PEO_FirstName ...
这有助于使更大的查询更具可读性。 join更有意义:
Select * -- naughty! From People Join Orders on PEO_PersonID = ORD_PersonID --...
我猜而不是命名约定是命名的一致性。