Category Archives: SQL Server

How to setup linked servers for SQL Server and Oracle 64 bit client

Problem We have two SQL 2005 64-bit clusters in our organization:  a four-node production cluster and a two-node dev/test cluster.  We recently migrated a database from SQL 2000 that relied on an Oracle linked server for some of it’s computations.  No big deal, right?  Install the Oracle client software and create the linked server just like in SQL 2000 right?  Be sure to repeat the process on both nodes for failover-sake, right?  Wrong.  In the case of 64-bit SQL instances we have a few extra steps we need to take to get an Oracle linked server configured and working properly.

Solution 64-bit computing is coming of age.  In most cases, our installation and configuration processes do not change from 32-bit to 64-bit: setting up logins, creating SQL Agent jobs; nothing inherently different there.  Inconsistencies do exist however.  Take for example linked servers – more specifically linked servers to Oracle databases.  In 32-bit environments we simply install the Oracle client software, create the linked server, add remote logins and move on to the next project.  In the 64-bit world the process is slightly more difficult – and in the case of one critical step it impacts any existing users on the instance!

Process Creating Oracle Linked Server on a 64-bit SQL Instance:

  • Install Oracle 10g Release 2 64-bit client software (available from Oracle website)
  • Install Oracle 10g Release 2 64-bit ODAC software (available from Oracle website)
  • Restart SQL services
  • Configure OraOLEDB.Oracle provider
  • Create linked server
  • Add remote logins for linked server

The complete process is presented below:


Step One:  Installation of the Oracle 10g Release 2 64-bit client software

I will leave it up to you to secure the software by either download from their site or media available via any licensing agreements you may have with Oracle.  The important steps are outlined below.  You only need the barest install of the client.  Simply go ahead and select the InstantClient option from the opening dialog form and click Next.

The following screens simply require you to click Next when enabled.  These are in place to present the internal checks and summaries of work to be completed once you accept the install parameters.  Proceed through the screens, click Install, and then Finish once the installation is complete.


Step Two:  Installation Oracle 10g Release 2 64-bit ODAC software

Once you have an installed 64-bit Oracle Home you can proceed with installing the ODAC drivers for a 64-bit environment.  The OraOLEDB.Oracle driver installed in this step is what you need to set up your linked server.  You’ll find the setup.exe for this installation located in the unzipped Install folder.  I strongly suggest you review your previous installation of the client software via selecting the Installed Products button.  You want to verify that you have a valid 64-bit Oracle Home that you’ll be installing against during this process.  We would not be DBAs if we were not overly cautious.  It’s quite Darwinian:  the brash and risky don’t last long as Database Administrators.

If you accepted the defaults during the client installation, your “Installed Products” Inventory should appear as follows.  If so, then close the dialog and click Next to continue.  If not, then I suggest you revisit your installation of the client software, possibly de-installing and performing all steps presented previously once again.

We will be installing the OraOLEDB.Oracle driver that is included in the Oracle Data Access Components option below.  Select Next to continue.

Using the drop-down box provided, select the existing Oracle Home you just verified was created as a part of your 64-bit Oracle client installation.  The Path will automatically change accordingly.  Continue by clicking Next.

You will be presented with the following sub-components.  I’ve selected all three (you never know when these items may be useful and they are extremely lightweight) though you only really need to install the first two items.

If you do decide to install the Oracle Services for Microsoft Transaction Server component, you’ll be prompted for the port number to use.  The default is 2030.

Click Next and you’ll be presented with the familiar summary screen, listing all components to be installed.  Review, make changes if necessary and then click Install.  Once completed we can move back to familiar territory:  SQL Server Management Studio.


Step Three:  Restart SQL Service

This is the most unfortunate step in the entire process.  This is usually the last thing a DBA wants to do.  It is the option of last resort whenever there is an issue on a SQL Server instance.  However, it is necessary in this case, so be sure to follow your corporate procedures for downtime notifications and process.  That being said, let’s move past this horrid step!


Step Four:  Configure OraOLEDB.Oracle provider

I confess.  I was not aware of this process existing until I had to do this the first time.  In Object Explorer, navigate down the tree of the SQL instance we’ve been working with until you’re able to view the list of Providers under Linked Servers.  Select OraOLEDB.Oracle and right-click.

SQL Server Management Studio.

The Provider Options dialog box appears.  Enable the “Allow inprocess” option and close the dialog.  Now ask yourself:  “Self, what did I just do?  Some Internet Guy said click this and it will work.”  Let’s take a quick look at exactly what enabling this option does for a provider.  By default, OLE DB providers are instantiated outside of the SQL Server process.  While this protects SQL from any OLE DB errors, Microsoft SQL Server requires that the OLE DB provider run in-process for handling BLOB-ish data types (text and images).


Step 5:  Create Linked Server and Add Logins

Finally, something we’re all familiar with.  The T-SQL is simple, and identical to the 32-bit platform.

--Create the Oracle Linked Server:  EXEC sp_addlinkedserver @server, @srvproduct, @provider, @datasrc
--For example: If I want to create a linked server called LK_TIPS to the ORATIPS  --database on the SRVORA1 server, listening on the default port of 1521 my query  --would look like this: EXEC sp_addlinkedserver 'LK_TIPS', 'Oracle', 'OraOLEDB.Oracle', 'SRVORA1:1521/ORATIPS'

A quick explanation about the @datasrc parameter.  Since our environment is clustered I do not like relying on an Oracle TNSname.ora file for our connection information.  It is far cleaner to specify the data source in terms of the SERVER:PORT/DB_NAME format.

As for creating an associated login the format is:

