存档

‘Sql Server’ 分类的存档

利用Tokyo Tyrant构建高并发的分布式key-value持久存储系统

2010年6月2日 admin 没有评论

本文转至 张宴大哥博客
“利用Tokyo Tyrant构建兼容Memcached协议、支持故障转移、高并发的分布式key-value持久存储系统”

Tokyo Cabinet 是日本人 平林幹雄 开发的一款 DBM 数据库,该数据库读写非常快,哈希模式写入100万条数据只需0.643秒,读取100万条数据只需0.773秒,是 Berkeley DB 等 DBM 的几倍。

点击在新窗口中浏览此图片


Tokyo Tyrant 是由同一作者开发的 Tokyo Cabinet 数据库网络接口。它拥有Memcached兼容协议,也可以通过HTTP协议进行数据交换。

Tokyo Tyrant 加上 Tokyo Cabinet,构成了一款支持高并发的分布式持久存储系统,对任何原有Memcached客户端来讲,可以将Tokyo Tyrant看成是一个Memcached,但是,它的数据是可以持久存储的。这一点,跟新浪的Memcachedb性质一样。

相比Memcachedb而言,Tokyo Tyrant具有以下优势:

1、故障转 移:Tokyo Tyrant支持双机互为主辅模式,主辅库均可读写,而Memcachedb目前支持类似MySQL主辅库同步的方式实现读写分离,支持“主服务器可读 写、辅助服务器只读”模式。

点击在新窗口中浏览此图片

这里使用 $memcache->addServer 而不是 $memcache->connect 去连接 Tokyo Tyrant 服务器,是因为当 Memcache 客户端使用 addServer 服务器池时,是根据“crc32(key) % current_server_num”哈希算法将 key 哈希到不同的服务器的,PHP、C 和 python 的客户端都是如此的算法。Memcache 客户端的 addserver 具有故障转移机制,当 addserver 了2台 Memcached 服务器,而其中1台宕机了,那么 current_server_num 会由原先的2变成1。

引用 memcached 官方网站和 PHP 手册中的两段话:

引用
http://www.danga.com/memcached/
If a host goes down, the API re-maps that dead host’s requests onto the servers that are available.

http://cn.php.net/manual/zh/function.Memcache-addServer.php
Failover may occur at any stage in any of the methods, as long as other servers are available the request the user won’t notice. Any kind of socket or Memcached server level errors (except out-of-memory) may trigger the failover. Normal client errors such as adding an existing key will not trigger a failover.


2、日志文件体积 小:Tokyo Tyrant用于主辅同步的日志文件比较小,大约是数据库文件的1.3倍,而Memcachedb的同步日志文件非常大,如果不定期清理,很容易将磁盘写 满。


3、超大数据量下表现出色:

点击在新窗口中浏览此图片

但是,Tokyo Tyrant 也有缺点:在32位操作系统下,作为 Tokyo Tyrant 后端存储的 Tokyo Cabinet 数据库单个文件不能超过2G,而64位操作系统则不受这一限制。所 以,如果使用 Tokyo Tyrant,推荐在64位CPU、操作系统上安装运行。


一、安装
1、首先编译安装tokyocabinet数据库

wget http://tokyocabinet.sourceforge.net/tokyocabinet-1.4.28.tar.gz
tar zxvf tokyocabinet-1.4.28.tar.gz
cd tokyocabinet-1.4.28/
./configure
make
make install
cd ../

2、然后编译安装tokyotyrant

wget http://tokyocabinet.sourceforge.net/tyrantpkg/tokyotyrant-1.1.29.tar.gz
tar zxvf tokyotyrant-1.1.29.tar.gz
cd tokyotyrant-1.1.29/
./configure
make
make install
cd ../

二、配置
1、 创建tokyotyrant数据文件存放目录

mkdir -p /ttserver/

2、启动 tokyotyrant的主进程(ttserver)
(1)、单机模式

ulimit -SHn 51200
ttserver -host 127.0.0.1 -port 11211 -thnum 8 -dmn -pid /ttserver/ttserver.pid -log /ttserver/ttserver.log -le -ulog /ttserver/ -ulim 128m -sid 1 -rts /ttserver/ttserver.rts /ttserver/database.tch

(2)、 双机互为主辅模式
服务器192.168.1.91:

ulimit -SHn 51200
ttserver -host 192.168.1.91 -port 11211 -thnum 8 -dmn -pid /ttserver/ttserver.pid -log /ttserver/ttserver.log -le -ulog /ttserver/ -ulim 128m -sid 91 -mhost 192.168.1.92 -mport 11211 -rts /ttserver/ttserver.rts /ttserver/database.tch

服务器192.168.1.92:

