希望这期不要掉粉,因为在说SQL SERVER 但实际上这期如果你放到所有的数据库上去看,也是有营养的,虽然放到了一般不会发文的周六,也没想有多少观众,就当自己对某些东西的回顾和反思。
先说问题,最近的SQL SERVER 内存消耗的厉害,在这之前是建立了一堆的索引,来提高查询的效率,内存的使用也在悄然的上涨.
一般来说,数据库有需求是正常合理的需求,就应该给,大部分人的第一反应,是不是有慢语句,是不是有消耗内存的东西在运行,是否应该优化或杀死。
语句当然要优化,索引当然要加,但过度的优化和大量的索引走向的就是另一个极端。SQL SERVER 本身与其他的 ORACLE ,POSTGRESQL ,MYSQL 三个传统数据库在内存的管理方面是比较“放羊”方式的管理,你安装后最大内存和最小内存都是不用设置的,系统会自动的进行处理。
其实这里有两个矛盾点,这在其他的数据库上也是存在的
1 防止buffer变得过大,以至于系统的内存不足
2 通过最大化缓冲池来最小化数据库文件频繁在I/O和内存中频繁的交换
这是放到大部分数据库都应该能被认可的一个点, 在一个负载过重的系统上,大型的查询无法获得所需要的内存的最小量,带来的就是处理这个SQL 的等待,而如果此时你的数据库还支持并行,POSTGRESQL ORACLE SQL SERVER ,等都支持并行,此时的并行对于大型的查询并不会好到哪里去,而会让事情变得更糟糕,因为我本身内存不足,而你要并行处理,内存就更加的不足,加速I/O的压力。
所以搞清楚到底是内存不足或软件的设计上有问题,这两件事情就被提到了台面上。个人倾向在目前硬件的价格较低的情况下,尽量的去添加硬件,而软件的某些架构和处理方式要改变是很难的,这和很多事情都有关,这里就不展开了。
在SQL SERVER 中如果得不到足够的内存,则查询可能会走另外的执行计划,并且会占用TEMP库(物理I/O)的方式处理,而性能就会走向另一个极端。
现在回到上面的那个问题,一个SQL 如果他执行的快,就说明很好,这样的想法对不对,个人认为,to young to simple。
我会从以下维度来考虑一个SQL 到底OK 不OK
1 执行时间,这当然的考虑, 否则你的客户就要投诉你了
2 每个SQL 占用的内存(我会对一些复杂的SQL 来看看到底会占用多少内存,怎么看后面说)
3 SQL 的复杂度,如果一个SQL 本身很复杂,那就要拆
关于第三个问题可能马上就有人问,我就喜欢写复杂的SQL 我又没有用MYSQL ,ORACLE SQL SERVER 不就是让人写复杂SQL 的,通过一个SQL 来解决复杂的逻辑,不是一件好事情。
实际上这的两面看,的确一个SQL 能解决的问题,换成多个SQL 来解决,效率上可能还真的是一个SQL 可能占有优势,(实际上也不尽其然,很多情况拆开运行倒是比写一个上百行的SQL 要快),但一般这样想的人,都没有一个并发的感念和想法,你的一个SQL 运行下去,会不会在单位时间里面多次重复运行,那他们要占有的资源很可能就重叠了,那重叠会怎么样,锁呗,死锁呗,锁等待呗,各种latch 锁呗。 所以SQL 的复杂度和并发本身就是一个矛盾体,放到其他数据库也是一样。
另外一个SQL 执行的快慢,他不是固定的,和你的天时地利人和(其实就是资源,并发,单位时间)是绑定的,而机器的资源可是动态的,所以一直强调语句要多少秒执行出来的做法,你的前提是,资源可别短人家的,并且系统的并发到底高不高,执行的频率是多少,等等问题,而一味要求一个SQL 要多少秒出来,前边的事情不想,后面的要求就很难达到。
下面是一个数据库的占用内存的情况,可以看到有的表的主键占用的内存都已经达到G级别,在证明这个系统很繁忙的情况下,也是能分析出一些其他的问题。
另外一个事情,SQL SERVER 本身是不会乱分配内存的,如果它达到了某个更高的内存消耗标准,自然会申请获得更多的内存,所以想限制内存的使用只能是徒劳的行为,最后用磁盘模拟内存那结果也是相当的好看,你可以查看一个数据库中某个线程的SQL占用内存的情况,下面这个语句占用的内存就被捕捉到了,所以在看一个语句的占用CPU 时间,逻辑扫描数,物理扫描数,还是要关心一下内存的使用情况。
其实在考虑一个SQL 是不是更快的时候,时间的节省,可能带来的就是空间的损失(这里不光指的是内存),所以还是那句话,空间换时间,时间换空间,在每种数据库上都是可以找寻的一句“金句”。在硬件性能不足的情况下,在怎么优化语句也是徒劳,同时在强悍的硬件,也架不住某些SQL。