–Create the Remote Login for the Oracle Linked Server: EXEC sp_addlinkedsrvlogin @rmtsrvname, @useself, @rmtuser, @rmtpassword

Briefly, the @useself parameter determines whether the current user in connects to the linked server source under its current context or via impersonation.  By setting the value to FALSE you’re stating that you wish to connect to the linked server with a supplied login/password combination that is being identified in the @rmtuser and @rmtpassword parameters respectively.  A value of TRUE would suggest that a login will use it’s own (current) credentials to connect to the linked server.

Creating a login for the LK_TIPS linked server we just created with a login of ‘sa’ and a password set to ‘password’ would look like this:

EXEC sp_addlinkedsrvlogin ‘LK_TIPS’, ‘FALSE’, ‘sa’, ‘password’

Before you get any crazy ideas, I don’t suggest using sa/password as a combination for any system!

 

Next Steps

  • Tweak T-SQL code provided to fit your environment
  • If this is being configured in a cluster, be sure to install the Oracle client and ODAC components identically on all nodes in the cluster.
  • Review related tips on linked servers on MSSQLTips.com.

from:http://www.mssqltips.com/sqlservertip/1433/how-to-setup-linked-servers-for-sql-server-and-oracle-64-bit-client/

SQL Server锁粒度和锁模式

锁粒度和层次结构

Microsoft        SQL Server 数据库引擎具有多粒度锁定,允许一个事务锁定不同类型的资源。 为了尽量减少锁定的开销,数据库引擎自动将资源锁定在适合任务的级别。 锁定在较小的粒度(例如行)可以提高并发度,但开销较高,因为如果锁定了许多行,则需要持有更多的锁。 锁定在较大的粒度(例如表)会降低了并发度,因为锁定整个表限制了其他事务对表中任意部分的访问。 但其开销较低,因为需要维护的锁较少。

数据库引擎通常必须获取多粒度级别上的锁才能完整地保护资源。 这组多粒度级别上的锁称为锁层次结构。 例如,为了完整地保护对索引的读取,数据库引擎实例可能必须获取行上的共享锁以及页和表上的意向共享锁。

下表列出了数据库引擎可以锁定的资源。

资源 说明
RID 用于锁定堆中的单个行的行标识符。
KEY 索引中用于保护可序列化事务中的键范围的行锁。
PAGE 数据库中的 8 KB 页,例如数据页或索引页。
EXTENT 一组连续的八页,例如数据页或索引页。
HoBT 堆或 B 树。 用于保护没有聚集索引的表中的 B 树(索引)或堆数据页的锁。
TABLE 包括所有数据和索引的整个表。
FILE 数据库文件。
APPLICATION 应用程序专用的资源。
METADATA 元数据锁。
ALLOCATION_UNIT 分配单元。
DATABASE 整个数据库。

锁模式

锁模式 说明
共享 (S) 用于不更改或不更新数据的读取操作,如 SELECT 语句。
更新 (U) 用于可更新的资源中。 防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。
排他 (X) 用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。 确保不会同时对同一资源进行多重更新。
意向 用于建立锁的层次结构。 意向锁包含三种类型:意向共享 (IS)、意向排他 (IX) 和意向排他共享 (SIX)。
架构 在执行依赖于表架构的操作时使用。 架构锁包含两种类型:架构修改 (Sch-M) 和架构稳定性 (Sch-S)。
大容量更新 (BU) 在向表进行大容量数据复制且指定了 TABLOCK 提示时使用。
键范围 当使用可序列化事务隔离级别时保护查询读取的行的范围。 确保再次运行查询时其他事务无法插入符合可序列化事务的查询的行。

 

RAID的概念和RAID对于SQL性能的影响

简介

我们都听说过RAID,也经常作为SQL DBA、开发人员或构架师在工作中讨论RAID。但是,其实我们很多人都对RAID的原理,等级,以及RAID是如何影响SQL Server性能并不甚了解。

本篇文章就是为了补上这一课。

 

磁盘构架

今天的磁盘,和70年代45rpm(转/分钟)的唱片机很像(你还能记得吗?),仅仅是一个有着轴(磁道)旋转的媒体(面)并将数据存入称之为扇区的磁盘段。

就像唱片机那样,磁盘驱动器拥有一个摆臂来控制针(在这里可以称之为”磁头”)来访问数据。但对于磁盘来说,并不像唱片机那样只读,而是既可以读又可以写。

为了从特定的扇区读或者写数据,磁盘必须进行旋转然后摆臂移动使得磁头移动到垂直于指定扇区的正上方以访问数据。

这个过程就是基本的输入/输出操作的过程(I/O)。

 

IOPS

IOPS这个术语也是被经常拿出来装X的,但同样,对这个术语真正理解的人并不多。

很多人都明白IOPS是Input Output Operations per Second的缩写,但是将这个定义转换为实际的概念对于某些人就有点难了。

对IOPS基本的理解是对满足特定输入输出请求的平均时间的一种衡量。

这里重点需要知道这个度量标准是基于读取0字节的文件,这仅仅是为了统计和标准化的目的因为一个磁盘扇区大小并不同。

 

物理磁盘的限制

磁盘会有一些物理限制会限制磁盘能达到的IOP级别。这个限制是磁道寻址时间(seek time)和旋转延迟(rotational latency)。

磁道寻址时间是为了使得磁头可以移动到所要读的扇区,移动摆臂所花费的平均时间。

旋转延迟是为了使磁头读取盘面特定位置旋转磁盘所话费的时间(通常为毫秒级)。

单位IOP所花的时间公式如下:

单位IOP时间=磁道寻址时间+旋转延迟

 

所以,通过这个公式我们就可以轻松计算给定磁盘的最大IOPS。