ulimit -SHn 51200
ttserver -host 192.168.1.92 -port 11211 -thnum 8 -dmn -pid /ttserver/ttserver.pid -log /ttserver/ttserver.log -le -ulog /ttserver/ -ulim 128m -sid 92 -mhost 192.168.1.91 -mport 11211 -rts /ttserver/ttserver.rts /ttserver/database.tch

(3)、 参数说明
ttserver [-host name] [-port num] [-thnum num] [-tout num] [-dmn] [-pid path] [-log path] [-ld|-le] [-ulog path] [-ulim num] [-uas] [-sid num] [-mhost name] [-mport num] [-rts path] [dbname]

-host name : 指定需要绑定的服务器域名或IP地址。默认绑定这台服务器上的所有IP地址。
-port num : 指定需要绑定的端口号。默认端口号为1978
-thnum num : 指定线程数。默认为8个线程。
-tout num : 指定每个会话的超时时间(单位为秒)。默认永不超时。
-dmn : 以守护进程方式运行。
-pid path : 输出进程ID到指定文件(这里指定文件名)。
-log path : 输出日志信息到指定文件(这里指定文件名)。
-ld : 在日志文件中还记录DEBUG调试信息。
-le : 在日志文件中仅记录错误信息。
-ulog path : 指定同步日志文件存放路径(这里指定目录名)。
-ulim num : 指定每个同步日志文件的大小(例如128m)。
-uas : 使用异步IO记录更新日志(使用此项会减少磁盘IO消耗,但是数据会先放在内存中,不会立即写入磁盘,如果重启服务器或ttserver进程被kill 掉,将导致部分数据丢失。一般情况下不建议使用)。
-sid num : 指定服务器ID号(当使用主辅模式时,每台ttserver需要不同的ID号)
-mhost name : 指定主辅同步模式下,主服务器的域名或IP地址。
-mport num : 指定主辅同步模式下,主服务器的端口号。
-rts path : 指定用来存放同步时间戳的文件名。

如果使用的是哈希数据库,可以指定参数“#bnum=xxx”来提高性能。它可以指 定bucket存储桶的数量。例如指定“#bnum=1000000”,就可以将最新最热的100万条记录缓存在内存中:

ttserver -host 127.0.0.1 -port 11211 -thnum 8 -dmn -pid /ttserver/ttserver.pid -log /ttserver/ttserver.log -le -ulog /ttserver/ -ulim 128m -sid 1 -rts /ttserver/ttserver.rts /ttserver/database.tch#bnum=1000000

如果大量的客户端访问ttserver,请确保文件描述符够用。许多服务器的默认文件描述符为1024,可以在启动ttserver前使用ulimit 命令提高这项值。例如:

ulimit -SHn 51200

3、停止tokyotyrant(ttserver)

ps -ef | grep ttserver

找到ttserver的进程号并kill,例如:

kill -TERM 2159

三、调用
1、任何Memcached客户端均可直接调用tokyotyrant。

2、 还可以通过HTTP方式调用,下面以Linux的curl命令为例,介绍如何操作tokyotyrant:
(1)、写数 据,将数据“value”写入到“key”中:

curl -X PUT http://127.0.0.1:11211/key -d “value”

(2)、读数据,读取“key”中数据:

(3)、删数据,删除“key”:


附: 文章修改历史

● [2008年08月07日] [Version 1.0] 撰写本文

● [2008年10月16日] [Version 1.1] Tokyo Cabinet 版本升级到 1.3.12;Tokyo Tyrant 版本升级到 1.1.5

● [2008年12月04日] [Version 1.2] Tokyo Cabinet 版本升级到 1.3.22;Tokyo Tyrant 版本升级到 1.1.8

● [2008年07月06日] [Version 1.3] Tokyo Cabinet 版本升级到 1.4.28;Tokyo Tyrant 版本升级到 1.1.29

Popularity: unranked [?]

Sql智能提示

2009年6月25日 admin 没有评论

其实就是 SQL Assistant 工具,
支持SqlServer,Visual Studio
,MySql,Oracle
看看 以下截图:

sql2
sql1

DB

下载地址:SQL Assistant2.516 (内含注册码)

Popularity: unranked [?]

在SQL SERVER中删除表的记录以后,新记录的编号从1开始

2009年3月12日 admin 没有评论

有两种方法:
方法1:
truncate table 你的表名 –这样不但将数据删除,而且可以重新置位identity各性的字段。

方法2:
delete from 你的表名
dbcc checkident(你的表名,reseed,0) –重新置位identity属性的字段,让其下个值从1开始。

Popularity: 14% [?]

Microsoft SQL Server 2005 Service Pack 3 (SP3)

2008年12月22日 admin 没有评论

