[设计] 数据库结构设计原则【转载】

1. 主键选取

主键的选取对于一个表的设计至关重要,一旦进入编码阶段,对主键的修改将会付出 很大的代价。主键选取字段过少可能会导致表无法适应业务的发展,过多则会使得表的效率严重降低。 主键的字段应处于一个表的前几个字段。 尽量选择唯一标识列作为主键。 建立联合主键时,一般不宜超过 3 个字段。如果字段过多,建议改用流水号做主键。 用作联合主键的字段应按“区分度”从大到小的顺序排列。 “区分度”是指平均每个选 值对应的数据条目数的倒数,即区分度越大的字段意味着该字段选取某一个特定值的 数据占全部数据的比例越小。

老大说:用UUID+TIMESTAMP+MC作为主键,撞车概率就极小了。

2. 字段设计

字段的设计应考虑适当的冗余,以便于查询。 能用更短的字段则使用更短的字段,如人员状态一般使用两位字符串如‘01’‘02’  、 ‘03’‘04’等标记,那么该字段类型定义为 char(2)就比 char(20)更合理也更节 省空间。 尽量减少定义可以为空的字段,因为用 is null 和 is not null 判断是否为空的查询 时不会使用索引, 而且对两个字段进行不等判断时也会更加困难。 A 为空、 为 如 B ‘01’ , A!=B 并不成立。

3. 索引定制

经常存取的列上,可建立索引 经常同时存取的多列,且每列都含有重复值可建立组合索引,组合索引要尽量使关键查询形成索引覆盖,其前导列(索引第一列)一定要选定最频繁使用的列。 索引并不是越多越好,索引对插入、修改和删除数据有副作用,过多的索引会降低系 统效率。一般在一张表上索引个数应控制在 5 个以内。 SQL 编码规则列表中只提供确实需要检索的那些列(尽量避免 避免使用 *)

4.检索字段尽可能的少

SELECT 列表中只提供确实需要检索的那些列(尽量避免使用 SELECT *) 。 DB2 表在将来可能需要更改,以包括附加列。SELECT * 也会检索那些新的列,而如果没有 进行费时的更改,程序也许无法处理附加的数据。 DB2 将为被请求返回的每一列消耗附加资源。 不要寻找您已经知道的东西

5. 不要检索已知字段

不要寻找您已经知道的东西 举一个典型的示例: Select agentcode,name from laagent where agentcode='1100D01001' and branchtype='1' 已经知道了 Agentcode 将等于值“1100D01001” ,但在 Select 子句中又列出了 Agentcode, DB2 还会尽职地检索该列。这会产生附加开销,从而降低性能。 表间的关联查询使用显示连接的语法( join)

6.左连接与外联接

 表间的关联查询使用显示连接的语法(inner join|[left|right]outer join|cross join) 这样做有几个好处:比起在 FROM 子句中用逗号简单地分隔表,这样更具描述性,这在查 询变得很长时,非常重要;在每次连接后,它强制对(ON 子句中的)连接谓词进行编码, 这样就不会忘记过滤条件;很容易确定哪个连接谓词属于哪张表;如果必要,很容易能够 将内连接转换为外连接。 例:Select b.branchattr,b.name,a.agentcode,a.name from laagent a inner join labranchgroup b on a.branchcode=b.agentgroup where a.branchtype=’1’ IN, 子查询里面的记录数相对固定。

7. 用 EXISTS 代替 IN

用 EXISTS 代替 IN,除非 IN 子查询里面的记录数相对固定。 例:Select a.agentcode from laagent a where exists (select 1 from labranchgroup b where b.agentgroup=a.agentgroup and b.branchattr in (‘861100001’,’861100002’) ) 速度更快, 能够更快地根据索引找到范围。

8.BETWEEN 在某些时候比 IN 速度更快

BETWEEN 在某些时候比 IN 速度更快,BETWEEN 能够更快地根据索引找到范围。 select * from laagent where sex in ('0','1') 和 select * from laagent where sex between '0' and '1' 查询结果是一样的。 由于 in 会比较多次,所以有时会慢些。 时发现查询没有走索引,可以使用显示申明指定索引 慎用! 使用显示申明指定索引(

9. 慎用 DISTINCT、TRIM 的使用

Distinct 会进行排序操作,而 Trim 使用不当则可能致使列上索引不能正常使用,所以需要 小心使用。 如果允许, ALL) OR。

10. 尽量用 UNION (如果允许,尽量用 UNION ALL)代替 OR。