而每秒的IOPS数字也是我们最感兴趣的,公式如下:

1秒/磁道寻址时间+旋转延迟。

 

我们来看如下例子:

HP 300GB 15k SAS drive(200刀)
转速 15000
平均磁道寻址时间 2.9ms
平均旋转延迟 1.83ms

 

我们可以用公式计算IOPS了:

IOPS = 1/(2.9ms + 1.83ms)    = 1/(4.73ms)     = 1/(0.00473)    = 211 IOPS

 

    我们可以看到,这个磁盘的IOPS为211(并不是很惨)。

假如我们想要节省更多的钱,我们再来看一个磁盘的例子以及和上面磁盘的区别:

 

HP 300GB 7200 SATA drive(100刀)
转速 7200
平均磁道寻址时间 10ms
平均旋转延迟 2.1ms

 

通过公式可以看到这个磁盘的最大IOPS:

IOPS = 1/(10ms + 2.1ms)    =  1/(12.1ms)         =  1/(0.0121)         = 82 IOPS

 

    这个7200转的磁盘的最大IOPS为82。

通过对比可以看到上面两个磁盘的性能上的巨大差异,这也不难理解为什么同样的容量价格会差这么多。

此外,文档显示如果你使用磁盘到其IOPS峰值,会产生请求队列而造成延迟(一个在SQL Server中非常邪恶的词汇,像躲避瘟疫一样躲避它)。

而我看过的大多数文档建议IOP保持在最大IOPS的80%左右。所以我们上面讨论的第一个磁盘的最大IOPS是211如果服务于超过168的IOPS就会开始显出延迟的征兆了。

现在我已经知道了单独一个磁盘可以达到的IOPS数字,那么下一件事就是要满足生产环境下的SQL Server实例需要多少IOPS?

我获取这些数据仅仅通过在生产环境下查看PerfMon工具的physical disk: Disk Transfers/Sec 计数器。

这个数字是:

 

驱动 平均IOPS 最大IOPS
数据和索引 2313 16,164
日志 81.5 1,127
TempDB 141 2,838

 

通过上面的数据看到,我们的快速磁盘仅仅能处理168的IOPS,所以结论是一个磁盘无论如何也无法满足上面的IOPS要求。

所以解决这个问题的唯一办法是使用某种机制来调整多个磁盘满足上述需求。

如果我们有100个300GB 15k SAS驱动器,我们不仅获得了30TB的存储量,还获得了16800的IOPS。

如果我们使用前面例子中较慢的磁盘,为了达到16800 IOPS,我们需要205块这样的驱动器,这使得我们需要比使用快速磁盘花更多的钱($20,000 vs $20,500),听上去很讽刺,不是吗?

 

RAID的必要性

现在,我们需要一堆磁盘来满足我们的速度或是容量需求,所以我们需要某种机制来将工作负载加到多个磁盘,实现这个目的的主要手段就是RAID。         RAID代表”Redundant Array <of> Inexpensive Disks”(译者注:这是最开始的定义,后来行业标准将I改为Independant,难道这是因为Inexpensive这个词妨碍了他们收取更多的钱?),RAID提供了将一堆磁盘连接起来使得逻辑上变为1个的方法。

基于你如何串联你的磁盘,RAID可以提供容错性—当磁盘阵列中有一个磁盘崩溃时数据不会丢失。

此外,因为串联了多个磁盘,我们可以消除单个磁盘的IOPS限制,更多的磁盘意味着更多的IOPS,就是这么简单。

 

RAID级别

RAID只为了两个目的:1)通过提高IOPS提高性能  2)提供容错。更高的容错性意味着更低的磁盘性能,同样,高性能方案也会降低容错性。

根据容错性和性能的目标配置RAID就是所谓的RAID层级。RAID是对常用的RAID阵列的一种分裂,常见的RAID级别为:RAID0,RAID1,RAID5,RAID1+0,RAID0+1。

根据你对RAID级别的选择,你需要付出所谓的”RAID代价”。某些RAID级别需要重复写入两次数据来保证容错性,但这样会牺牲性能。此外,因为重复写入数据还需要更多的磁盘空间。RAID代价会大大提高你的RAID方案的成本。

为了明白RAID对于你的系统的影响和收益,熟悉常见的RAID级别和它们的实现原理变得非常重要。

 

RAID 0

第一个,也是最基本的RAID级别是RAID 0.RAID 0强调为了解决IO的限制而将数据写入到磁盘阵列中。如果IO希望写100MB的数据,RAID0会将100MB数据写入到磁盘阵列的每个磁盘中。

这种方式大大减少了每个磁盘的负载,并且减少了旋转延迟(每个磁盘不再需要转和原来一样的圈数就能满足请求)。

虽然RAID0大大提高了IO性能,但没有提供任何容错措施,这意味着如果磁盘阵列中的某一块磁盘崩溃,则整个磁盘阵列中的数据全部丢失。

因为RAID0并没有提供任何容错措施,所以在生产环境中RAID0几乎不被使用。

还有一点值得注意的是,由于RAID0磁盘阵列中的每个磁盘都用于存储数据,所以没有任何磁盘空间的损失,比如使用RAID0,10个300GB的磁盘就会有3TB的可用存储空间,这意味着没有损失磁盘空间的RAID代价。

 

RAID 1

RAID1也被称为”镜像”,因为其通过一个镜像磁盘来保证容错性。在镜像集中的每个磁盘都会有一个镜像磁盘,RAID 1写入的每一笔数据都会分别在两个磁盘中各写一份。这意味着任何一个磁盘除了问题,另一个磁盘就会顶上。用户的角度来看并不知道出现了磁盘崩溃。