今天刚刚看到 Microsoft SQL Server 2005 Service Pack 3 发布了,哈哈

Microsoft released today SQL Server 2005 Service Pack 3 (SP3). SQL 2005 version should now be 9.00.4035.

Microsoft SQL Server 2005 Service Pack 3 (SP3) contains hotfixes that were included in cumulative update packages for SQL Server 2005 Service Pack 2 from cumulative update package 1 to cumulative update package 9, and fixes to issues that have been reported through our customer feedback platforms. It also includes supportability enhancements and issues that have been reported through Windows Error Reporting.

Related links:

Downloads:


Technorati : ,

Popularity: 31% [?]

SQL Server死锁

2008年11月16日 admin 没有评论

本文收藏博客园的,哈哈。。。。。

1. 死锁原理

根据操作系统中的定义:死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。

死锁的四个必要条件:
互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。
请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。
非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
循环等待条件(Circular wait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。

对应到SQL Server中,当在两个或多个任务中,如果每个任务锁定了其他任务试图锁定的资源,此时会造成这些任务永久阻塞,从而出现死锁;这些资源可能是:单行(RID,堆中的单行)、索引中的键(KEY,行锁)、页(PAG8KB)、区结构(EXT,连续的8)、堆或B(HOBT) 、表(TAB,包括数据和索引)、文件(File,数据库文件)、应用程序专用资源(APP)、元数据(METADATA)、分配单元(Allocation_Unit)、整个数据库(DB)一个死锁示例如下图所示:


说明:
T1T2表示两个任务;R1R2表示两个资源;由资源指向任务的箭头(R1->T1R2->T2)表示该资源被改任务所持有;由任务指向资源的箭头(T1->S2T2->S1)表示该任务正在请求对应目标资源;
其满足上面死锁的四个必要条件:
(1).互斥:资源S1S2不能被共享,同一时间只能由一个任务使用;
(2).请求与保持条件:T1持有S1的同时,请求S2T2持有S2的同时请求S1
(3).非剥夺条件:T1无法从T2上剥夺S2T2也无法从T1上剥夺S1
(4).循环等待条件:上图中的箭头构成环路,存在循环等待。

2. 死锁排查

(1). 使用SQL Server的系统存储过程sp_whosp_lock,可以查看当前数据库中的锁情况;进而根据objectID(@objID)(SQL Server 2005)/ object_name(@objID)(Sql Server 2000)可以查看哪个资源被锁,用dbcc ld(@blk),可以查看最后一条发生给SQL ServerSql语句;

CREATE Table #Who(spid int,
ecid
int,
status
nvarchar(50),
loginname
nvarchar(50),
hostname
nvarchar(50),
blk
int,
dbname
nvarchar(50),
cmd
nvarchar(50),
request_ID
int);

CREATE Table #Lock(spid int,
dpid
int,
objid
int,
indld
int,
[Type] nvarchar(20),
Resource
nvarchar(50),
Mode
nvarchar(10),
Status
nvarchar(10)
);

INSERT INTO #Who
EXEC sp_who active 看哪个引起的阻塞,blk
INSERT INTO #Lock
EXEC sp_lock 看锁住了那个资源id,objid

DECLARE @DBName nvarchar(20);
SET @DBName=NameOfDataBase

SELECT #Who.* FROM #Who WHERE dbname=@DBName
SELECT #Lock.* FROM #Lock
JOIN #Who
ON #Who.spid=#Lock.spid
AND dbname=@DBName;

最后发送到SQL Server的语句
DECLARE crsr Cursor FOR
SELECT blk FROM #Who WHERE dbname=@DBName AND blk<>0;
DECLARE @blk int;
open crsr;
FETCH NEXT FROM crsr INTO @blk;
WHILE (@@FETCH_STATUS = 0)
BEGIN;
dbcc inputbuffer(@blk);
FETCH NEXT FROM crsr INTO @blk;
END;
close crsr;
DEALLOCATE crsr;

锁定的资源
SELECT #Who.spid,hostname,objid,[type],mode,object_name(objid) as objName FROM #Lock
JOIN #Who
ON #Who.spid=#Lock.spid
AND dbname=@DBName
WHERE objid<>0;

DROP Table #Who;
DROP Table #Lock;


(2).
使用 SQL Server Profiler 分析死锁: Deadlock graph 事件类添加到跟踪。此事件类使用死锁涉及到的进程和对象的 XML 数据填充跟踪中的 TextData 数据列。SQL Server 事件探查器 可以将 XML 文档提取到死锁 XML (.xdl) 文件中,以后可在 SQL Server Management Studio 中查看该文件。

3. 避免死锁