Union 会对查询结果进行重新排序,因此其查询效率要低于 Union All; 但是 Union 会去除重复行,而 Union all 则不会。 因此需要根据实际情况来决定最终应该采用哪一种方法。 在索引列上不要使用’<>’ 索引只能找到“是什么” 不能找到“不是什么”

11. >=(<=) 效率高于> (<)

Select agentcode,name from laagent where agentstate<’03’可替换为 Select agentcode,name from laagent where agentstate<=’02’ 尽量避免使用 like’%abc%’ 此种语法也会导致索引失效。

12. 尽量避免使用 like’%abc%’,此种语法也会导致索引失效。

使用COUNT(1)来判断记录是否存在;

13. 尽量用 EXISTS 代替 SELECT COUNT(1)来判断记录是否存在;

COUNT 函数只在统计表的行数时 使用,而且 COUNT(1)比 COUNT(*)更有效率。 避免在索引列上使用函数,函数、算术运算或其他表达式,运算尽量放在“ 尽量放在 右边。

14. 避免在索引列上使用函数,函数、算术运算或其他表达式,运算尽量放在“=”右边,否则 可能无法正确使用索引。

例:select * from lccont where trim(conntno)=’123456’,此时不会使用建在 contno 上的索引。 例:应避免使用 Select * from lacommision where branchtype=’1’ and wageno=’200901’and agentcode=’1100D01001’and (transmoney-100)=1000 此种 写法;如换成“transmoney=1000+100”或“transmoney=1100”会更好。 值得注意的是在 ORCLE 的语法中,还需要避免对隐式转换的使用,例如:select * from lccont where contno =123456,此时不会使用建在 contno 字段上的索引,该语句的效率 会明显低于 select * from lccont where contno =’123456’。子句的写法,必须考虑语句顺序,应根据索引顺序,

15. 注意 WHERE 子句的写法,必须考虑语句顺序。

应根据索引顺序,范围大小来确定条件子句的 先后顺序,尽可能的让字段顺序与索引顺序一致,范围从大到小。 先后顺序,尽可能的让字段顺序与索引顺序一致,范围从大到小。Where 条件总是从后向前 执行。 执行。

例: 范围大小顺序为:branchtype>managecom>agentcode。那么 select name from lagent where branchtype=’1’and managecom=’861100’and agentcode=’1100D01001’会比 select name from lagent where agentcode=’1100D01001’and managecom=’861100’and branchtype=’1’的效率更高。 复合索引中,尽量使用前导列(索引第一列) 复合索引中,尽量使用前导列(索引第一列) . 例:表 test 含有 A、B、C、D 四个字段,并在 A、B 列上建立了复合索引 TEST_1,其中 A 为 前导列,那么 select * from test where A=’12’and B=’23’或者 select * from test where A=’12’都会使用该索引,而 select * from test when B=’23’则无法使用该索 引。 子据来做剔除行的操作。 来做剔除行的操作

16. 尽量不要用 GROUP BY 和 HAVING 子据来做剔除行的操作。

一般在 WHERE 子句时就能完成剔除行的操作,对于大的数据行进行 Group By 和 Having 都 十分消耗资源。 执行顺序应该如下最优:Select 的 Where 字句选择所有合适的行,Group By 用来分组和统 计行,Having 字句用来剔除多余的分组。这样 Group By 和 Having 的开销小、查询快。 如果 Group BY 的目的不包括计算,只是分组,那么多数情况下用 Distinct 更快。 减少不必要的排序操作。

17. 减少不必要的排序操作。 能采用批处理尽量采用批处理。 批处理尽量采用批处理

18. 能采用批处理尽量采用批处理。

一次更新或查询多条记录比分多次、每次更新或查询一条更快。主要是节省了与数据库通 信的时间,数据量越大效果越明显。 不要在一句话里再三的使用相同的函数,浪费资源,将结果放在变量里再调用更快。


19. 不要在一句话里再三的使用相同的函数,浪费资源,将结果放在变量里再调用更快。

例:假设一条 SQL 中有多处用到 formatdate(‘2009-01-02’,’yyyymm’),那么可以先 通过一次查询获得其对应的值 ‘200901’ 再将取得的值‘200901’ , 以变量的方式传入到 SQL 语句中。这样有时效率会高。 在向库表中写入数据时,最好先对字符串前后的空格进行处理。

20. 在向库表中写入数据时,最好先对字符串前后的空格进行处理。 可以有效减少后期查询等操作时使用 Trim 函数的可能性。

 

原文地址:https://www.cnblogs.com/avivaye/p/2851436.html