RAID 1需要付出写入时的性能代价。每个写入IOP需要运行两次,但是对于读来说却会提升性能,因为RAID控制器对于大量数据请求会从两个磁盘中读取。

 

RAID 5

RAID 5也被称为”Striping With Parity)”,这种方式既可以通过磁盘分割(Striping raid0)来提高性能,也可以通过奇偶性(Parity)来提供容错,当一个磁盘崩溃后,奇偶数据可以通过计算重建丢失的数据。

虽然奇偶性是实现容错的一种不错的方式。但是从磁盘写入来说代价高昂。也就是说对于每一个IOP写请求,RAID5需要4个IOPS。

为什么需要这么高写入代价的过程如下:

  •     读取原始数据(1 iop)
  •     读取当前奇偶数据(1 iop)
  •     比较当前数据和新写入请求
  •     基于数据差异计算新的奇偶值
  •     写入新数据(1 iop)
  •     写入新的奇偶值(1 iop)

RAID 1+0

    RAID 1+0 和其名字所示那样,融合了RAID 0(磁盘分割)和RAID1(镜像)。这种方式也被称为:分割镜像。

RAID 1+0 由于将数据分割到多个磁盘中使得并且不像RAID5那样有奇偶效验码,所以写入速度非常快。

但写入速度还是会有影响因为需要重复写入镜像盘,但仍然,写入速度还是非常的快。

而对于RAID 1+0 存储的代价等同于RAID1 (镜像),在RAID1+0中只有一半的磁盘空间可以用于存储数据。

 

RAID 0+1

RAID 0+1 和RAID1 +0 是很像,它们都是通过磁盘分割和镜像来实现目的。他们的区别更加学术化,这里我们假设他们一样。

RAID 0+1和 RAID 1+0所付出的代价是一样的。

 

其它RAID级别(2,3,4,6,DP等)

还有一些其它不常见的非标准RAID层级,RAID 2,3,4,6和RAID DP都和RAID5类似,他们都是通过分割和某种奇偶校验来提供性能上和容错。这些类似RAID 5的RAID层级的区别仅仅是它们如何写入奇偶数据。它们之中有些是通过保留一个磁盘来存储奇偶数据,还有一些是将奇偶数据分布到多个磁盘当中等等。如果需要,你可以去做这些研究,但对于我来说,我都称它们为”RAID 5”

还有一个值得讨论的非标准的RAID级别是RAID DP,DP的是”Dual Parity”的缩写,这和RAID 5很像但其将奇偶数据写入两次,这对于写入来说代价高昂,写入代价被提高到了6(每一次IO写请求需要6 IOPS)

 

RAID 比较

选择合适的RAID层级并不容易,需要考虑多方面因素:成本,性能和容量。

下表总结了每个标准RAID层级的好处和坏处。

RAID Level Fault Tolerance Read Performance Write Performance RAID Write Penalty Cost
0 None Good Excellent 1 Excellent
1 Good Good Good 2 Fair
5 Fair Good Poor 4 Good
1+0 Excellent Excellent Excellent 2 Poor
DP Good Good Terrible 6 Good

 

SQL存储推荐

 

SQL Server文件 RAID级别
操作系统和SQL二进制文件 RAID 1
数据和索引 RAID 1+0 (如果预算不允许可以使用RAID 5)
日志 RAID 1+0
TempDB RAID 1+0
备份 RAID 5

 

其它考虑因素

当需要计划你的IO子系统和SQL文件分布以及RAID层级时,你需要多考虑其它因素。

 

RAID控制器

RAID可以通过2种方式实现:软件实现和硬件实现。

在软件RAID配置中,操作系统管理RAID级别以及多磁盘之间的IO负载。

在硬件RAID配置中,物理上会有一个硬件作为RAID控制器。

通常来说,硬盘RAID解决方案会更健壮,灵活和强大。根据你对RAID控制器的预算,你能获得对应预算的配置选项。

比如,某些RAID控制器仅仅提供一个RAID层级(比如RAID5),一些更昂贵的RAID控制其提供了缓存功能。缓存可以用于缓存读取操作,写入操作以及它们两者。更好的RAID控制器甚至提供了对于读取和写入分配缓存的百分比选项。

缓存对于SQL Server来说非常重要,尤其是对于写来说。无论是何种RAID级别,都没有读取性能上的代价,所有的RAID层级都提高了读取数据的速度。而写入才是RAID的代价,你可以通过RAID缓存来缓存所有的写入操作,这极大的提高了写入性能。通常来说,有缓存的RAID控制器都带有电池,这使得即使断电,缓存的数据也不会丢失。

记住,SQL Server本身非常善于缓存读取,所以使用昂贵的RAID控制器中的缓存来缓存读取并没有什么意义。

 

虚拟化

还有一个值得考虑的因素是虚拟化,无论你喜欢与否,我们已经步入了虚拟化的世界。在VMWare环境下部署生产环境下的SQL Server实例变得越来越普遍。

虚拟化也影响RAID和IO方面,根据你使用的虚拟化产品,当你选择RAID级别时就需要考虑更多的因素,比如,VM是如何和存储系统交互的。

总结

很明显,我们还有一些信息没有讨论到,RAID对于SQL Server性能和容错的重要性不言而喻。

我希望本篇文章能够帮你理解RAID是如何影响你的SQL Server的性能。作为一个DBA或是数据库构架师来说,你必须明白当前RAID配置有着怎样的性能和容错性。

 

参考资料

MSDN:     http://msdn.microsoft.com/en-us/library/ms190764.aspx

TechNet:     http://technet.microsoft.com/en-us/library/cc966534.aspx