上面1中列出了死锁的四个必要条件,我们只要想办法破其中的任意一个或多个条件,就可以避免死锁发生,一般有以下几种方法(FROM Sql Server 2005联机丛书)
(1).按同一顺序访问对象。(注:避免出现循环)
(2).避免事务中的用户交互。(注:减少持有资源的时间,较少锁竞争)
(3).保持事务简短并处于一个批处理中。(注:同(2),减少持有资源的时间)
(4).使用较低的隔离级别。(注:使用较低的隔离级别(例如已提交读)比使用较高的隔离级别(例如可序列化)持有共享锁的时间更短,减少锁竞争)
(5).使用基于行版本控制的隔离级别2005中支持快照事务隔离和指定READ_COMMITTED隔离级别的事务使用行版本控制,可以将读与写操作之间发生的死锁几率降至最低:
SET ALLOW_SNAPSHOT_ISOLATION ON –事务可以指定 SNAPSHOT 事务隔离级别;
SET READ_COMMITTED_SNAPSHOT ON 指定 READ_COMMITTED 隔离级别的事务将使用行版本控制而不是锁定。默认情况下(没有开启此选项,没有加with nolock提示)SELECT语句会对请求的资源加S(共享锁);而开启了此选项后,SELECT不会对请求的资源加S锁。
注意:设置 READ_COMMITTED_SNAPSHOT 选项时,数据库中只允许存在执行 ALTER DATABASE 命令的连接。在 ALTER DATABASE 完成之前,数据库中决不能有其他打开的连接。数据库不必一定要处于单用户模式中。
(6).使用绑定连接(注:绑定会话有利于在同一台服务器上的多个会话之间协调操作。绑定会话允许一个或多个会话共享相同的事务和锁(但每个回话保留其自己的事务隔离级别),并可以使用同一数据,而不会有锁冲突。可以从同一个应用程序内的多个会话中创建绑定会话,也可以从包含不同会话的多个应用程序中创建绑定会话。在一个会话中开启事务(begin tran)后,调用exec sp_getbindtoken @Token out;来取得Token,然后传入另一个会话并执行EXEC sp_bindsession @Token来进行绑定(最后的示例中演示了绑定连接)

4. 死锁处理方法:

(1). 根据2中提供的sql,查看那个spid处于wait状态,然后用kill spid来干掉(即破坏死锁的第四个必要条件:循环等待);当然这只是一种临时解决方案,我们总不能在遇到死锁就在用户的生产环境上排查死锁、Kill sp,我们应该考虑如何去避免死锁。

(2). 使用SET LOCK_TIMEOUT timeout_period(单位为毫秒)设定锁请求超时。默认情况下,数据库没有超时期限(timeout_period值为-1,可以用SELECT @@LOCK_TIMEOUT来查看该值,即无限期等待)。当请求锁超过timeout_period时,将返回错误。timeout_period值为0时表示根本不等待,一遇到锁就返回消息。设置锁请求超时,破环了死锁的第二个必要条件(请求与保持条件)

服务器: 消息 1222,级别 16,状态 50,行 1
已超过了锁请求超时时段。

(3). SQL Server内部有一个锁监视器线程执行死锁检查,锁监视器对特定线程启动死锁搜索时,会标识线程正在等待的资源;然后查找特定资源的所有者,并递归地继续执行对那些线程的死锁搜索,直到找到一个构成死锁条件的循环。检测到死锁后,数据库引擎 选择运行回滚开销最小的事务的会话作为死锁牺牲品,返回1205 错误,回滚死锁牺牲品的事务并释放该事务持有的所有锁,使其他线程的事务可以请求资源并继续运行。

5. 两个死锁示例及解决方法

5.1 SQL死锁

(1). 测试用的基础数据:

CREATE TABLE Lock1(C1 int default(0));
CREATE TABLE Lock2(C1 int default(0));
INSERT INTO Lock1 VALUES(1);
INSERT INTO Lock2 VALUES(1);

(2). 开两个查询窗口,分别执行下面两段sql

Query 1
Begin Tran
Update Lock1 Set C1=C1+1;
WaitFor Delay 00:01:00;
SELECT * FROM Lock2
Rollback Tran;
Query 2
Begin Tran
Update Lock2 Set C1=C1+1;
WaitFor Delay 00:01:00;
SELECT * FROM Lock1
Rollback Tran;

上面的SQL中有一句WaitFor Delay ‘00:01:00′,用于等待1分钟,以方便查看锁的情况。

(3). 查看锁情况

在执行上面的WaitFor语句期间,执行第二节中提供的语句来查看锁信息:

Query1中,持有Lock1中第一行(表中只有一行数据)的行排他锁(RID:X),并持有该行所在页的意向更新锁(PAG:IX)、该表的意向更新锁(TAB:IX)Query2中,持有Lock2中第一行(表中只有一行数据)的行排他锁(RID:X),并持有该行所在页的意向更新锁(PAG:IX)、该表的意向更新锁(TAB:IX)

执行完WaitforQuery1查询Lock2,请求在资源上加S锁,但该行已经被Query2加上了X锁;Query2查询Lock1,请求在资源上加S锁,但该行已经被Query1加上了X锁;于是两个查询持有资源并互不相让,构成死锁。

(4). 解决办法

a). SQL Server自动选择一条SQL作死锁牺牲品:运行完上面的两个查询后,我们会发现有一条SQL能正常执行完毕,而另一个SQL则报如下错误:

