这本书《心兽》是在上学时读的,今天随手翻到以前的摘录,在此一记。

作者赫塔·穆勒(Herta Müller)1953年出生于罗马尼亚,1987年开始定居德国,2009年拿到诺贝尔文学奖。

每朵云里有一个朋友,

在充满恐惧的世界里朋友无非如此,

连我母亲都说这很平常,

别提什么朋友,

想想正经事吧。

如果我们沉默,别人会不舒服,埃德加说,如果我们说话,别人会觉得可笑。

独裁者是个错误,死去的人对这句话的体会也许跟我们的不一样,埃德加说。

萝拉从南边来,从她身上可以发现一个没有脱贫的地域。我不知道从哪里,或许从颧骨上,嘴边,眼睛里。这种事说不清道不明,一个地域也罢,一张脸也罢。这个国家每个地方都没有脱贫,每张脸上也一样。可是萝拉来的地方,一如人们从她的颧骨、嘴边和眼里所看到的,也许更穷一些。地域多于风景。

贫瘠吞噬了一切,萝拉写道,除了羊,瓜和桑树。

怀揣着白衬衫的梦想,萝拉得追逐,得逃跑。这梦想即或在最幸福的时刻也还是和她脸上的地域一样贫瘠。

他们将恐惧换成了疯狂。

我父亲,格奥尔格说,带着自行车去火车站,这样,去的路上就不必紧挨着我走,回家的路上也不至于手里空落落的,感觉踽踽独行的味道。

使用Sql Server也快有一年了,本来是不想在这个数据库上纠结太多的,但是由于工作的需要还是浅浅地学了一点,有几点体会。

1. Sql Server 的临时表

当我刚开始接触Sql Server的时候,看着别人写的SP代码,发现好多以#开头的表(如这样的#TMP_Customer_L1M),后来才知道,这就是Sql Server的临时表。这种临时表使用很灵活,主要是创建方便(直接select ... into #tmp_table from ...就创建成了),操作速度快(SQL Server的临时表是放在内存中的,从这点也可以体会出“SQL Server很喜欢吃内存”这点),使用起来和使用变量有相通之处。我感觉Sql Server与Oracle的临时表除了名字一样,其它的相同点少得可怜,他们的不同之处可以看文章《Oracle临时表和SQL Server临时表的不同点对比》(更多从技术角度来分析),以及《临时表在Oracle数据库与SQL Server数据库中的异同》(结合业务来分析),还有一个视频《Comparing Temporary Tables in Oracle and SQL Server

2. Sql Server的内置函数

这一点我其实就是想吐槽的。它的内置函数是在是少啊,功能不够用啊,需要处理略复杂的逻辑时就很痛苦。当需要取某月的第一天时,好怀念Oracle的这种写法:

 SELECT TRUNC(SYSDATE,'mm') FROM dual;

在Sql Server里需要自己去做加减法来得到本月的第一天,在社区里被顶得最多的写法如下:

SELECT DATEADD(month, DATEDIFF(month, 0, @mydate), 0) AS StartOfMonth

还有Sql Server的对正则表达式的支持实在太差,相比于Oracle的REGEXP_LIKE(), REGEXP_SUBSTR(), REGEXP_INSTR(), REGEXP_REPLACE()正则表达式函数,SQL Server表示它一无所有(好像最接近的函数就是PATINDEX了,但是它只能查找,功能也弱),但是它提供了CLR(Common Language Runtime),可以通过调用.NET来实现正则的相关处理(这个没有研究过),或者自己建几个基础的正则表达式函数(这个就是在重复造轮子),再或者就是想出各种曲折的算法来达到相同的目的。

还有Sql Server分析函数功能也弱,没有Oracle的Family Tree函数,等等,总体感觉和Oracle的内置函数比起来,Sql Server还有很长的路要走啊,使用太不方便了!

3. Sql Server的死锁

之前我知道死锁,但是是Sql Server让我认识到了数据库里的死锁。刚接触时,同事就告诫说引用表时记得要在后面加上WITH(NOLOCK),虽然会有脏读的可能性,但是在我们目前这个系统出现的可能性极低,所以做ETL时都会加上这个hint。本来我对这个问题认识估计也就停留在此了,直到最近要编写完ETL调度的脚本时,面对多并发的情况,频繁发生死锁,我才学了一些关于Sql Server锁的相关知识,见此文

关于Sql Server的锁的介绍可以看官方文档或这篇文章《T-SQL查询进阶—理解SQL Server中的锁》的介绍。

查看锁可以通过使用sys.dm_tran_locks这个DMV或者用Profile查看器。用锁锁定的对象可以从行到数据库。

Sql Server的锁大致分为几种:

  • 共享锁(S锁):用于读取数据时所加的锁,默认是读取前加共享锁,读取完一行就释放。共享锁之间不互斥;
  • 拍他锁(X锁):用于修改数据,排斥其他所有的锁;
  • 更新锁(U锁):相当于是S锁+U锁,用于更新;
  • 意向锁(IS,IU,IX):SQL Server锁定一个粒度比较低的资源时,会在其父资源上加上意向锁,告诉其他查询这个资源的某一部分已经上锁。

可以看到Sql Server对于查询一般是要加共享锁的。

下面讲讲死锁,死锁的发生有几个条件:资源的互斥性(mutual exclusion);占有并等待(hold and wait);不可剥夺(no preemption);循环等待(bounded waiting)。

死锁的处理:当Sql Server发生的死锁被检测到时,系统会自动决定终止其中一个进程让其它进程可以继续执行下去,被中断的进程会报错1205的错误,如下。

deadlock

死锁的预防正是程序员所要考虑到的问题。如何将死锁减至最少,官方文档里有提供一些建议:

  • 按同一顺序访问对象
  • 避免事务中的用户交互。
  • 保持事务简短并处于一个批处理中。
  • 使用较低的隔离级别。
  • 使用基于行版本控制的隔离级别。
    • 将 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON,使得已提交读事务使用行版本控制。
    • 使用快照隔离。
  • 使用绑定连接。

官方文档中有对这些建议的详细解释。

对于锁,Sql Server提供了一些Hint,可以用来在程序中人工干预锁的一些属性,官方文档里有详细介绍。