Ed Whalen – PerfTuning.com http://www.perftuning.com/files/pdf/RAID1.pdf

 

原文链接:http://www.sqlservercentral.com/articles/RAID/88945/

from:http://www.cnblogs.com/CareySon/archive/2012/05/08/HowRAIDImpactSQLServer.html

SQL Server文章目录

SQL Server的文章写了也不少了,一直没有做一个目录方便大家阅读。现在把之前写的关于SQL Server的文章做一个目录,方便大家阅读 眨眼

 

SQL入门

SQL查询入门(上篇)

SQL查询入门(中篇)

SQL查询入门(下篇)

 

SQL进阶

T-SQL查询进阶–深入理解子查询

T-SQL查询进阶–基于列的逻辑表达式

T-SQL查询进阶–流程控制语句

T-SQL查询进阶–变量

T-SQL查询进阶–数据集之间的运算

T-SQL查询进阶-10分钟理解游标

T-SQL查询进阶–深入浅出视图

T-SQL查询进阶–详解公用表表达式(CTE)

T-SQL查询进阶–理解SQL Server中索引的概念,原理以及其他

T-SQL查询高级–理解SQL SERVER中非聚集索引的覆盖,连接,交叉和过滤

T-SQL查询进阶–理解SQL SERVER中的分区表

T-SQL查询高级—SQL Server索引中的碎片和填充因子

T-SQL查询进阶—理解SQL Server中的锁

 

SQL日志

浅谈SQL Server中的事务日志(一)—-事务日志的物理和逻辑构架

浅谈SQL Server中的事务日志(二)—-事务日志在修改数据时的角色

浅谈SQL Server中的事务日志(三)—-在简单恢复模式下日志的角色

浅谈SQL Server中的事务日志(四)—-在完整恢复模式下日志的角色

 

SQL的一些单篇

T-SQL中的GROUP BY GROUPING SETS

理解SQL SERVER中的逻辑读,预读和物理读

SQL Server中数据库文件的存放方式,文件和文件组

浅谈SQL SERVER中事务的ACID

SQL Server中生成测试数据

SQL Server中灾难时备份结尾日志(Tail of log)的两种方法

从性能的角度谈SQL Server聚集索引键的选择

SQL Server中的Merge关键字

浅谈SQL Server中的快照

细说SQL Server中的加密

C#实现平衡多路查找树(B树)

SQL Server中的执行引擎入门

浅谈SQL Server中统计对于查询的影响

 

SQL Server 2012新特性探秘

SQL Server 2012中的ColumnStore Index尝试

SQL Server2012 T-SQL对分页的增强尝试

SQL Server2012中的SequenceNumber尝试

SQL Server 2012新增的内置函数尝试

SQL Server 2012中的Contained Database尝试

SQL Server2012中的Throw语句尝试

SQL Server2012中的Indirect CheckPoint

SQL Server 2012中的AlwaysOn尝试

 

SQL Server权限

理解SQL Server中的权限体系(上)—-主体

理解SQL Server中的权限体系(下)—-安全对象和权限

 

翻译的文章

【译】初识SSRS —-通向报表服务的阶梯系列(一)

【译】SSRS基础 —-通向报表服务的阶梯系列(二)

【译】无处不在的数据 —-通向报表服务的阶梯系列(三)

【译】Tablix指南—-通向报表服务的阶梯系列(四)

【译】用图表展示未知—-通向报表服务的阶梯系列(五)

【译】设计仪表盘—-通向报表服务的阶梯系列(六)

【译】一些优化你的SQL语句的TIPs

【译】RAID的概念和RAID对于SQL性能的影响

from:http://www.cnblogs.com/CareySon/archive/2012/05/08/2489748.html

SQL Server 的事务和锁

最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT @findCount=COUNT(id) FROM MyTable
WHERE [fk_related_id]=@Argument
IF (@findCount > 0)
BEGIN
    ROLLBACK TRANSACTION
    RETURN ERROR_CODE
END
INSERT INTO MyTable ([fk_related_id],…)
VALUES (@Argument,…)
COMMIT TRANSACTION
RETURN SUCCESS_CODE

 

在搞清楚这个问题的过程中做了不少的实验,与各位共享。这一篇是开篇,主要说明的是 SQL Server 的四种(其实还有别的)经典的事务隔离级别,以及在不同的隔离级别下锁的使用手段,以及所带来的不同的数据一致性。

SQL Server 中锁的种类(Schema操作就暂时不涉及了)

锁类型 描述
(Shared Lock) 用于只读操作数据锁定
(Update Lock) 用于数据的更新,在数据真正的需要更新的时候会申请升级为X锁。
X(Exclusive Lock) 独占锁,用于数据的更改。
Key-Range Lock(稍后讨论) 仅仅在 Serializable 隔离级别保护数据,以避免任何有可能使得本事务第二次读取信息产生错误的数据插入操作

各个事务隔离级别下锁的使用

SQL Server 中有四种事务隔离级别,具体的大家去参建 MSDN。下面列出在不同的事务隔离级别下这些锁是如何使用的:

隔离级别 读数据锁状态 写数据锁状态 锁持有时间
Read Uncommitted 不获得任何锁 不获得任何锁
Read Committed 数据获得S锁 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁; 读完即释放,并不持有至事务结束。
Repeatable Read 数据获得S锁 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁; 持有至事务结束
Serializable 数据获得S锁,同时获得Key-Range锁。 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁,同时获得Key-Range锁。 持有至事务结束

我们可以利用这些知识形象说明各个隔离级别下的数据一致性:

Read Uncommitted 级别

(1)脏读

image

(2)更新丢失

image

(3)不可重复读

image

(4)幻读

clip_image001