服务器: 消息 1205,级别 13,状态 50,行 1
事务(进程 ID  xx)与另一个进程已被死锁在  lock 资源上,且该事务已被选作死锁牺牲品。请重新运行该事务。

这就是上面第四节中介绍的锁监视器干活了。

b). 按同一顺序访问对象:颠倒任意一条SQL中的UpdateSELECT语句的顺序。例如修改第二条SQL成如下:

Query2
Begin Tran
SELECT * FROM Lock1在Lock1上申请S锁
WaitFor Delay 00:01:00;
Update Lock2 Set C1=C1+1;Lock2:RID:X
Rollback Tran;

当然这样修改也是有代价的,这会导致第一条SQL执行完毕之前,第二条SQL一直处于阻塞状态。单独执行Query1Query2需要约1分钟,但如果开始执行Query1时,马上同时执行Query2,则Query2需要2分钟才能执行完;这种按顺序请求资源从一定程度上降低了并发性。

c). SELECT语句加With(NoLock)提示:默认情况下SELECT语句会对查询到的资源加S(共享锁)S锁与X(排他锁)不兼容;但加上With(NoLock)后,SELECT不对查询到的资源加锁(或者加Sch-S锁,Sch-S锁可以与任何锁兼容);从而可以是这两条SQL可以并发地访问同一资源。当然,此方法适合解决读与写并发死锁的情况,但加With(NoLock)可能会导致脏读。

SELECT * FROM Lock2 WITH(NOLock)
SELECT * FROM Lock1 WITH(NOLock)

d). 使用较低的隔离级别。SQL Server 2000支持四种事务处理隔离级别(TIL),分别为:READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLESQL Server 2005中增加了SNAPSHOT TIL默认情况下,SQL Server使用READ COMMITTED TIL,我们可以在上面的两条SQL前都加上一句SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED,来降低TIL以避免死锁;事实上,运行在READ UNCOMMITTED TIL的事务,其中的SELECT语句不对结果资源加锁或加Sch-S锁,而不会加S锁;但还有一点需要注意的是:READ UNCOMMITTED TIL允许脏读,虽然加上了降低TIL的语句后,上面两条SQL在执行过程中不会报错,但执行结果是一个返回1,一个返回2,即读到了脏数据,也许这并不是我们所期望的。

e). SQL前加SET LOCK_TIMEOUT timeout_period,当请求锁超过设定的timeout_period时间后,就会终止当前SQL的执行,牺牲自己,成全别人。

f). 使用基于行版本控制的隔离级别(SQL Server 2005支持):开启下面的选项后,SELECT不会对请求的资源加S锁,不加锁或者加Sch-S锁,从而将读与写操作之间发生的死锁几率降至最低;而且不会发生脏读。

SET ALLOW_SNAPSHOT_ISOLATION ON
SET READ_COMMITTED_SNAPSHOT ON

g). 使用绑定连接(使用方法见下一个示例。)

5.2 程序死锁(SQL阻塞)

看一个例子:一个典型的数据库操作事务死锁分析,按照我自己的理解,我觉得这应该算是C#程序中出现死锁,而不是数据库中的死锁;下面的代码模拟了该文中对数据库的操作过程:

//略去的无关的code
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
SqlTransaction tran
= conn.BeginTransaction();
string sql1 = Update Lock1 SET C1=C1+1;
string sql2 = SELECT * FROM Lock1;
ExecuteNonQuery(tran, sql1);
//使用事务:事务中Lock了Table
ExecuteNonQuery(null, sql2); //新开一个connection来读取Table

public static void ExecuteNonQuery(SqlTransaction tran, string sql)
{
SqlCommand cmd
= new SqlCommand(sql);
if (tran != null)
{
cmd.Connection
= tran.Connection;
cmd.Transaction
= tran;
cmd.ExecuteNonQuery();
}

else
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
cmd.Connection
= conn;
cmd.ExecuteNonQuery();
}

}

}

执行到ExecuteNonQuery(null, sql2)时抛出SQL执行超时的异常,下图从数据库的角度来看该问题:

