SQL Server中的重要观点

以下为重要观点:

1、通过把数据库设置成读已提交快照,在read committed隔离级别下,读不会阻塞写,写也不会阻塞读,通过尝试这个观点是正确的。

2、当连接1请求了共享锁,2请求了独占锁,3请求了共享锁,4请求了更新锁时,这四个请求都会进入锁的请求队列中,书上说SQL Server的锁队列,基本上是按照先进先出的规则,但是会考虑锁的兼容性,所以这个时候可能1、3、4这3个请求的锁是兼容的,所以这3个请求会先处理,这个得尝试一下




一个优化方面的重要的观点

网友的提问:
大牛们,加了一个or,为什么执行计划由哈希匹配变成嵌套循环?http://bbs.csdn.net/topics/390599501

select count(*) from t1 where a1='1' and a2 in(select a2 from t2)


select count(*) from t1 where a1='1' and (a2 in(select a2 from t2) or a2='2')

表t1超过100万条数据,语句1执行时间为1秒,语句2超过80秒,请问为什么,语句2该怎样修改?


下面是我的回答:

建议把查询改写成关联的,inner join或者是left join,其实要想明白,为什么加了a2='2'后,执行计划变化了,这个很难,因为这个是由SQL Server的优化器决定的,我们很难猜测优化器在一堆的判断当中为什么选了nested loop 而不选hash join。

但如果你写成inner join或者left join的时候,如果速度不佳,你可以通过添加查询提示,比如hash:inner hash join

其实本质上就是手动给SQL Server的优化器建议,建议他采用hash join,之所以微软会提供这种查询提示,就是已经预料到会有你所遇到的问题,所以才提供了这种可以由你来进行微调的技术。


 

下面是一个关于数据库设计的观点

下面是网友的一个问题:http://bbs.csdn.net/topics/390631703?page=1#post-395959332

关于仓储系统的方案设计,以下为现有仓库表的设计(部分表):

TAB/装车单:
字段:(装车单号,仓库ID,仓库编码,仓库名称,...创建人NAME,创建时间,修改人NAME,修改时间...)

TAB/装车单明细表:
字段:(装车单号,货物ID,货物名称,...创建人NAME,创建时间,修改人NAME,修改时间...)


TAB/采购单:
字段:(采购单号,...创建人NAME,创建时间,修改人NAME,修改时间...)

TAB/采购单明细表:
字段:(进货商ID,进货商NAME,采购部门ID,采购部门NAME,...创建人NAME,创建时间,修改人NAME,修改时间...验货人NAME,验货时间)

 

首先这个不我设计的,我觉那个人这样的设计的好处就是为了查询方便(不用做关联查询嵌套查询什么的就能获得要的数据),但是一旦部门名称或者管理员名称(即便可能不修改 但不是绝对的)等等会影响到所有使用这些数据的表。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
我的解决方案

我看到这个库时候感觉里面太多太多的表都都是这样的,举个最明显的例子,创建人NAME 好多表都存的是 管理员的NAME 而非ID。

我觉的除了把管理员NAME之类的删除,都换成外键。除此 像装车单里的仓库编码、仓库名称、等;装车明细表里的货物名称;采购单明细里的采购部门NAME,进货商NAME都统统删除 只保留引用的外键ID进行设计

之所以这样修改是为了解决数据冗余问题,但后期在查询数据时候会涉及更多的嵌套查询关联查询才能解决。不知道各位老虾怎么看我这样的处理方案或者给个更好的意见,多谢
===============================================================================

 

下面是我的回复:

其实,你对于表的修改意见,是有道理的。

因为,关系数据库系统,在设计时,有所谓3NF,一般都要达到这个第三范式,这样能够减少数据的冗余。

而且,实际上不仅能够减少冗余,而且这样做的好处是由于是通过外键来引用基表的id,修改也方便了,

比如,当你的仓库名称变化了,你只需要去修改,这些业务表所引用的,基表里面的仓库名称。

而你们公司现在的系统,如果你有10个业务表,都有仓库名称这个字段,一旦只要有一个仓库的名称变化了,那么你就得通过仓库编号,来连接基表,然后再update这10个表的仓库名称,那是非常麻烦的。

应该说,你们公司现在系统的数据存储方式是采用了反向规范化,也就是冗余化存储。

你希望采用规范化,而你们公司原来的系统采用的是范规范化。

规范化的好处上面说了,就是减少数据冗余,修改非常容易。
而反向规范化的好处,就是不用子查询,或者关联多的表,查询的性能会好。

总结:
我觉得到底采用哪种方式,这需要你自己权衡,如果你的系统,很少有更新仓库名称,也就是很少更新这些基表数据,那么为了提高查询的性能,而且也不用每次写查询,关联N多基表,那么就还是采用原来的方式。这种方式,在互联网的应用中比较多,传统的业务用的不多。

如果系统中会更新这些仓库名称,那么还是建议采用外键id的方式,来修改这些表的设计,当然啦,语句可能得写的比较复杂,因为我原来的公司就是都采用外键id的,由于这种外键很多,公司设计了一个字典表,

比如:dict_table 里面存放了几乎所有的外键id,所引用的id,那么我们公司有一个store表,里面有一堆的id,上面渠道id,公司id,组织id,经销商id,层级id,性质id等,于是乎,为了取得这些客户的渠道、公司、组织、经销商、层级、性质,就得关联dict_table 至少6次,也就是

select 字段列表
from store
left join dict_table
left join dict_table
left join dict_table
left join dict_table
left join dict_table
left join dict_table

就是这样,经常一个查询,得关联10-15个表左右,语句写的非常复杂。

所以,呵呵,最后还是得楼主,按照你们公司的特殊情况,业务特点,来选择,到底是去除冗余,或者是去除部分冗余。



还有下面的,关于数据库设计的:

我也试了,如果把数据拆分成列,那么到时候,比如:属性-值,拆分成2行数据,一行存属性,一行存列,
这样看上去倒是好一点,但是在查询的时候,还是得行转列,比较麻烦。


其实设计表,就是得考虑:性能,业务,占用存储,开发速度。

我原来的公司,需要非常快的开发速度,于是,就把不同业务的数据,放到一个表中,通过增加一个func_code字段,来区分是不同功能产生的,然后后面是一堆字段,A业务用xx字段,B业务用yy字段,其他都是空着的,这样的话,非常方便开发,在理解业务的时候,也很容易,不同业务,用不同的字段。

但是,如果你不懂业务,就会很迷惑,看不懂,怎么一眼看过去,一堆没用的字段放在那儿,全是null。

也想过拆分,但是这样也麻烦,就是刚才说的,开发的难度就上去了,而且性能也不会太好,因为你得做动态的行转列,每个业务用到的字段个数,和字段名称,都不完全一样,这可非常的麻烦。

所以,你一开始想的还是对的,这种表的设计,虽然看着,有很多null值,但是开发上就比较容易,性能也不错。



关于通过游标和循环的方式来处理数据的问题:


其实用循环和游标,之所以对性能有影响,根本的原因在于,处理数据的方式,也就是取出1条数据,然后处理,处理完成后,再取出下一条,

如果你的表有1000w条数据,那么就得循环1000w次,效率肯定是非常低的。

同样的,如果单纯的sql语句,之所以性能相对较好的原因在于,他是以集合为单位来处理数据,也就是批处理,一次能把所有的数据都处理好。

当然,有时候,由于业务逻辑非常复杂,可能需要写多个语句,每个语句先把中间的结果插入到一个临时表中,然后最后再对临时表进行处理,这也是一个变通的办法,但尽量不要用游标或者是循环来处理数据,因为效率比较低。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值