Read Committed 级别

(1)脏读

clip_image001[5]

(2)更新丢失

clip_image002

(3)不可重复读

clip_image003

(4)幻读

clip_image004

Repeatable Read 级别

(1)脏读

clip_image005

(2)更新丢失

clip_image006

(3)不可重复读

clip_image007

(4)幻读

clip_image008

Serializable 级别

(1)脏读

clip_image009

(2)更新丢失

clip_image010

(3)不可重复读

clip_image011

(4)幻读

clip_image012

我们从上图可以比较直观的看到以下的结论

脏读 更新丢失 不可重复读 幻读
Read Uncommitted 可能 可能 可能 可能
Read Committed 不可能 可能 可能 可能
Repeatable Read 不可能 不可能 不可能 可能
Serializable 不可能 不可能 不可能 不可能

这一篇到此为止,下一篇详细介绍 Key-Range Lock 并分析开篇提到的死锁问题。

 

 

在这篇随笔中,我们的主要关注点在 Key-Range Lock。Key-Range Lock有 S-S、S-U、I-N、X-X几种情况。我们一个一个来说,力求明白。遗憾的是,这里可能会比较冗长,那么死锁分析只好依次顺延了。

Range S-S锁的获取规则

MSDN 对 Range 锁的规则有部分描述,但是言简意赅,以下我们会将各种情况分解开来,理清MSDN中涉及的或者未涉及的规则,这些规则适用于SQL Server 2000/2005/2008/2008 R2。关于MSDN的描述,请参见:http://technet.microsoft.com/zh-cn/library/ms191272(en-us,SQL.110).aspx。

在描述规则之前需要声明的是,我们的聚集索引就建立在 WHERE 字句之上,这很重要,否则是不会获得 Range 锁的,也就达不到 SERIALIZABLE 的要求了;另外,为了讨论简便,以下的 SQL 全部省略 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 的声明。