代码从上往下执行,会话1持有了表Lock1X锁,且事务没有结束,回话1就一直持有X锁不释放;而会话2执行select操作,请求在表Lock1上加S锁,但S锁与X锁是不兼容的,所以回话2的被阻塞等待,不在等待中,就在等待中获得资源,就在等待中超时。。。从中我们可以看到,里面并没有出现死锁,而只是SELECT操作被阻塞了。也正因为不是数据库死锁,所以SQL Server的锁监视器无法检测到死锁。

我们再从C#程序的角度来看该问题:

C#程序持有了表Lock1上的X锁,同时开了另一个SqlConnection还想在该表上请求一把S锁,图中已经构成了环路;太贪心了,结果自己把自己给锁死了。。。

虽然这不是一个数据库死锁,但却是因为数据库资源而导致的死锁,上例中提到的解决死锁的方法在这里也基本适用,主要是避免读操作被阻塞,解决方法如下:

a). SELECT放在Update语句前:SELECT不在事务中,且执行完毕会释放S锁;
b). SELECT也放加入到事务中:ExecuteNonQuery(tran, sql2);
c). SELECTWith(NOLock)提示:可能产生脏读;
d). 降低事务隔离级别:SELECT语句前加SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;同上,可能产生脏读;
e). 使用基于行版本控制的隔离级别(同上例)。
g). 使用绑定连接:取得事务所在会话的token,然后传入新开的connection中;执行EXEC sp_bindsession @Token后绑定了连接,最后执行exec sp_bindsession null;来取消绑定;最后需要注意的四点是:
(1). 使用了绑定连接的多个connection共享同一个事务和相同的锁,但各自保留自己的事务隔离级别;
(2). 如果在sql3字符串的“exec sp_bindsession null”换成“commit tran”或者“rollback tran”,则会提交整个事务,最后一行C#代码tran.Commit()就可以不用执行了(执行会报错,因为事务已经结束了-,-)
(3). 开启事务(begin tran)后,才可以调用exec sp_getbindtoken @Token out来取得Token;如果不想再新开的connection中结束掉原有的事务,则在这个connection close之前,必须执行“exec sp_bindsession null”来取消绑定连接,或者在新开的connectoin close之前先结束掉事务(commit/tran)
(4). (Sql server 2005 联机丛书)后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。 请改用多个活动结果集 (MARS) 或分布式事务。

tran = connection.BeginTransaction();
string sql1 = Update Lock1 SET C1=C1+1;
ExecuteNonQuery(tran, sql1);
//使用事务:事务中Lock了测试表Lock1
string sql2 = @”DECLARE @Token varchar(255);
exec sp_getbindtoken @Token out;
SELECT @Token;
;
string token = ExecuteScalar(tran, sql2).ToString();
string sql3 = EXEC sp_bindsession @Token;Update Lock1 SET C1=C1+1;exec sp_bindsession null;;
SqlParameter parameter
= new SqlParameter(@Token, SqlDbType.VarChar);
parameter.Value
= token;
ExecuteNonQuery(
null, sql3, parameter); //新开一个connection来操作测试表Lock1
tran.Commit();

附:锁兼容性(FROM SQL Server 2005 联机丛书)

锁兼容性控制多个事务能否同时获取同一资源上的锁。如果资源已被另一事务锁定,则仅当请求锁的模式与现有锁的模式相兼容时,才会授予新的锁请求。如果请求锁的模式与现有锁的模式不兼容,则请求新锁的事务将等待释放现有锁或等待锁超时间隔过期。

Popularity: 29% [?]

安装Windows Server 2003 SP2可能会影响SQL Server性能

2008年10月7日 admin 1 条评论

安装Windows Server 2003 SP2可能会影响SQL Server性能,大家快打补丁吧 (*^__^*)

Scalable Networking Pack (常见问题 详细描述)在Server 2003安装SP2后会默认被打开,打开此功能可以把对网络数据包的处理从CPU分担一部分到网卡上,但这可能会引起SQL Server性能问题,详情可以看下面的KB:

http://support.microsoft.com/kb/942861

http://support.microsoft.com/kb/918483

另外发现SNP会使SQL Server对事务的吞吐量变小以及使不同查询语句之间的执行间隔变长,比如,有一个事务包含多个查询语句,并且每个语句的执行时间很短,那么他们执行的时间总和应该也会比较短,比如下面的Profiler追踪(注意语句的执行间隔):

image

当SNP开启后,你可以看到下面的Profiler数据,注意其中不同语句的执行间隔,基本都在500ms左右:

image

这种执行间隔明显会影响到并发性,下表显示了SNP启用和禁用后相同工作负荷的执行时间:

Implicit Transaction Summary SNP Enabled

