写在最前
最近复习了下SQL Server的知识点,之前都是在做项目的时候依靠经验来添加索引设计表结构来进行数据库的构建。省事是省事了,但是非常不安全也不易于维护,很容易留下坑。想着能抽出时间具体研究一下数据库原理,怎么根据业务去科学地设计数据库模型,添加索引等等。看书是最系统学习知识的方法,看总结帖是最快吸收知识精华的方法,具体怎么学习我就不介绍了。
总述
SQL Server 性能优化主要可以从语句的优化以及索引的建立考虑,另外的还有,表结构的设计优化等。
具体分析
写出好SQL语句
先从最基本的说起,写出“好”的SQL语句,那么怎么样的SQL语句算是好的SQL语句呢?
从三个方面来说,首先牢记SQL语句执行顺序。
以查询的SQL执行顺序举例:
(1) FROM < left_table>
(3) < join_type> JOIN < right_table> (2) ON < join_condition>
(4) WHERE < where_condition>
(5) GROUP BY < group_by_list>
(6) WITH {cube | rollup}
(7) HAVING < having_condition>
(8) SELECT (9) DISTINCT (11) < top_specification> < select_list>
(10) ORDER BY < order_by_list>
数据库中执行的顺序如下
1.FROM:先对FROM子句中前两个表执行笛卡尔积生成虚拟表结果vt1
2.ON:对vt1表应用ON筛选器只有满足< join_condition> 为真的行才被插入vt2
3.JOIN:如果指定了 OUTER JOIN保留表(preserved table)中未找到的行将行作为外部行添加到vt2 生成t3,如果from包含两个以上表则对上一个联结生成的结果表和下一个表重复执行步骤和步骤直到结束(vt2与下一个表笛卡尔积再次生成vt1插入vt2...循环)
4.WHERE:对vt3应用 WHERE 筛选器只有使< where_condition> 为true的行才被插入vt4
5.GROUP BY:按GROUP BY子句中的列列表对vt4中的行分组生成vt5
6.CUBE|ROLLUP:把超组(supergroups)插入vt6 生成vt6
7.HAVING:对vt6应用HAVING筛选器只有使< having_condition> 为true的组才插入vt7
8.SELECT:处理select列表产生vt8
9.DISTINCT:将重复的行从vt8中去除产生vt9
10.ORDER BY:将vt9的行按order by子句中的列列表排序生成一个游标vc10
11.TOP:从vc10的开始处选择指定数量或比例的行生成vt11 并返回调用者
因此在数据库要注意以下几种情况:
1.以批量代替循环:避免使用in,not in 会产生大量的循环遍历,游标的执行效率特别低下,尽量避免使用。应用上也要避免循环向数据库做请求,合并请求。使用Union All 替代 Or
2.降低语句复杂性:如果有大量表进行联结查询的话,可以讲部分业务关联表插入临时表,使用临时表代替这些表进行联结。(在笛卡尔积时可以增加效率),只返回需要的字段数据,避免使用*
3.避免重复读取:如果有重复查询的数据结果,然后再做处理,可以放在一起处理,比如说同时对一份用户信息做多方面的用户分析等。
4.尽早筛选,不要把筛选条件写到having里
5.事务操作过程要尽量小,能拆分的事务要拆分开来。
建立索引
索引是数据库性能优化最常用的一种方法了,那么有什么科学建立索引的规则吗?
1.最简单的方法,sql server 执行语句的执行计划中会对语句进行索引建议。
2.索引查找一般为最优查找,可以将查找条件建立一个组合索引(最好包括查询字段),但是需要注意的是索引列不能带函数,不能参与计算,不能有隐式转换。
举个例子:userid(varchar) = @id(nvarchar) 包含隐式转换无法使用索引,userid = @id - 2 包含计算无法使用..
3.根据执行计划创建,检查语句主要的消耗在哪里,优化语句。
表结构优化
表的设计结构需要基本符合三范式:
第一范式:属性(字段)的原子性约束,要求属性具有原子性,不可再分割;
第二范式:记录的惟一性约束,要求记录有惟一标识,每条记录需要有一个属性来做为实体的唯一标识。
第三范式:属性(字段)冗余性的约束,即任何字段不能由其他字段派生出来,在通俗点就是:主键没有直接关系的数据列必须消除(消除的办法就是再创建一个表来存放他们,当然外键除外)
但是,数据库设计应该在数据冗余和处理速度之间找到合适的平衡点。所以我们可以适当的冗余,增加计算列等。
如果表过大需要考虑分割表:对于数据量较大的表进行水平分表,对于列数较多的表进行垂直分表分成2个或以上
另外还有字段的设计,字段是数据库最基本的单位,其设计对性能的影响是很大的。需要注意如下:
A、数据类型尽量用数字型,数字型的比较比字符型的快很多。
B、数据类型尽量小,这里的尽量小是指在满足可以预见的未来需求的前提下的。
C、尽量不要允许NULL,除非必要,可以用NOT NULL+DEFAULT代替。
D、少用TEXT和IMAGE,二进制字段的读写是比较慢的,而且,读取的方法也不多,大部分情况下最好不用。
E、自增字段要慎用,不利于数据迁移
写在文末:
文章总结的过程中参考了SQL专家云团队成员以及CSDN、博客园等论坛的优秀博文,感谢各位程序员前辈们的知识分享。