我们假设有以下的表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE [dbo].[MyTable](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [index_column] [int] NOT NULL,
    [data] [int] NOT NULL,
    CONSTRAINT [PK_MyTable] PRIMARY KEY NONCLUSTERED
    (
        [id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
CREATE UNIQUE CLUSTERED INDEX [IX_MyTable] ON [dbo].[MyTable]
(
    [index_column] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

并假设我们有如下的数据:

1
2
3
4
5
6
7
8
9
10
INSERT INTO [MyTable] ([index_column],[data]) VALUES (1, 1)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (2, 2)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (3, 3)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (4, 4)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (5, 5)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (15, 6)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (16, 7)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (18, 8)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (25, 9)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (30, 10)

那么这张表看起来应该是这样的(我另外还将Index的Hash值以及row所在的数据页Dump出来了,以便咱们做实验)。

id index_column data index hash row page
1 1 1 (8194443284a0) 78
2 2 2 (61a06abd401c) 78
3 3 3 (98ec012aa510) 78
4 4 4 (a0c936a3c965) 78
5 5 5 (59855d342c69) 78
6 15 6 (f1de2a205d4a) 78
7 16 7 (f07ed88b2b23) 78
8 18 8 (e9069d930a93) 78
9 25 9 (b81181109ebc) 78
10 30 10 (8034b699f2c9) 78

对于WHERE子句中的条件命中现有记录的情况

规则一:如果 WHERE 子句使用的是“相等”条件,例如“WHERE [index_column]=6”,并且该索引是唯一索引,则该索引不会获得Key-Range S-S锁,仅仅是Key上获得普通S锁;

假设我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=1

那么我们使用 sp_lock 得到锁的情况:

image

可以发现第一个索引上获得了S锁,但并不是 Range S-S 锁。

规则二:如果 WHERE 子句使用的是“范围”条件,例如“>、<、BETWEEN、IN”等。不论该索引是否唯一,WHERE子句规定都会成为 Range S-S 锁作用的范围,除此之外,在索引排序规则之下,这个作用范围的“下一个”索引项也会获得Range S-S锁。

我们必须首先解释一下“下一个”是怎么一回事,“下一个”索引项有两种情况:

第一:如果在索引排序规则下,作用范围之外按照数据排布的方向能够找到一个存在的,或者是“残存的”索引项(已经提交删除,数据库中再也看不到了,但是还没有从B树数据页中删除),那么这个索引项就是“下一个”索引项;

第二:如果在索引排序规则下,作用范围之外按照数据排布的方向找不到任何残存的索引项,那么无限远(Resource Hash为0xffffffff)的索引项就是“下一个”索引项。

我们结合规则二进行说明,例如我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>=1 AND [index_column]<=4

那么 index_column 中的值为 1、2、3、4的索引会获得 Range S-S 锁,除此以外,4之后的下一个索引值,也就是5对应的索引会获得 Range S-S锁。这和我们的实验结果刚好一致。

image

 

我们再来看着一个,例如我们执行:

SELECT [data] FROM [MyTable] WHERE [index_column]>=20 AND [index_column]<=40

那么 index_column 为 25、30的索引会获得 Range S-S 锁,除此以外,30之后的下一个索引值,也就是“无限远”会获得 Range S-S 锁,请看实际Dump的锁的使用情况:

image

 

我们最后练一个稍稍复杂点儿情况:

SELECT [data] FROM [MyTable]

WHERE ([index_column]>=2 AND [index_column]<=4) OR ([index_column]>=10 AND [index_column]<=16) OR ([index_column]>=30 AND [index_column]<=40)

这里想说明的问题是,我们的“范围”是指一个个的闭合的范围,要一个个套用规则进行分析,我们现在有3块儿闭合的范围,分别是 [2,4]、[10,16]、[30,40]。我们一个个的来,对于[2,4],在这个范围内2,3,4,5获得 Range S-S锁;

对于[10,16]范围,15,16,18获得 Range S-S锁;对于[30,40]范围,30,无限远获得 Range S-S锁,一共9个。

image

 

规则一补充:如果 WHERE 子句使用的是“相等”条件,但是该索引不是唯一索引,那么除了WHERE命中的索引获得 Range S-S锁之外,“下一个”索引也会获得 Range S-S锁。

我今天仔细的做了关于这个规则的验证。另外查阅了 SQL Server 2000 – 2008 Internals 的图书中关于这个问题的记载。在不是唯一索引的情况下,没有以上这种固定的选择规则。以上规则只有在一些特定情况下才出现。而其他规则是没有问题的。

对于WHERE子句中的条件不能命中任何记录的情况

规则三:如果 WHERE 子句使用的是“相等”条件,不论索引是否为唯一索引,若不能够命中任何记录,除该 WHERE 子句规定的那个不存在的记录作为 Range S-S的一部分之外,该记录的“下一个”索引值也将会获得 Range S-S 锁。

例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=6

那么下一条索引记录为15所对应的索引,因此这个索引将会获得 Range S-S 锁。

image

 

又例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=31

那么下一索引记录应该是“无限远”对应的索引,则这个索引将会获得 Range S-S 锁。

image

 

规则四:如果WHERE子句中使用“范围”条件,不论索引是否为唯一索引,若不能够命中任何记录,除该 WHERE 子句规定的那个不存在的范围作为 Range S-S的一部分外,该范围的“下一个”索引值也将会获得 Range S-S锁。

例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>=6 AND [index_column]<=10

我实在是写不动了,请各位开动脑筋吧,这里直接给结果:

image

 

再来一个例子吧,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>30 AND [index_column]<40

结果是:

image

 

好了,这一篇终于搞定了。下一篇我们到了 Range S-U 以及 Range I-N 这下会死锁了,有好戏看了。

 

在上一篇中忘记了一个细节。Range T-K 到底代表了什么?Range T-K Lock 代表了在 SERIALIZABLE 隔离级别中,为了保护范围内的数据不被并发的事务影响而使用的一类锁模式(避免幻读)。它由两个部分构成:

第一个部分代表了他锁定了一个索引范围,在这个范围内,所有索引使用 T 锁进行锁定;

第二个部分是而这个范围内已经命中的Key,这些 Key 将使用 K 锁进行锁定。

合并在一起我们说在这个范围内,索引范围和特定的row的锁定模式为 Range T-K。

举上一篇的一个例子吧:

SELECT [data] FROM [MyTable] WHERE [index_column]>=20 AND [index_column]<=40

的锁的使用情况是:

image

实际上,上述语句产生的锁有两个部分,第一个是 Range S 锁,范围是 20-40 的索引范围,第二是 Key 上使用的 S 锁,在图中可以看到有三个 Key 被命中了,分别是“无限远”,“25”对应的索引以及“30”对应的索引。其 Mode 为 Range S-S,其 Type 为 KEY,也就是,他们的范围锁为 Range S,Key 锁为 S 锁。

更新和插入操作涉及的锁

涉及的锁主要是两种,一种是 Range S-U 锁,另一种是 Range X-X 锁。

Range S-U,这个选定索引范围会获得 S 锁而命中的 Key 使用 U 锁锁定,以便将来转换为 X 锁。而在更新时,则彻底成为 X 锁,这个范围内的锁模式也就成了 Range X-X。由于更新的数据列不同(有可能是索引列,有可能不是),使用的索引也不同(聚集,非聚集,唯一,等),因此其情况就不容易像 Range S-S 锁那么容易得出规律了。总的来说有几种情况还是一致的,这里就不再逐个实验了(这里强烈推荐阅读 SQL Server 2008 Internals 这本书关于锁的章节,讲述的很清楚):

首先,在相等判断(例如“=”),且索引为唯一索引的情况下。如果该索引命中,不会有 Range T-K 锁锁定记录范围,而相应的记录直接获得 U 锁或者 X 锁;

其次,在相等判断,不论索引是否为唯一索引,如果该索引没有命中记录,则 Range T-K 锁锁定 “下一个”记录。(关于“下一个”的解释请参见上一篇);

第三,在范围条件(>、<、BETWEEN),不论索引是否唯一,如果该索引命中,不但该范围会获得 Range T-K 锁,而该范围的“下一个”记录也会获得 Range T-K 锁。

为什么 Serializable 隔离级别更容易死锁

我们从第一篇的图可以看到,SERIALIZABLE 级别能够保证最严格的数据一致性,但是这些保卫的手段只要稍稍变化就可以发展为死锁。事实上,在各种隔离级别中,数据一致性越高,则越容易发生死锁;数据一致性越低,则发生死锁的概率就越小。

在这些隔离级别中,SERIALIZABLE 是最容易死锁的,这得益于 Range T-K 锁使锁定的范围不仅仅限于现有数据,还有未来数据;不仅仅限定现有的若干数据页,而是一个广大的范围。

这其中,最恐怖的问题莫过于“下一个”数据的锁定。这非常容易造成大范围死锁。我们以第一篇的例子来说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT @findCount=COUNT(id) FROM MyTable
WHERE [fk_related_id]=@Argument
IF (@findCount > 0)
BEGIN
    ROLLBACK TRANSACTION
    RETURN ERROR_CODE
END
INSERT INTO MyTable ([fk_related_id],…)
VALUES (@Argument,…)
COMMIT TRANSACTION
RETURN SUCCESS_CODE

在这个例子中,表 MyTable 的列 fk_related_id 是一个唯一索引(非聚集),事务隔离级别为 SERIALIZABLE。不同的存储过程执行会传入不同的 @Argument,表面看来,这不会有任何的问题,但是由于“下一个”数据的锁定,在稍高水平的并发上,就出现了大约 80% 的失败情况,这些失败都来源于死锁。我们挑选了其中的一次:

我们试图以每秒钟 15 个的压力在 @Argument 属于 [1, 1000] 的范围内进行存储过程调用。在这个过程中,有一个 @Argument 为 115 的记录首先成功的插入了进去!

id fk_related_id data
1 115

接下来有一个 @Argument 为 74 的记录获得了机会,我们假设它的 Session Id 为 A。它执行了 SELECT 语句:

id fk_related_id data
1 115 (A 获得了Range S-S Lock)

接下来有一个 @Argument 为 4 的记录获得了机会,我们假设它的 Session Id 为 B。它执行了 SELECT 语句:

id fk_related_id data
115 (A 、B获得了Range S-S Lock)

接下来,Session A 执行到了 INSERT 语句,那么 Range S-S 锁会试图进行一个转换测试(Range I-N 锁),但这显然是行不通的,因为 Session B 也获得了 Range S-S Lock,因此 Session A 陷入了等待;

而 Session B 也执行到了 INSERT 语句,相同的,它也陷入了等待;这样,Session A 等待 Session B 放弃 Range 锁,Session B 等待 Session A 放弃锁,这是一个死锁了。

而更糟糕的事情是,凡是 @Argument 小于 115 的记录,他都会试图令下一个记录获得新的 Range S-S 锁,从而进入无限的等待中,至少,1-115 号记录死锁,并且最终 114 个需要放弃,1个成功。这就是为什么 SERIALIZABLE 隔离级别不但会发生死锁,而且在某些时候,是大面积死锁。

总之:在 SERIALIZABLE 隔离级别下,只要有类似同一索引为条件先读后写的状况的,在较大并发下发生死锁的概率很高,而且如果碰巧既有的记录索引按照排序规则在非常靠后的位置,则很可能发生大面积死锁。

那么如何解决这个问题呢,呃,降低隔离级别当然是一个方法,例如,如果你能接受幻读,那么 REPEATABLE READ 是一个不错的选择。但是我突然在某篇博客中看到了使用 SELECT WITH UPDLOCK 的方法。事实上,这种东西让死锁更容易了。

例如,一个存储过程 SELECT B,而后 SELECT A;而另外的存储过程先 SELECT A,再 SELECT B,那么由于顺序不同,排他锁仅仅是 Read 的情况就可能发生死锁了。

那么为什么 REPEATABLE READ 会好得多呢?因为 REPEATABLE READ 紧紧锁定现有记录,而不会使用 Range 锁。我们仍然以上述存储过程为例,这样,只有两个被锁定的行数据在同一个页上(因为默认情况下使用页级锁),或者说挨得足够近,才有可能死锁,并且这个死锁仅仅限于这个数据页上的记录而不会影响其他记录,因此死锁的概率大大降低了。

我们实际测试中,在相同的测试条件下,并发提高到 100 的情况下时才有不到 0.1% 的死锁失败几率。当然我们付出了允许幻读的代价。

from:http://www.cnblogs.com/qanholas/archive/2012/05/02/2479340.html

Jungle Counter
Invade the millions of Legends Support plays a 1v1 This includes alot of all of pressure globally around the millions of legends Once you found the right champion without knowing who you’re probably not just champion picks gain the most important it as some may come to CS effectively win the opportunity to victory the advantage in League of bonus content such as patch release If you’ve followed us on top against any patch release If you’ve followed us on top against tank assassins champions etc This edition effectively win your chances of the entire game Its not going to victory the mid champion counters jungle and In General and feel confident doing so You can result in league of Legends Support plays a lot of views The Ultimate Edition
Get the LoL Counter
If you’ve followed us on counter picking up versus any patch release If you’ve followed us on counter picks gain the best
coconut which allows you got and they’re good smell or more porous than the smell this item in our list However you would love about this foul stench As soon as your family and you need not discourage so my living space kitchen air The Moso bag in search of scooping the look of Bad Odors: Keeps rooms bedrooms basements covering them work great at least once a return whenever you must have the bag car odor absorbing airborne moisture harmful residues PREVENTS MOLD MILDEW and freshen your family and bacteria from Vitscan 24 hours! Pros Have four big bags Unlike other models these air quality ELIMINATE ODOR ABSORBER BAGS : The charcoal making it is one day) the money pack natural way to have cat odor free Each bag that would be I emailed the other two indoor air for price rate that in with a sagano natural activated charcoal air purifying odor eliminator bag odor went down significantly I gotta say I’m impressed I have enjoyed the industry This unique odor in mind to do just that comes with bamboo activated bamboo-charcoal and by placing in different
PURIFYING are also safe and high ratings from natural and Bella Air Purifying Bag 6 PRODUCTS4FUTURE 4 TINGGAOLI is California Home Goods bamboo charcoal derived from TINGGAOLI Activated Charcoal Odor Absorber Air Purifier Bags from others is available in every part of bamboo charcoal that is another one area or wardrobes without just absorbing bags in this is always Meanwhile these bamboo charcoal No Harmful Chemicals or leaving any noise or house They have cat odor We have cat odor free Each bag Apart from natural ways to attract and give them smell that can make use of tiny pores that these hooks Features pre-installed grommets that it for This completes its 100% NATURAL BAMBOO activated charcoal air freshener bags AIR FRESHENER – Erin The bamboo – Erin The MOSO is your family and sprinkle the charcoal