spid TransactionID TranStart TranEnd TranDuration sum_batch_duration batch_count delta
——- ————– ————- ———— ————- ——————– ————– ——–
57 916972 09:40:24.450 09:41:17.623 53173 601 516 52572
57 896243 09:39:31.620 09:40:01.840 30220 322 301 29898
57 877227 09:39:12.120 09:39:15.293 3173 306 161 2867
57 876313 09:38:58.590 09:38:58.603 13 0 1 13
57 895388 09:39:18.510 09:39:18.527 16 16 4 0
57 915675 09:40:02.653 09:40:02.670 16 16 4 0

Implicit Transaction Summary SNP Disabled

spid TransactionID TranStart TranEnd TranDuration sum_batch_duration batch_count delta
——- ————– ———— ———— ————- ——————– ————– ——–
54 127910 11:13:47.287 11:13:52.490 5203 4060 516 1143
54 107344 11:13:23.380 11:13:24.427 1046 382 301 664
51 87187 11:12:50.067 11:12:50.550 483 0 1 483
54 88182 11:13:03.987 11:13:07.237 3250 2878 161 372
51 106432 11:13:10.487 11:13:10.487 0 0 1 0
54 126550 11:13:25.490 11:13:26.007 516 516 4 0

Server 2008 的SNP默认是关闭的,已经装上SP2的Server 2003用户可以通过下面的补丁关闭SNP:http://support.microsoft.com/default.aspx?scid=kb;EN-US;948496 或者使用下面的方法手工关闭:

1. Locate the following registry subkey:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

2. Double-click the EnableTCPChimney registry entry.

3. In the Edit DWORD Value dialog box, type 0 in the Value data box, and then click OK.

4. Double-click the EnableRSS registry entry.

5. In the Edit DWORD Value dialog box, type 0 in the Value data box, and then click OK.

6. Double-click the EnableTCPA registry entry.

7. In the Edit DWORD Value dialog box, type 0 in the Value data box, and then click OK.

8. Restart the server.

Popularity: 25% [?]

SQL server数据页页头参数列表

2008年8月18日 admin 没有评论

SQLserver每个数据页面的页头都是固定的96字节,另外就是真正的数据行以及行偏移矩阵。
掌握页面元数据也是对SQLserver内部组织的一个了解。
其中nextpage 和 prepage参数只有在相应表有聚集索引的时候,才会将页面以链表的形式组织起来,不然,仍然是靠的表扫描(先扫描IAM页)
LSN用于事务管理
行偏移矩阵是用作跟踪数据在磁盘上的真正位置,以及与逻辑位置的对应关系。顺便说一下即使表有聚集索引,行存储的物理位置仍然不是按照索引顺序,真正的物理位置顺序由操作系统决定。只是建立了聚集索引,表数据行的逻辑顺序才跟索引顺序一致。
使用DBCC PAGE可以对其进行查看。

字段 包含

pageID 该页面在数据库中的文件编号和页码

nextPage 如果该页面处于一个页面链中,那么该字段表示下一个页面的案件编号和页码

prevPage 如果该页面处于一个页面链中,那么该字段表示上一个页面的案件编号和页码

objID 该页面所属的对象的ID

lsn 用于更改和更新该页面的日志序列号(LSN)值

slotCnt 该页面中所用的总的槽(行)数

level 该页面在索引中的级别(对于叶页通常为0)

indexId 该页面的索引ID(对于数据页面通常为0)

freeData 该页面中的第一个自由空间的字节偏移量

pminlen 行的固定长度部分的字节数

freeCnt 页面中的自由字节数

reservedCnt 由所有事务预留的字节数

xactresenved 由最近启动的事务预留的字节数

tornBits 每个扇区1位,用于检测残缺页的写

flagBits 包含关于页面其他信息的2字节位图

顺便说一句,从这个链接
http://www.1huifu.com/Get/dr-doc/09_32_25_1917.htm
的一篇文章类似sqlserver2005技术内幕之存储引擎的第209页的内容极度重合,后搜到作者相关书籍:
http://www.golden-book.com/booksinfo/52/522761.html
哎,天下文章一大抄。

Popularity: 14% [?]

微软官方SQL Server 2008正式中文试用版下载

2008年8月8日 admin 2 条评论

昨天在浏览微软的网站时,发现在8月4日微软已经发布了SQL2008的中文版,到现在还没人发到这里来,所以就想发出来给大家一起分享!
下载要注册,不过经常玩MS网站的话,注册下又没关系啦!下面是下载地址!本人第一次在这里发东东,希望大家喜欢!

^_^

Microsoft® SQL Server® 2008 Enterprise Evaluation:开发人员试用体验
http://www.microsoft.com/downloads/details.aspx?FamilyId=6B10C7C1-4F97-42C4-9362-58D4D088CD38&displaylang=zh-cn

Microsoft® SQL Server® 2008 Enterprise Evaluation:IT 专业人员试用体验
http://www.microsoft.com/downloads/details.aspx?familyid=265F08BC-1874-4C81-83D8-0D48DBCE6297&displaylang=zh-cn

SQL Server 2008 发行说明
http://www.microsoft.com/downloads/info.aspx?na=90&p=&SrcDisplayLang=zh-cn&SrcCategoryId=&SrcFamilyId=daf00920-7214-418a-a4b0-727f4ce08f81&u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f9%2ff%2fe%2f9fe7971b-cea6-4f67-ac49-d7fc82a75119%2fReleaseNotesSQLServer2008_CHS.htm

Microsoft SQL Server 2008 联机丛书
http://www.microsoft.com/downloads/info.aspx?na=90&p=&SrcDisplayLang=zh-cn&SrcCategoryId=&SrcFamilyId=765433f7-0983-4d7a-b628-0a98145bcb97&u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f1%2f3%2f2%2f1321c45a-aab0-4033-9d82-f0862edc8418%2fSQLServer2008_BOL_CHS.msi

Popularity: 23% [?]

SQL2005新增函数

2008年8月8日 admin 2 条评论

SQL2005新增了几个结果集行号、排名、分组等函数,给我们带来了很大的方便。

1. ROW_NUMBER函数
返回结果集分区内行的序列号。SQL表是基于集合的,没有像DBF,ACCESS这样的记录行的概念。ROW_NUMBER函数返回行号不是数据表的物理行号,而是结果集分区内行的序列号。

如:SELECT ROW_NUMBER() OVER (ORDER BY ProdCode) AS rownum, * FROM t_Product

返回基于列ProdCode排序集合的行号。利用ROW_NUMBER 及 OVER排序子句,我们可以实现数据分页功能,而以前要比较复杂的代码才能实现。

SELECT TOP(10) prodcode,name FROM ( SELECT prodcode,name, ROW_NUMBER() OVER (ORDER BY prodcode) AS ROW_Number FROM t_product) as T WHERE Row_Number > ((5 – 1) * 10)

这条语句显示产品表的第5页 ,每页10行记录。

2. 分组 NTITLE

NTITLE函数将指定数据集划分成N个组,分组时由Orderby指定排序列。如将产品表划分成10个组:

Select prodcode,name,ProdTypeCode,NTile(10) OVER(ORDER BY ProdTypeCode) AS NTile From t_product

3. RANK、DENSE_RANK排名函数

排名函数很容易实现诸如销售排名报表这样的功能,同ROW_NUMBER、NTITLE一样需要指定OVER 排名窗口函数,确定行集的分区和排序。如实现按业务员的销量排名表。

Select prodid,Sum(quantity) as Total,Rank() OVER(ORDER BY Sum(quantity) desc) AS Rank From secontdetl Group by prodid

运行结果如下:

DENSE_RANK与RANK不同的是返回指定元组在指定集中的排名(排名从 1 开始),但排名号不间断。即如果有2个并列第1名,那么RANK函数第3行记录将是排名3,而DENSE_RANK是2.

Popularity: 17% [?]

数据库同步

2008年7月9日 admin 没有评论

不同服务器数据库之间的数据操作

–创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
exec sp_addlinkedsrvlogin ‘ITSV ‘, ‘false ‘,null, ‘用户名 ‘, ‘密码 ‘

–查询示例
select * from ITSV.数据库名.dbo.表名

–导入示例
select * into 表 from ITSV.数据库名.dbo.表名

–以后不再使用时删除链接服务器
exec sp_dropserver ‘ITSV ‘, ‘droplogins ‘

–连接远程/局域网数据(openrowset/openquery/opendatasource)
–1、openrowset

–查询示例
select * from openrowset( ‘SQLOLEDB ‘, ’sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–生成本地表
select * into 表 from openrowset( ‘SQLOLEDB ‘, ’sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–把本地表导入远程表
insert openrowset( ‘SQLOLEDB ‘, ’sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)
select *from 本地表

–更新本地表
update b
set b.列A=a.列A
from openrowset( ‘SQLOLEDB ‘, ’sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)as a inner join 本地表 b
on a.column1=b.column1

–openquery用法需要创建一个连接

–首先创建一个连接创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
–查询
select *
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
–把本地表导入远程表
insert openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
select * from 本地表
–更新本地表
update b
set b.列B=a.列B
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘) as a
inner join 本地表 b on a.列A=b.列A

–3、opendatasource/openrowset
SELECT *
FROM opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘ ).test.dbo.roy_ta
–把本地表导入远程表
insert opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘).数据库.dbo.表名
select * from

Popularity: 10% [?]