<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
	<channel>
		<title>金麦网络</title>
		<link>http://www.kingmx.com</link>
		<copyright>Copyright (C) 2006 金麦网络-Kingmx.com All Rights Reserved.</copyright>
		<item>
			<title>改善SQL Server数据库的内存管理方法</title>
			<link>http://www.kingmx.com/article.php?id=14965</link>
			<pubDate>2007-1-18</pubDate>
			<description><![CDATA[
最近，为了能在数据库服务器中运行其他应用程序，在保持数据库操作系统版本不变的前提下对数据库服务器进行了软、硬件上的升级。在软件上，将操作系统从Windows 2000升级到Windows Server 2003；在硬件上，将服务器中的内存由原来的512MB增加到1GB（1024MB）。 

在升级后的开始几个星期之内，服务器在使用中表现良好。但是不久后就发现，在服务器上同时运行的其他应用程序却出现了异常，不时地报出内存分配不足的警告。经过几次跟踪后发现，原来是SQL Server吞去了大部分内存所致。被SQL Server占用的内存由升级前的不到400MB一下子增加到现在的900MB，并且有不断增长的趋势。 

通过查找原因才知道这是SQL Server 缓冲池的预期行为。默认情况下，在启动 SQL Server之后，SQL Server会根据操作系统报告的物理内存数来动态增大或缩小高速缓冲存储器的容量。只要可用物理内存大小保持在4MB到10MB之间，SQL Server 缓冲池就会继续增大（保留可用物理内存在4MB到10MB之间是为了避免操作系统因为缺少内存而频繁地换页）。如果物理可用内存变得较少的时候，则SQL Server会将一些内存释放给操作系统。 

为了使运行在服务器上的应用程序都能达到比较满意的效果，同时也为了能给其他应用程序分配足够的内存，需要采取措施限制SQL Server 的内存使用量。我们可以通过设置SQL Server 数据库引擎使用的内存的上下限来达到此目的。其具体步骤是： 

1.打开企业管理器，展开服务器组。 

2.单击该服务器，点击鼠标右键，单击属性菜单。 

3.在弹出的对话框中单击内存选项卡。 

内存设置方法有两种： 

1.设置min server memory和max server memory 在一个范围段内。 

比如，我们将它设置成最小0MB，最大255MB。这种方法在为一台服务器中运行多个应用程序分配内存时非常有用。 

2.设置 min server memory 和 max server memory 为同一数值。 

比如，可以将它最大和最小值都设置成255MB。这样的设置方法与窗口中的另一个选项“使用固定的内存大小” 相一致。 

虽然内存最小值和最大值设置是高级选项，但在设置完毕之后，最好还是先将SQL Server服务停止后再重新运行，以便SQL Server能更好地对内存进行合理安排。
]]></description>
		</item>
		<item>
			<title>SQL Server数据库崩溃后的恢复之法</title>
			<link>http://www.kingmx.com/article.php?id=14963</link>
			<pubDate>2007-1-18</pubDate>
			<description><![CDATA[

任何数据库系统都无法避免崩溃的状况，即使你使用了Clustered，双机热备……仍然无法完全根除系统中的单点故障，何况对于大部分用户来说，无法承受这样昂贵的硬件投资。所以，在系统崩溃的时候，如何恢复原有的宝贵数据就成为一个极其重要的问题了。 

在恢复的时候，最理想的情况就是你的数据文件和日志文件都完好无损了，这样只需要sp_attach_db，把数据文件附加到新的数据库上即可，或者在停机的时候把所有数据文件(一定要有master等)都copy到原有路径下也行，不过一般不推荐这样的做法，sp_attach_db比较好，虽然麻烦许多。 

但是呢，一般数据库崩溃的时候系统是未必能有时间把未完成的事务和脏页等写入磁盘的，这样的情况sp_attach_db就会失败。那么，寄期望于DBA制定了一个良好的灾难恢复计划吧。按照你的恢复计划，还原最新的完全备份，增量备份或者事务日志备份，然后如果你的活动事务日志还能读得出来的话，恭喜你!你可以还原到崩溃前的状态。 

一般的单位都是没有专职的DBA的，如果没有可用的备份，更可能是最近一次备份的时间过于久远而导致不可接受的数据损失，而且你的活动事务日志也处于不可用的状态，那就是最麻烦的情况了。 

不幸的很的是，一般数据库崩溃都是由于存储子系统引起的，而这样的情况是几乎不可能有可用的日志用于恢复的。 

那么就只好试一下这些方案了。当然，是要求至少你的数据文件是存在的，要是数据文件、日志文件和备份都没有了的话，别找我，你可以到楼顶上去唱“神啊，救救我吧”。 

首先，你可以试一下sp_attach_single_file_db，试着恢复一下你的数据文件，虽然能恢复的可能性不大，不过假如这个数据库刚好执行了一个checkpoint的话，还是有可能成功的。 

如果你没有好到有摸彩票的手气，最重要的数据库没有像你期盼的那样attach上去，不要气馁，还是有别的方案的。 

我们可以试着重新建立一个log，先把数据库设置为emergency mode，sysdatabases的status为32768 就表示数据库处于此状态。 

不过系统表是不能随便改的，设置一下先 






Use MasterGosp_configure 'allow updates', 1reconfigure with overrideGo

然后 






update sysdatabases set status = 32768 where name = ''

现在，祈求满天神佛的保佑吧，重新建立一个log文件。成功的机会还是相当大的，系统一般都会认可你新建立的日志。如果没有报告什么错误，现在就可以松一口气了。 

虽然数据是恢复了，可是别以为事情就算完成了，正在进行的事务肯定是丢失了，原来的数据也可能受到一些损坏。 

先把SQL Server 重新启动一下，然后检查你的数据库吧。 

先设置成单用户模式，然后做 






dbcc sp_dboption '', 'single user', 'true'DBCC CHECKDB('')

如果没有什么大问题就可以把数据库状态改回去了，记得别忘了把系统表的修改选项关掉。 






update sysdatabases set status = 28 where name = ''

当然你的数据库状态可能不是这个，自己改为合适的值吧。也可以用 






sp_resetstatusgosp_configure 'allow updates', 0reconfigure with overrideGo

Checkdb的时候可能报告有一些错误，这些错误的数据你可能就只好丢弃了。 

Checkdb有几种修复选项，自己看着用吧，不过最后你可能还是得REPAIR_ALLOW_DATA_LOSS，完成所有修复。 

Chekcdb并不能完成所有的修复，我们需要更进一步的修复，用DBCC CHECKTABLE对每一个表做检查吧。 

表的列表可以用sysobjects里面得到，把OBJECTPROPERTY是IsTable的全部找出来检查一下吧，这样能够基本上解决问题了，如果还报告错误，试着把数据select into到另一张表检查一下。 

这些都做完了之后，把所有索引、视图、存储过程、触发器等重新建立一下。DBCC DBREINDEX也许可以帮你一些忙。
]]></description>
		</item>
		<item>
			<title>优化SQL Server数据库服务器内存配置（3）</title>
			<link>http://www.kingmx.com/article.php?id=14899</link>
			<pubDate>2007-1-6</pubDate>
			<description><![CDATA[
3使用tempinRAM 
SQL Server使用tempdb临时数据库作为一些查询连接操作时排序或创建临时表的工作空间。将tempdb创建在RAM中可以使系统操作性能有较大提高，而且因为tempdb在每次重启动服务器时都重建，这样即使有非正常的关闭也是较为安全的，例如停电故障。要将tempdb创建在RAM中，可以使用sp_configure进行设置，具体用法请参阅有关资料。 
由于tempdbinRAM使用的内存是由系统从内存体单独分配的，与SQL Server的内存选项设置的可用内存池是分开的，使用tempdbin RAM将减少整个系统的可用内存，应根据SQL Server和服务器运行情况进行配置，否则就可能适得其反，影响系统性能。另外，适当增加tempdb数据库空间，即使不使用tempdbin RAM，也可以提高数据库的运行速度。 
4注意事项 
(1)建议在生产环境中SQL Server不要设置小于32MB内存，而且数据库服务器上尽量不要运行其它应用程序； 
(2)扩充供虚拟内存、增大SQL Server可用内存，应考虑物理内存使用状况和磁盘空间许可情况； 
(3)在可能的情况下，要为系统留有部分额外的内存，这样在服务器上打开一个服务或添加一个进程且不改变SQL Server内存配置时，不致于使NT服务器的运行速度受到影响(变得很慢)，一般认为最小为2MB最大为20MB。 
四、巧用内存配置，解决统计服务器问题 
一单位的统计服务器投入使用后，运行速度较慢，经排查原因，发现SQLServer中的内存选项(Memory)仅为安装缺省值——16MB(而服务器有128MB的物理内存)，在将内存值调整为100MB时却误将其改成了 1000MB，使得SQL Server服务不能启动，统计数据库打不开，也就不能再次进入SQL Enterprise Manager修改内存设置了。由于近期未备份业务数据，不到万不得已不能重装SQLServer数据库，就试图用命令行参数命令来重新启动SQL Server服务，但均不能奏效，陷入了困境。我们经过仔细分析提出：既然SQL Server可用内存设置值远远大于物理内存，造成SQLServer服务不能启动，何不扩充虚拟内存呢?经设法将机器虚拟内存扩充至1000MB并重新启动，SQL Server数据库成功启动，问题迎刃而解。 
五、结束语 
目前，大多数单位投入使用的Microsoft SQL Server数据库服务器的物理内存一般都在64MB以上，如农业银行省、市分行的统计服务器配备128MB物理内存，只要按照上面提出的方法合理规划、优化NT和SQL Server的内存配置，使设置尽可能达到最优，应用系统就一定能够充分发挥设计功能、满足业务需求。 
]]></description>
		</item>
		<item>
			<title>优化SQL Server数据库服务器内存配置（2）</title>
			<link>http://www.kingmx.com/article.php?id=14898</link>
			<pubDate>2007-1-6</pubDate>
			<description><![CDATA[
4注意事项 
(1)合理确定分页文件的最大值，根据系统需求随时进行调整，使用过多虚拟内存将导致整个系统处理性能的下降。设置虚拟内存最大值的目的是使用户不必在WindowsNT的交换文件上消耗过多的磁盘空间，通常情况下如果超过了系统需要的最佳值后，生成交换文件的磁盘空间就被浪费了。 
(2)尽可能设立专用硬盘配置内存交换区，或将交换空间放到主硬盘的另一个分区，同时应将主硬盘的交换文件大小降至16MB，这样主硬盘(分区)仅用来放置操作系统和应用程序，就可以减少交换次数，防止频繁交换耗费大量 CPU时间。 
(3)虚拟内存技术的确改善了Windows NT系统的性能，但也受到机器硬盘空间大小、硬盘速度、处理器 (CPU)速度的影响，从理想角度出发，要提高计算机的性能就必须减少交换操作的次数，但是没有一个WindowsNT计算机不发生交换，这就要求计算机要有足够的物理内存，以保持最少的交换操作。 
三、优化Microsoft SQL Server数据库内存配置 
内存是影响Microsoft SQL Server系统性能的一个重要因素，SQL Server数据库安装时将为具有32MB物理内存的机器缺省配置16MB可用内存，16MB物理内存的机器缺省配置4MB可用内存。应在Microsoft SQL Server数据库安装后进行内存选项(Memory)设置，最大配置值为2GB。 
为了确定SQL Server系统最适宜的内存需求，可以从总的物理内存中减去Windows NT4.0需要的内存以及其它一些内存需求后综合确定，理想的情况是给SQL Server分配尽可能多的内存，而不产生页面调度。 
1根据物理内存合理规划SQL Server可用内存 
在大多数的生产环境中，服务器配备的物理内存是64MB～128MB，偶尔也有256MB的，只要配置恰当是完全可以满足SQL Server的内存需求的。下表是笔者关于SQL Server内存分配的建议规划，供参考。 
物理内存 分配给SQL Server 设置值(单位：2KB) 





8MB 4MB 2048 
16MB 8MB 4096 
32MB 16～18MB 8192～9216 
48MB 28～34MB 14336～17408 
64MB 40～46MB 20480～23552 
128MB 100～108MB 51200～55296 
256MB 216～226MB 110592～115712 
512MB 464～472MB 237568～241664

以下是SQL Server内存选项(Memory)设置方法 
(1)从Microsoft SQL Server程序集中启动SQL Enterprise Manager； 
(2)从Server Manager窗口中选择“Server”菜单选项； 
(3)在“Server”菜单中选择“Configurations”选项； 
(4)在“Server Configuration”对话框中选择”Configuration”标签，Configuration窗口显示配置选项列表； 
(5)选中“Memory”项目，在“Current”栏填入新值； 
(6)停止并重新启动SQLServer服务，使设置生效。 
2合理扩充虚拟内存、增大SQL Server可用内存 
当SQL Server系统确实需要扩大可用内存时，应在磁盘空间充足的情况下扩充供虚拟内存，并相应增大 SQL Server可用内存。具体做法是，系统管理员首先扩充服务器的虚拟内存，然后再参考上表增大SQL Server可用内存，关键是要根据系统的负载情况综合决定是否扩充内存、优化配置。 
]]></description>
		</item>
		<item>
			<title>优化SQL Server数据库服务器内存配置（1）</title>
			<link>http://www.kingmx.com/article.php?id=14897</link>
			<pubDate>2007-1-6</pubDate>
			<description><![CDATA[
前言 
农业银行总行1998年以来正式推广了新版网络版综合业务统计信息系统，该系统是基于WindowsNT4.0平台，采用客户／服务器模式，以Microsoft SQL Server为基础建立起来的大型数据库应用程序，系统界面友好、操作简便，计算、分析、检索功能非常强大，为保证农业银行系统及时进行纵向和横向业务数据采集、按照不同要求生成统计报表，进行全面业务活动分析提供了强有力的保障。但在这套程序的推广、维护中笔者发现系统有时运行速度较慢，特别是在Win95客户端操作时尤为严重，经过排除网线连接等硬件可能带来的影响后上述问题仍然存在。笔者经过仔细摸索，发现系统对硬、软件的要求较高，为充分发挥设计效能，达到最佳运作效果，需要对计算机硬、软件系统进行较为完备的性能测试与最佳配置，特别是内存配置的好坏对系统的运行速度具有决定性的作用。下面，笔者就如何优化SQLServer数据库服务器的内存配置提出一些认识和看法。 
一、有关内存的基本概念 
1物理内存与虚拟内存 
WindowsNT使用两类内存：物理内存与虚拟内存。 
物理内存：作为RAM芯片安装在计算机内部的存储器。 
虚拟内存：用于模拟RAM芯片功能的磁盘(硬盘)空间，其实质是通过将内存中当前没有使用的部分内容临时存储到磁盘上，使系统可以使用到比机器物理内存更多的内存。 
2分页和分页文件 
WindowsNT系统通过使用磁盘空间使得对内存的需求得到部分缓解，从而使用到比物理内存更多内存的技术就称为“交换”或分页，也就是通常所说的虚拟内存技术。通常Windows NT 4.0系统安装时将在引导驱动器上设置一个大小为16MB的交换(分页)文件(pagefile.sys)。 
二、优化Windows NT 4.0系统内存配置 
在大多数情况下，为了充分发挥Windows NT 4.0系统效能，内存的作用比起处理器的处理能力更具有影响力，特别是在客户／服务器模式环境下更是如此，因为通常在这种环境下并不十分强调处理器的能力，相反却十分注重是否采用足够的内存来满足各个客户的应用需要。此外，为了获得容错功能和保护应用程序，保证应用程序高速运行、充分发挥设计功能都需要有足够多的内存，特别是工业绘图设计和各种工程应用程序更需要占用大量的内存来进行复杂的计算。 
物理内存(RAM)方便快速的优点显而易见，但由于其价格昂贵，也就不可能做到多多益善了，因此通过合理优化内存配置、扩充虚拟内存提高计算机运算速度也就成了一项很重要的应用技术手段。 
1保证Windows NT系统基本内存需求 
Windows NT 4.0系统至小应配置12MB内存，16MB内存基本够用，正常情况下保证NT系统有32MB内存就可以了，因为并不是所有的16MB基本内存在任何时候都被同时使用。如果添加一些服务和应用程序，则对内存的需求就会急剧增大。如： 
(1)添加网络服务需要4MB内存空间； 
(2)容错功能和系统保护功能需要8MB内存(如磁盘镜像和分条功能)； 
(3)进行图形图象处理需要增加16MB内存空间； 
(4)安装VC、VB开发系统需要增加16MB内存空间； 
另外，如在Windows NT上构建大型数据库如SYBASE、Microsoft SQL Server等，对内存的需求就更多了。 
2优化内存性能 
为了使WindowsNT不至于过分占用较多的内存或者浪费处理器的时间用于换页，可以采用以下方法优化内存性能。 
(1)减少显示颜色的数量； 
(2)降低显示分辨率； 
(3)尽可能不使用或使用位宽度较小的墙纸； 
(4)关闭不需要的服务程序或驱动程序，尽量不要在服务器上使用其它应用程序。 
停用服务或驱动程序的操作步骤如下： 
①确定需要停用的服务或驱动程序的名称； 
②从“控制面板”中双击“服务”或“设备”图标； 
③在列表中选择想要停用的服务或设备驱动程序的名称，单击“停止”按钮，这时出现确认操作对话框； 
④选择“是”确认操作，然后关闭对话框完成设置。 
3优化虚拟内存 
在对Windows NT虚拟内存进行设置时需要合理确定各个驱动器分页文件的“起始大小”和“最大值”两个参数，它们用于指定分页文件的起始空间和最大空间。下面对这两个参数作一些解释： 
起始大小：指初始创建该分页文件时的文件大小，单位为MB，根据缺省设置，这个值被设置为系统中的物理内存的大小。 
最大值：指出该分页文件的最大尺寸，单位为MB。 
(1)分页文件的设置原则： 
①分页文件起始大小应保留缺省设置，一般情况下请不要改动； 
②分页文件理想的最大尺寸为系统物理内存尺寸的2.5倍至4倍。需要说明的是：如果系统工作时不需要大量内存，请选择靠近下限的值，即用系统物理内存的2.5倍作为这个尺寸的起始值；如果系统工作时需要大量内存，请选择靠近上限的值。 
(2)Windows NT虚拟内存设置步骤： 
①从“控制面板”中双击“系统”图标； 
②在“系统特性”对话框中单击“性能”标签； 
③在虚拟内存对话框中单击“更改”按钮，这时出现“虚拟内存”对话框，上端的驱动器框逐一列出了 Windows NT所有页面文件的大小； 
④在驱动器列表中，选择需要设置分页文件的驱动器盘符，在“驱动器页面文件大小”对话框中列出了 “起始大小”和“最大值”两个参数栏，填入按照上面的原则确定的数值； 
⑤单击“设置”确认以上操作，然后依次单击“确定”按钮退出各个对话框，完成设置。 
(3)Win95／98虚拟内存设置。 
Win95／98虚拟内存设置方法、步骤和原则与Windows NT 4.0的设置大致相同，请参照上面Windows NT的设置。
]]></description>
		</item>
		<item>
			<title>数据库远程复制和异地容灾方案相关分析</title>
			<link>http://www.kingmx.com/article.php?id=14843</link>
			<pubDate>2006-12-22</pubDate>
			<description><![CDATA[

目前，针对oracle数据库的远程复制、容灾主要有以下几种技术或解决方案： 

（1）基于存储层的容灾复制方案 

这种技术的复制机制是通过基于SAN的存储局域网进行复制，复制针对每个IO进行，复制的数据量比较大;系统可以实现数据的同步或异步两种方式的复制.对大数据量的系统来说有很大的优势（每天日志量在60G以上）,但是对主机、操作系统、数据库版本等要求一致，且对络环境的要求比较高。 

目标系统不需要有主机，只要有存储设备就可以，如果需要目标系统可读，需要额外的配置和设备，比较麻烦。 

（2）基于逻辑卷的容灾复制方案 

这种技术的机制是通过基于TCP/IP的网络环境进行复制，由操作系统进程捕捉逻辑卷的变化进行复制。其特点与基于存储设备的复制方案比较类似，也可以选择同步或异步两种方式，对主机的软、硬件环境的一致性要求也比较高，对大数据量的应用比较有优势。其目标系统如果要实现可读，需要创建第三方镜像。个人认为这种技术和上面提到的基于存储的复制技术比较适合于超大数据量的系统，或者是应用系统的容灾复制。 

（3）基于oracle redo log的逻辑复制方式 

使用这种方式的主要有一些第三方的软件，以及oracle自己的DATAGUARD 中的logical Standby。目前，国外已经有了很多比较成熟的产品及成功案例，国内也有类似的产品， 但在产品的成熟程度和成功案例上跟国外还有一定的差距。 

这类产品的原理基本相同，其工作过程可以分为以下几个流程： 

使用oracle以外的独立进程，捕捉redo log file 的信息，将其翻译成sql语句，再通过网络传输到目标端数据库，在目标端数据库执行同样的sql。如果其进程赶不上oracle日志切换，也可以捕捉归档日志中的内容。也有的产品在源端以事务为单位，当一个事务完成后，再把它传输到目标端。所有的产品一般都是以表为单位进行复制，同时也支持大部分DDL的复制（主要在oracle9i环境中）。 

这种技术的技术特点和优势主要有以下几点： 

目标端数据库一直是一个可以访问的数据库； 

能保证两端数据库的事务一致性； 

因为使用oracle以外的进程进行捕捉，且其优先级低于oracle进程，所以对源系统数据库的性能影响很小； 

基于其实现原理及多个队列文件的使用，复制环境可以提供网络失败、数据库失败、主机失败的容错能力； 

因为这类软件复制的只是sql语句或事务，所以他可以完全支持异构环境的复制，硬件的型号，oracle的版本，操作系统的种类、版本等都没有要求。 

这种方式还可以支持多种复制方式，比如数据集中、分发、对等复制、或者多层测的复制等。 

由于传输的内容只是redolog 或archive log中的一部分，所以对网络资源的占用很小，可以实现不同城市之间的远程复制。 

基于redolog的逻辑复制产品有很多的优势，但跟上面提到过的其他方案比较起来，也有一些缺点： 

数据库的吞吐量太大时，其实据会有较大的延迟，当数据库每天的日量达到60G或更大时，这种方案的可行性交差； 

实施的过程可能会有一些停机时间，来进行数据的同步和配置的激活； 

复制环境建立起来以后，对数据库结构上的一些修改需要按照规定的操作流程进行，有一定的维护成本。 

不过目前这类产品的发展很快，上面的这些问题，在大部分产品的最新版本中都有很大的改进。
]]></description>
		</item>
		<item>
			<title>基于规则的优化机制对表达式的处理</title>
			<link>http://www.kingmx.com/article.php?id=14817</link>
			<pubDate>2006-12-20</pubDate>
			<description><![CDATA[

ORACLE优化器在任何可能的时候都会对表达式进行评估，并且把特定的语法结构转换成等价的结构，这么做的原因是： 

· 要么结果表达式能够比源表达式具有更快的速度。 

· 要么源表达式只是结果表达式的一个等价语义结构。 

不同的SQL结构有时具有同样的操作（例如：= ANY (subquery) and IN (subquery)），ORACLE会把他们映射到一个单一的语义结构。 

下面将讨论优化器如何评估优化如下的情况和表达式：常量 LIKE 操作符 IN 操作符 ANY和SOME 操作符 ALL 操作符 BETWEEN 操作符 NOT 操作符 传递（Transitivity） 确定性（DETERMINISTIC）函数。 

常量 

常量的计算是在语句被优化时一次性完成，而不是在每次执行时。下面是检索月薪大于2000的的表达式： 






　　
　　· sal &gt; 24000/12
　　
　　· sal &gt; 2000
　　
　　· sal*12 &gt; 24000

　　 如果SQL语句包括第一种情况，优化器会简单地把它转变成第二种。 

注意：优化器不会简化跨越比较符的表达式，例如第三条语句，鉴于此，应用程序开发者应该尽量写用常量跟字段比较检索的表达式，而不要将字段置于表达式当中。 

LIKE 操作符 

优化器把使用LIKE操作符和一个没有通配符的表达式组成的检索表达式转换为一个“=”操作符表达式。 

例如：优化器会把表达式ename LIKE 'SMITH'转换为ename = 'SMITH'优化器只能转换涉及到可变长数据类型的表达式，前一个例子中，如果ENAME字段的类型是CHAR(10)， 那么优化器将不做任何转换。 

IN 操作符 

优化器把使用IN比较符的检索表达式替换为等价的使用“=”和“OR”操作符的检索表达式。例如，优化器会把表达式ename IN ('SMITH','KING','JONES')替换为: 






　　
　　ename = 'SMITH' OR ename = 'KING' OR ename = 'JONES'

　　 ANY和SOME 操作符 

优化器将跟随（following）值列表的ANY和SOME检索条件用等价的同等操作符和“OR”组成的表达式替换。 

例如，优化器将如下所示的第一条语句用第二条语句替换： 






　　
　　· sal &gt; ANY (:first_sal, :second_sal)
　　
　　· sal &gt; :first_sal OR sal &gt; :second_sal

　　 优化器将跟随子查询的ANY和SOME检索条件转换成由“EXISTS”和一个相应的子查询组成的检索表达式。 

例如，优化器将如下所示的第一条语句用第二条语句替换： 






　　
　　· x &gt; ANY (SELECT sal FROM emp WHERE job = 'ANALYST')
　　
　　· EXISTS (SELECT sal FROM emp WHERE job = 'ANALYST' AND x &gt; sal)

　　 ALL 操作符 

优化器将跟随值列表的ALL操作符用等价的“=”和“AND”组成的表达式替换。 

例如，sal &gt; ALL (:first_sal, :second_sal)表达式会被替换为： 






　　
　　sal &gt; :first_sal AND sal &gt; :second_sal

　　 对于跟随子查询的ALL表达式，优化器用ANY和另外一个合适的比较符组成的表达式替换。例如，优化器会把表达式 x &gt; ALL (SELECT sal FROM emp WHERE deptno = 10) 替换为： 






　　
　　NOT (x &lt;= ANY (SELECT sal FROM emp WHERE deptno = 10))

　　 接下来优化器会把第二个表达式适用ANY表达式的转换规则转换为下面的表达式： 






　　
　　NOT EXISTS (SELECT sal FROM emp WHERE deptno = 10 AND x &lt;= sal)

BETWEEN 操作符 

优化器总是用“&gt;=”和“&lt;=”比较符来等价的代替BETWEEN操作符。例如：优化器会把表达式sal BETWEEN 2000 AND 3000用sal &gt;= 2000 AND sal &lt;= 3000来代替。 

NOT 操作符 

优化器总是试图简化检索条件以消除“NOT”逻辑操作符的影响，这将涉及到“NOT”操作符的消除以及代以相应的比较运算符。 

例如，优化器将下面的第一条语句用第二条语句代替： 






　　
　　· NOT deptno = (SELECT deptno FROM emp WHERE ename = 'TAYLOR')
　　
　　· deptno &lt;&gt; (SELECT deptno FROM emp WHERE ename = 'TAYLOR')

　　 通常情况下一个含有NOT操作符的语句有很多不同的写法，优化器的转换原则是使“NOT”操作符后边的子句尽可能的简单，即使可能会使结果表达式包含了更多的“NOT”操作符。例如，优化器将如下所示的第一条语句用第二条语句代替： 






　　
　　· NOT (sal &lt; 1000 OR comm IS NULL)
　　
　　· NOT sal &lt; 1000 AND comm IS NOT NULL sal &gt;= 1000 AND comm IS NOT NULL

　　 传递（Transitivity） 

如果“WHERE”子句的两个检索条件涉及了一个共同的字段，优化器有时会根据传递原理推断出第三个检索条件，随后可以根据这个推断出的条件对语句进行优化，推断出的条件可能会激活一个原来的检索条件没有激活的潜在的接口路径（access path）。注意：传递仅仅被用在基于代价（cost-based）的优化中。 

假设有一个这样的包含两个检索条件的“WHERE”子句：WHERE 字段1 常量 AND字段1 = 字段2，在这个例子里，优化器会推断出新的检索条件：字段2 常量。在这里，是比较运算符=、!=、^=、&lt;&gt;、&gt;、&lt;= 或 &gt;=之中的任何一个，常量是指任何一个涉及了操作符、SQL函数、文字、绑定变量（bind variables）或者关联变量（correlation variables）的常量表达式。 

例如，考虑这样一个包含两个各自使用了字段EMP.DEPTNO的检索条件的WHERE子句的查询： 






　　
　　SELECT * FROM emp, dept WHERE emp.deptno = 20 AND emp.deptno = dept.deptno;
　

　 使用传递优化，优化器会推断出如下条件：dept.deptno = 20。如果有索引存在于EMP.DEPTNO字段上，这个条件会使调用这个索引的接口路径有效。注意：优化器只能对字段关联常量的表达式进行推断，而不是字段关联字段的表达式。例如，包含这样条件的WHERE子句：字段1 字段3 AND 字段1 = 字段2，这种情况不能推断出表达式：字段2 &lt; comp_oper&gt; 字段3。 

确定性（DETERMINISTIC）函数 

在某些情况下，优化器能够使用先前的函数返回结果而不是重新执行用户定义的函数，这仅仅对那些以限制的方式来执行的函数来说是有效的。这些函数必须对任何的输入都有同样的返回值，函数的结果必须不能因为包（PACKAGE）变量、数据库或会话（SESSION）的参数（例如NLS参数）不同而变化，如果函数在将来重新定义，返回值必须对任何参数来说仍然与以前的返回值相同。函数的创建者可以在以CREATE FUNCTION、CREATE PACKAGE或者CREATE TYPE声明函数时根据以上的要求使用DETERMINISTIC关键字向数据库申明该函数为确定性函数，数据库不会对确定性函数的合法性进行校验，即使一个函数明显的使用了包变量或操作了数据库，仍然可以被定义为确定性函数，这就是说如何安全合法的使用和定义确定性函数是程序员的责任。 

当确定性函数在同一个查询里被多次调用，或者被基于函数的索引或物化视图（materialized view）调用时，有可能被一个已经计算出的值取代。
]]></description>
		</item>
		<item>
			<title>SQL Server 中调整自增字段的当前初始值</title>
			<link>http://www.kingmx.com/article.php?id=14816</link>
			<pubDate>2006-12-20</pubDate>
			<description><![CDATA[

前几天在把一个Communtiy Server 的数据库从SQL 2000升级到SQL 2005 的时候，碰到一个怪异的问题，报如下错误：

Violation of PRIMARY KEY constraint 'PK_cs_Threads'. Cannot insert duplicate key in object 'dbo.cs_Threads'.

分析进去后，竟然发现这个表的自增字段数据库中已经达到了6144，而数据库维护的这个表的初始自增值只到6109。

解决方法很简单，利用以下SQL 语句即可搞定：

DBCC CHECKIDENT ('cs_Threads')

上述语句的意思就是：如果表'cs_Threads'的当前标识值小于列中存储的最大标识值，则使用标识列中的最大值对其进行重置。

CHECKIDENT 命令可以有以下几种写法：

1、DBCC CHECKIDENT ('table_name', NORESEED) 

不重置当前标识值。DBCC CHECKIDENT 返回一个报表，它指明当前标识值和应有的标识值。 

类似如下的报表：

Checking identity information: current identity value '6109', current column value '6144'.

2、DBCC CHECKIDENT ('table_name') 或DBCC CHECKIDENT ('table_name', RESEED) 

如果表的当前标识值小于列中存储的最大标识值，则使用标识列中的最大值对其进行重置。

上述命令执行的时候，也会报类似上面的报表。

3、DBCC CHECKIDENT ('table_name', RESEED, new_reseed_value) 

当前值设置为 new_reseed_value。

如果自创建表后没有将行插入该表，则在执行 DBCC CHECKIDENT 后插入的第一行将使用 new_reseed_value 作为标识。否则，下一个插入的行将使用 new_reseed_value + 1。

如果 new_reseed_value 的值小于标识列中的最大值，以后引用该表时将产生 2627 号错误信息。
]]></description>
		</item>
		<item>
			<title>SQL Server中数据仓库的构建与分析</title>
			<link>http://www.kingmx.com/article.php?id=14793</link>
			<pubDate>2006-12-17</pubDate>
			<description><![CDATA[

基本概念： 

1．多维数据集：多维数据集是联机分析处理 (OLAP) 中的主要对象，是一项可对数据仓库中的数据进行快速访问的技术。多维数据集是一个数据集合，通常从数据仓库的子集构造，并组织和汇总成一个由一组维度和度量值定义的多维结构。 

2．维度：是多维数据集的结构性特性。它们是事实数据表中用来描述数据的分类的有组织层次结构（级别）。这些分类和级别描述了一些相似的成员集合，用户将基于这些成员集合进行分析。 

3.度量值：在多维数据集中，度量值是一组值，这些值基于多维数据集的事实数据表中的一列，而且通常为数字。此外，度量值是所分析的多维数据集的中心值。即，度量值是最终用户浏览多维数据集时重点查看的数字数据。您所选择的度量值取决于最终用户所请求的信息类型。一些常见的度量值有 sales、cost、expenditures 和 production count 等。 

4．元数据：不同 OLAP 组件中的数据和应用程序的结构模型。元数据描述 OLTP 数据库中的表、数据仓库和数据集市中的多维数据集这类对象，还记录哪些应用程序引用不同的记录块。 

5．级别：级别是维度层次结构的一个元素。级别描述了数据的层次结构，从数据的最高（汇总程度最大）级别直到最低（最详细）级别。 

6．数据挖掘：数据挖掘使您得以定义包含分组和预测规则的模型，以便应用于关系数据库或多维 OLAP 数据集中的数据。之后，这些预测模型便可用于自动执行复杂的数据分析，以找出帮助识别新机会并选择有获胜把握的机会的趋势。 

7．多维 OLAP (MOLAP)：MOLAP 存储模式使得分区的聚合和其源数据的复本以多维结构存储在分析服务器计算机上。根据分区聚合的百分比和设计，MOLAP 存储模式为达到最快查询响应时间提供了潜在可能性。总而言之，MOLAP 更加适合于频繁使用的多维数据集中的分区和对快速查询响应的需要。 

8．关系 OLAP (ROLAP)：ROLAP 存储模式使得分区的聚合存储在关系数据库的表（在分区数据源中指定）中。但是，可为分区数据使用 ROLAP 存储模式，而不在关系数据库中创建聚合。 

9．混合 OLAP (HOLAP)：HOLAP 存储模式结合了 MOLAP 和 ROLAP 二者的特性。 

10．粒度：数据汇总的层次或深度。 

11．聚合|聚集：聚合是预先计算好的数据汇总，由于在问题提出之前已经准备了答案，聚合可以改进查询响应时间。 

12．切块：由多个维的多个成员限定的分区数据，称为一个切块。 

13．切片：由一个维的一个成员限定的分区数据，称为一个切片。 

14．数据钻取：最终用户从常规多维数据集、虚拟多维数据集或链接多维数据集中选择单个单元，并从该单元的源数据中检索结果集以获得更详细的信息，这个操作过程就是数据钻取。 

15．数据挖掘模型：数据挖掘使您得以定义包含分组和预测规则的模型，以便应用于关系数据库或多维 OLAP 数据集中的数据。之后，这些预测模型便可用于自动执行复杂的数据分析，以找出帮助识别新机会并选择有获胜把握的机会的趋势。 

实例构建过程与分析 

1．现在以一个比较简单的实例来分析和探讨MS SQL SERVER 数据仓库的构建过程。实际上数据仓的构建是相当复杂的，他结合了数据仓库的前端技术和很强的业务要求。在这儿只是以一个简单的实例来说明他大致的构建流程。 

2．构建数据仓库模型，他包括两部分，一是要考虑原来的数据源能够提供哪些有用的数据，也就是经过数据的筛选之后能够为数据仓库所用。二是要看公司业务层需要什么样的分析结果。这要和公司的高级决策层紧密配合，完全了解他的业务需求，因为数据仓库的使用者主要是公司的高级决策者。 

在这一阶段要做好很多前期的工作，因为你的原始数据库中的数据也许和你的正要建立的数据仓库的需求也许有很大的出入，结构完全是两马事。你如何才能将你的原始数据提取出来，作为数据仓库的有用数据呢，你的原始数据库中存储的是零碎的事务数据，而你的数据仓库中要的是经过转化和提炼过的统计数据，比如说，你的原始数据库中存储这每天的所有存款和取款记录，而你的数据仓库并不关心你的每条记录的数据，而是希望在最短的时间内，以最快的速度统计出这个月的所有存款和取款的总数量，如果这种查询放在原来的数据库上来做的话，也就失去了数据仓库的意义，超大规模的数据使你无法查询下去，这时候你就要将对这个查询有意义的数据转化到数据仓库，这就是数据清洗，即ETL。实现数据清洗有很多的方法，也有很多的细节问题，比如，数据类型的匹配，数据格式的转换，异地数据表数据集中到一起时有主键重复，以及你如何定期，按时的将数据加工到数据仓库中来等等。在我的示例中没有严格的经过着一步，因为我没有规范的原始数据库，也没有规范的业务需求。我只是运用星型模型和雪花模型做了几个典型的数据仓库表。其表关系如下： 

窗口中FACT为事实表，TIME，ADDRESS，DETAIL分别为时间维，地址维，详细地址维，DETAIL又是ADDRESS的子维。他们又构成雪花模型。其中都有部分数据。 

现在，数据仓库已经建立成功，下一步就是在OLAP服务器上建立元数据数据库。这个数据库和我们以前所说的数据库不同，他是存放元数据的数据库，比如我们下一步要创建的多维数据集、角色、数据源、共享维度和挖掘模型等。然后需要和早期在 ODBC 数据源管理器中建立的数据源连接，使其与数据仓库连接上。这些工作做好了之后，就可以用数据仓库中的维表来建立共享维度，现在以时间维和地址维为例。其创建过程一样。依此点下一步即可创建时间维（TIME），下面用ADDRESS和DETAIL建立雪花模型共享维度,点下一步即可创建DETAIL维。创建完成之后都要进行处理才能生效。维度创建好了之后就该创建多维数据集了。多维数据集是一种基于维表和事实表的数据集，以他来对数据仓库进行快速的访问。我们的多维数据集结构如下： 






　　
　　DETAIL（SREET）
　　
　　DETAIL（MARK）
　　
　　ADDRESS（PROVINCE，CITY）
　　
　　TIME（YEAR，DAY）

到现在一个简单的数据仓库架构已经建立成功，我们利用前端分析工具来对建立的数据仓库做查询，看能否实现我们的简单的业务要求，先以EXCEL作为查询工具。我们除了用EXCEL，ENGLISH QUERY 等现成工具做查询外，还可以用MDX函数直接对OLAP做查询 

到现在为止，一个简单的数据仓库已经创建成功，可以实现一些简单的业务查询。这个实例主要是分析数据仓库的创建过程以及进一步加深对数据仓库的认识和了解，进一步理解其中的基本概念。
]]></description>
		</item>
		<item>
			<title>SQL在存储过程编写经验和优化措施</title>
			<link>http://www.kingmx.com/article.php?id=14689</link>
			<pubDate>2006-12-12</pubDate>
			<description><![CDATA[

【导读】在数据库的开发过程中，经常会遇到复杂的业务逻辑和对数据库的操作，这个时候就会用SP来封装数据库操作。本文介绍SQL在存储过程编写经验和优化措施


一、适合读者对象

数据库开发程序员，数据库的数据量很多，涉及到对SP(存储过程)的优化的项目开发人员，对数据库有浓厚兴趣的人。

二、介绍

在数据库的开发过程中，经常会遇到复杂的业务逻辑和对数据库的操作，这个时候就会用SP来封装数据库操作。如果项目的SP较多，书写又没有一定的规范，将会影响以后的系统维护困难和大SP逻辑的难以理解，另外如果数据库的数据量大或者项目对SP的性能要求很，就会遇到优化的问题，否则速度有可能很慢，经过亲身经验，一个经过优化过的SP要比一个性能差的SP的效率甚至高几百倍。

三、内容

1、开发人员如果用到其他库的Table或View，务必在当前库中建立View来实现跨库操作，最好不要直接使用“databse.dbo.table_name”，因为sp_depends不能显示出该SP所使用的跨库table或view，不方便校验。

2、开发人员在提交SP前，必须已经使用set showplan on分析过查询计划，做过自身的查询优化检查。

3、高程序运行效率，优化应用程序，在SP编写过程中应该注意以下几点：

a)SQL的使用规范：

i.　尽量避免大事务操作，慎用holdlock子句，提高系统并发能力。

ii.　尽量避免反复访问同一张或几张表，尤其是数据量较大的表，可以考虑先根据条件提取数据到临时表中，然后再做连接。

iii.　尽量避免使用游标，因为游标的效率较差，如果游标操作的数据超过1万行，那么就应该改写;如果使用了游标，就要尽量避免在游标循环中再进行表连接的操作。

iv.　注意where字句写法，必须考虑语句顺序，应该根据索引顺序、范围大小来确定条件子句的前后顺序，尽可能的让字段顺序与索引顺序相一致，范围从大到小。

v.　不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算，否则系统将可能无法正确使用索引。

vi.　尽量使用exists代替select count(1)来判断是否存在记录，count函数只有在统计表中所有行数时使用，而且count(1)比count(*)更有效率。

vii.　尽量使用“&gt;=”，不要使用“&gt;”。

viii.　注意一些or子句和union子句之间的替换

ix.　注意表之间连接的数据类型，避免不同类型数据之间的连接。

x.　注意存储过程中参数和数据类型的关系。

xi.　注意insert、update操作的数据量，防止与其他应用冲突。如果数据量超过200个数据页面(400k)，那么系统将会进行锁升级，页级锁会升级成表级锁。

b)索引的使用规范：

i.　索引的创建要与应用结合考虑，建议大的OLTP表不要超过6个索引。

ii.　尽可能的使用索引字段作为查询条件，尤其是聚簇索引，必要时可以通过index index_name来强制指定索引

iii.　避免对大表查询时进行table scan，必要时考虑新建索引。

iv.　在使用索引字段作为条件时，如果该索引是联合索引，那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引，否则该索引将不会被使用。

v.　要注意索引的维护，周期性重建索引，重新编译存储过程。

c)tempdb的使用规范：

i.　尽量避免使用distinct、order by、group by、having、join、cumpute，因为这些语句会加重tempdb的负担。

ii.　避免频繁创建和删除临时表，减少系统表资源的消耗。

iii.　在新建临时表时，如果一次性插入数据量很大，那么可以使用select into代替create table，避免log，提高速度;如果数据量不大，为了缓和系统表的资源，建议先create table，然后insert。

iv.　如果临时表的数据量较大，需要建立索引，那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中，这样才能保证系统能够很好的使用到该临时表的索引。

v.　如果使用到了临时表，在存储过程的最后务必将所有的临时表显式删除，先truncate table，然后drop table，这样可以避免系统表的较长时间锁定。

vi.　慎用大的临时表与其他大表的连接查询和修改，减低系统表负担，因为这种操作会在一条语句中多次使用tempdb的系统表。

d)合理的算法使用：

根据上面已提到的SQL优化技术和ASE Tuning手册中的SQL优化内容,结合实际应用,采用多种算法进行比较,以获得消耗资源最少、效率最高的方法。具体可用ASE调优命令：set statistics io on, set statistics time on , set showplan on 等。

]]></description>
		</item>
		<item>
			<title>浅析SQL Server与Oracle、DB2的比较</title>
			<link>http://www.kingmx.com/article.php?id=14688</link>
			<pubDate>2006-12-12</pubDate>
			<description><![CDATA[

【导读】本文浅要分析了三种数据库SQL Server与Oracle、DB2在使用和性能等方面的差异,供参考。


开放性

SQL Server
只能在Windows 上运行，没有丝毫的开放性，操作系统的系统的稳定对数据库是十分重要的。Windows9X系列产品是偏重于桌面应用，NT server只适合中小型企业。而且Windows平台的可靠性，安全性和伸缩性是非常有限的。它不象Unix那样久经考验，尤其是在处理大数据量的关键业务时。

Oracle
能在所有主流平台上运行（包括 Windows）。完全支持所有的工业标准。采用完全开放策略。可以使客户选择最适合的解决方案。对开发商全力支持。

DB2
能在所有主流平台上运行（包括Windows）。最适于海量数据。DB2在企业级的应用最为广泛,在全球的500家最大的企业中,几乎85%以上用DB2数据库服务器,而国内到97年约占5%。 

可伸缩性,并行性

SQL Server
并行实施和共存模型并不成熟。很难处理日益增多的用户数和数据卷。伸缩性有限。

Oracle
平行服务器通过使一组结点共享同一簇中的工作来扩展Window NT的能力,提供高可用性和高伸缩性的簇的解决方案。如果WindowsNT不能满足需要, 用户可以把数据库移到UNIX中。

DB2 
DB2具有很好的并行性。DB2把数据库管理扩充到了并行的、多节点的环境。数据库分区是数据库的一部分，包含自己的数据、索引、配置文件、和事务日志。数据库分区有时被称为节点或数据库节点。 

安全性

SQL server&nbsp;&nbsp; 没有获得任何安全证书。 
Oracle&nbsp; &nbsp;获得最高认证级别的ISO标准认证。
DB2&nbsp; 获得最高认证级别的ISO标准认证。 

性能

SQL Server&nbsp;&nbsp; 多用户时性能不佳 
Oracle&nbsp;&nbsp; 性能最高， 保持WindowsNT下的TPC-D和TPC-C的世界记录。
DB2&nbsp;&nbsp; 适用于数据仓库和在线事物处理，性能较高。 

客户端支持及应用模式

SQL Server 
C/S结构，只支持Windows客户，可以用ADO,DAO,OLEDB,ODBC连接。

Oracle
多层次网络计算，支持多种工业标准，可以用ODBC,JDBC,OCI等网络客户连接。

DB2
跨平台，多层结构，支持ODBC,JDBC等客户。

操作简便 

SQL Server 
操作简单,但只有图形界面。

Oracle
较复杂, 同时提供GUI和命令行，在Windows NT和Unix下操作相同。

DB2
操作简单,同时提供GUI和命令行，在Windows NT和Unix下操作相同。 

使用风险 

SQL Server 
完全重写的代码，经历了长期的测试，不断延迟，许多功能需要时间来证明。并不十分兼容早期产品。使用需要冒一定风险。

Oracle
长时间的开发经验，完全向下兼容。得到广泛的应用。完全没有风险。

DB2
在巨型企业得到广泛的应用，向下兼容性好。风险小。 

]]></description>
		</item>
		<item>
			<title>教你使用数组一样使用数据表变量</title>
			<link>http://www.kingmx.com/article.php?id=14686</link>
			<pubDate>2006-12-12</pubDate>
			<description><![CDATA[

虽然你可以使用数组一样使用一个数据表变量，对于它能够使用的数据类型是有限制的。例如，你不能在一个数据表变量中包含另一个数据表变量。 

你可以象申明一个用户定义的数据表一样申明一个数据表变量；但是，在你申明了它以后，你就不能再改变数据表的定义了。另外，你必须在申明的时候定义数据表变量的所有属性。 

并不是所有的INSERT命令都能够在数据表变量上操作。例如，你不能在向数据表变量插入值的时候使用EXEC命令。执行一个存储过程或者插入值到数据表变量的字符串命令会返回一个错误。同样，不是所有的SELECT 命令都能够在数据表变量上操作而且你不能使用SELECT INTO 命令来插入数据到一个数据表变量中去。 

你不能在数据表变量上使用一些系统过程，比方sp_depends。数据表变量的对象名在运行时生成，并且是一个随机的名字，它被保存在tempdb数据库里。因为大多数的系统功能和系统过程需要对象名或者标识数值，所以要在一个数据表变量上执行系统功能或者过程是困难的。需要复杂的逻辑来获得对象的名字以及/或者标识数值来运行系统功能和过程。 

一个数据表变量的作用域是批处理过程，存储过程或者函数执行的过程。当批处理过程中GO命令被触发了，数据表变量也就出离了它的作用域。 

下面是在一个存储过程中使用一个数据表变量的简单脚本。 






　　
　　CREATE PROCEDURE TestName
　　
　　AS
　　
　　DECLARE @TableId TABLE
　　
　　(table_id INT IDENTITY NOT NULL
　　
　　primary key nonclustered,
　　
　　id INT NOT NULL,
　　
　　name sysname NOT NULL
　　
　　DEFAULT 'UNKNOWN',
　　
　　type char(2) NOT NULL
　　
　　DEFAULT '9',
　　
　　crdate datetime NOT NULL
　　
　　DEFAULT current_timestamp)
　　
　　INSERT @TableId (id, name, type, crdate)
　　
　　SELECT id, 'test_' + name, type, crdate FROM tempdb..sysobjects
　　
　　SELECT * FROM @TableID
　　
　　GO
　　
　　exec TestName
　　
　　GO

]]></description>
		</item>
		<item>
			<title>如何正确的在对IN操作使用变量绑定</title>
			<link>http://www.kingmx.com/article.php?id=14685</link>
			<pubDate>2006-12-12</pubDate>
			<description><![CDATA[

大家都知道在sql语句中变量绑定的重大意义，甚至有高人指出：一个应用想要它变的很糟糙的话，只要不使用变量绑定就可以了。这话的确不假。这时可能有人就会问：我该绑定的都绑定了，可是我实在无法想到好的方法在in操作符中使用变量绑定。下面的方法可以解决这个疑问。 

我们知道in操作符接受两种list, 一个是由一个个item组成的list,　另一个是由另一个表中选出的list。第一种方式由于值个数不一定，变量绑定具有一定的困难。于是我们思路就集中到准备将一个字符串传入到sql语句中，然后使用一个方法将字符串parse成一个table, 再传回in operator: 

首先我们来创建方法，及由此方法返回的table类型： 






　　rudolf@test9i&gt; create or replace type numTableType as table
　　2　　　 of number
　　3　/
　　
　　Type created.
　　
　　rudolf@test9i&gt; create or replace function str2numList( p_string in varchar2 ) return
　　2　numTableType
　　3　as
　　4　　　v_str　 long default p_string || ',';
　　5　　　v_n　　　　number;
　　6　　　v_data　　numTableType := numTableType();
　　7　begin
　　8　　　loop
　　9　　　　　v_n := to_number(instr( v_str, ',' ));
　　10　　　　　exit when (nvl(v_n,0) = 0);
　　11　　　　　v_data.extend;
　　12　　　　　v_data( v_data.count ) := ltrim(rtrim(substr(v_str,1,v_n-1)));
　　13　　　　　v_str := substr( v_str, v_n+1 );
　　14　　　end loop;
　　15　　　return v_data;
　　16　end;
　　17　/
　　
　　Function created.
　　 
我们把下列语句： 






　　select object_name from t where object_id in ( xx,xxx,xxx,...);

改为： 






　　select object_name from t
　　where object_id in
　　( select * from　THE ( select cast( str2numList(:variable ) as numtableType ) from　dual )
　　);
　　 
现在我们来看看是否达到了我们的目的： 






　　rudolf@test9i&gt; var STR varchar2(3000)
　　
　　rudolf@test9i&gt;　exec :STR := '5770,1810,4481'
　　
　　PL/SQL procedure successfully completed.
　　
　　rudolf@test9i&gt; alter session set events= '10046 trace name context forever, level 4'
　　2　/
　　
　　Session altered.
　　
　　rudolf@test9i&gt; select object_id,object_name from t where object_id in (
　　2　　 select * from　THE ( select cast( str2numList(:STR ) as numtableType ) from
　　3　　dual ) )
　　4
　　rudolf@test9i&gt; /
　　
　　OBJECT_ID OBJECT_NAME
　　---------- ------------------------------
　　1810 ALL_ALL_TABLES
　　4481 AGGXMLINPUTTYPE
　　5770 ALL_APPLY
　　 
检查dump文件，我们看到(注意星号的行)： 






　　
　　PARSING IN CURSOR #1 len=146 dep=0 uid=81 oct=3 
lid=81 tim=1036636837633718 hv=2833917919 ad='529b9f48'
　　select object_id,object_name from t where object_id in (
　　select * from　THE ( select cast( str2numList(:STR ) as numtableType ) from
　　dual ) )
　　END OF STMT
　　PARSE #1:c=0,e=655,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=0,tim=1036636837633701
　　BINDS #1:　　　　　　　　　*****
　　bind 0: dty=1 mxl=2000(200) mal=00 scl=00 pre=00 oacflg=03 oacfl2=10 size=2000 offset=0
　　bfp=406402fc bln=2000 avl=14 flg=05
　　value="5770,1810,4481"
　　EXEC #1:c=0,e=245,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=1036636837645450
　　FETCH #1:c=20000,e=16739,p=0,cr=52,cu=0,mis=0,r=1,dep=0,og=4,tim=1036636837662283
　　FETCH #1:c=0,e=4644,p=0,cr=0,cu=0,mis=0,r=2,dep=0,og=4,tim=1036636837667979

这样我们就完成了。
]]></description>
		</item>
		<item>
			<title>探讨SQL Server中Case 的不同用法</title>
			<link>http://www.kingmx.com/article.php?id=14683</link>
			<pubDate>2006-12-12</pubDate>
			<description><![CDATA[

CASE 可能是 SQL 中被误用最多的关键字之一。虽然你可能以前用过这个关键字来创建字段，但是它还具有更多用法。例如，你可以在 WHERE 子句中使用 CASE。 

首先让我们看一下 CASE 的语法。在一般的 SELECT 中，其语法如下： 






SELECT &lt;myColumnSpec&gt; = 
CASE 
WHEN &lt;A&gt; THEN &lt;somethingA&gt; 
WHEN &lt;B&gt; THEN &lt;somethingB&gt; 
ELSE &lt;somethingE&gt; 
END

在上面的代码中需要用具体的参数代替尖括号中的内容。下面是一个简单的例子： 






USE pubs 
GO 
SELECT 
    Title, 
    'Price Range' = 
    CASE 
        WHEN price IS NULL THEN 'Unpriced' 
        WHEN price &lt; 10 THEN 'Bargain' 
        WHEN price BETWEEN 10 and 20 THEN 'Average' 
        ELSE 'Gift to impress relatives' 
    END 
FROM titles 
ORDER BY price 
GO

这是 CASE 的典型用法，但是使用 CASE 其实可以做更多的事情。比方说下面的 GROUP BY 子句中的 CASE： 






SELECT 'Number of Titles', Count(*) 
FROM titles 
GROUP BY 
    CASE 
        WHEN price IS NULL THEN 'Unpriced' 
        WHEN price &lt; 10 THEN 'Bargain' 
        WHEN price BETWEEN 10 and 20 THEN 'Average' 
        ELSE 'Gift to impress relatives' 
    END 
GO

你甚至还可以组合这些选项，添加一个 ORDER BY 子句，如下所示： 






USE pubs 
GO 
SELECT 
    CASE 
        WHEN price IS NULL THEN 'Unpriced' 
        WHEN price &lt; 10 THEN 'Bargain' 
        WHEN price BETWEEN 10 and 20 THEN 'Average' 
        ELSE 'Gift to impress relatives' 
    END AS Range, 
    Title 
FROM titles 
GROUP BY 
    CASE 
        WHEN price IS NULL THEN 'Unpriced' 
        WHEN price &lt; 10 THEN 'Bargain' 
        WHEN price BETWEEN 10 and 20 THEN 'Average' 
        ELSE 'Gift to impress relatives' 
    END, 
    Title 
ORDER BY 
    CASE 
        WHEN price IS NULL THEN 'Unpriced' 
        WHEN price &lt; 10 THEN 'Bargain' 
        WHEN price BETWEEN 10 and 20 THEN 'Average' 
        ELSE 'Gift to impress relatives' 
    END, 
    Title 
GO

注意，为了在 GROUP BY 块中使用 CASE，查询语句需要在 GROUP BY 块中重复 SELECT 块中的 CASE 块。 

除了选择自定义字段之外，在很多情况下 CASE 都非常有用。再深入一步，你还可以得到你以前认为不可能得到的分组排序结果集。 
]]></description>
		</item>
		<item>
			<title>启动SQL Server时自动执行存储过程</title>
			<link>http://www.kingmx.com/article.php?id=14682</link>
			<pubDate>2006-12-12</pubDate>
			<description><![CDATA[

如何在启动SQL SERVER的时候，执行一个存储过程？ 

将存储过程创建在master数据库中，然后企业管理器中找到这个存储过程--右键--属性--勾选"每当sql server启动时执行"。 

或者在master中创建存储过程后,执行语句设置为自动启动 






　　use master 

　　exec sp_procoption '存储过程名','startup','on'

自动执行存储过程 

SQL Server 启动时可以自动执行一个或多个存储过程。这些存储过程必须由系统管理员创建，并在 sysadmin 固定服务器角色下作为后台过程执行。这些过程不能有任何输入参数。 

对启动过程的数目没有限制，但是要注意，每个启动过程在执行时都会占用一个连接。如果必须在启动时执行多个过程，但不需要并行执行，则可以指定一个过程作为启动过程，让该过程调用其它过程。这样就只占用一个连接。 

在启动时恢复了最后一个数据库后，即开始执行存储过程。若要跳过这些存储过程的执行，请将启动参数指定为跟踪标记 4022。如果以最低配置启动 SQL Server（使用 -f 标记），则启动存储过程也不会执行。有关更多信息，请参见跟踪标记。 

若要创建启动存储过程，必须作为 sysadmin 固定服务器角色的成员登录，并在 master 数据库中创建存储过程。使用 sp_procoption 可以：将现有存储过程指定为启动过程。 阻止过程在 SQL Server 启动时执行。 
]]></description>
		</item>
		<item>
			<title>SQL概述及在网络安全中的应用（下）</title>
			<link>http://www.kingmx.com/article.php?id=14593</link>
			<pubDate>2006-11-30</pubDate>
			<description><![CDATA[

3.2.3 利用结构错误查询表单 

一些数据库服务器返回的错误信息中包含了一部分格式错误消息,你可以通过分析这些片断来构造你提交的INJECTION语句,有些你提交的字符串会返回有用的信息,有的却不会,这主要是以来于web应用程序中SQL查询语句是如何设计的.下面这些是我推荐你尝试的字符串: 






　　' 
　　BadValue' 
　　'BadValue 
　　' OR ' 
　　' OR 
　　; 
　　9,9,9

通常这些字符串中的一些会返回相同的信息,或者根本不返回信息.但是有例子告诉我们,可能有的信息只有用他们中的一个才能得到,所以你最好提交字符串的时候,把他们都试一遍. 

3.2.4 圆扩弧 

如果有缺陷的查询语句中包含圆扩弧'(' (就像下面将会举的例子那样),或者返回的错误信息里显式地提醒你缺了'('号(Oracle这么做),那么你应该在你提交的SQL注射字符串中加入'('号.通常在WHERE子句后面加一个括号,但是在一些情况下,你需要加2个或者更多的括号. 

下面是parenthesis.asp的源码: 






　　mySQL="SELECT LastName, FirstName, 
   Title, Notes, Extension FROM Employees WHERE (City = '" &amp; strCity &amp; "')"

我们插入如下的值: 






　　"') UNION SELECT OtherField FROM OtherTable WHERE (''='"

那么传送给SQL SERVER的语句就变成了这样: 






SELECT LastName, FirstName, Title, Notes, 
Extension FROM Employees WHERE (City = '') 
UNION SELECT OtherField From OtherTable WHERE (''='')

3.2.5 LIKE语句查询 

另一个大的灾难是陷入一个LIKE子句的陷阱.(Seeing the LIKE keyword or percent signs cited in an error message are indications of this situation.)大多数的web搜索程序使用LIKE子句来查询数据库,比如下面这个: 






SQLString = "SELECT FirstName, 
LastName, Title FROM Employees 
WHERE LastName LIKE '%" &amp; strLastNameSearch &amp; "%'"

这里面的%是通配符,在这个例子里,WHERE子句会返回TRUE,只要LASTNAME里有字符串含有strLastNameSearch.为了阻止SQL SERVER返回预计中的记录,你构造的SQL语句里必须含有LASTNAME里没有的字符串.web搜索程序搜索的字符串来自于用户的输入.通常有一个'和一个%在输入的字符串之前,因此我们构造字符串时,需要在WHERE子句中匹配它们.如果你提交了NULL作为搜索字符串,那么LIKE的参数会变成"%%",这是一个全匹配,会返回所有的记录。 




3.2.6 “死胡同” 

大部分的时候sql injection都要伴随着大量失败的实践，如果你发现你无论如何都不能插入相关的语句，并且无论你怎么做都不对，这个时候你就要判断自己是否掉进了一个死胡同，很多时候遇到这种情况你很可能是在一个多重嵌套的WHERE和SELECT子句的语句中，或者一些更加复杂的多重嵌套，连使用“;--”都没有用，所以自己要小心和避免在这种地方停留。 

3.2.7 列的数目不匹配问题 

如图所示，我们可以从几次错误中得到很多有用的信息，并且加以调整自己的请求语句，这种信息多了，那就意味着我们离成功不远了。在猜列名时，如图所示，我们提交语句后会碰到以下错误“在UNION语句中的所有查询都必须在目标列表中具有相同数目的表达式”，这就是说你需要找出或者说是探测出在合法的请求中有多少个列。 

这里我解释一下，UNION 语句是用来将两个不同的查询结果集相加得到一个结果集，UNION使用的唯一要求是两个查询的信息（你的查询语句）必须有相同的列数和相同的数据类型 

我举个例子，web程序中有如下语句： 






SQLstring= "SELECT FirstName,LastName,
EmployeeID FROM Employees WHERE City ='"&amp;strCity"'"

合法的SELECT语句和我们注入的UNION SELECT语句在WHERE子句中都要有相同的列。就上面的语句来说，如果我要加入UNION 语句的话，前后两者都要有3个列。并且他们列的数据类型也要相互匹配才可以。如果FirstName这个值是字符串类型的，那么在你注入的语句中所对应的值也应该是字符串类型的。一些数据库，如ORACLE，是对类型检查非常严格的。其他的数据库相对要好一些，允许你输入任何数据类型并且它会自动的把你输入错误的数据类型转换成正确的。比如SQL数据库中，你在varchar类型的地方输入数值类型的数据(如int)是不会报错的，因为在这里数值类型会被自动转为字符串类型。但是如果在smallint列处输入text类型则被认为是非法的,因为text类型不能被转换成int类型。把数值类型的数据转换成字符串型是被允许的，而反之则不行，所以默认都是使用数值类型的数据。 

要想知道我们要注入的目标语句中有多少个列，你就要试探性的往UNION SELECT子句中添加相应的值，直到它不报“在UNION语句中的所有查询都必须在目标列表中具有相同数目的表达式”这样的错为止。如图所示，如果你遇到的是数据类型不匹配的错误，那么你要去改变列的数据类型。如果返回消息只是一个转换数据类型失败的错误，那就说明你已经猜对了列的数目，只是其中有个别的列的数据类型不对。那么接下来要做的就是判断是哪个列的数据类型的不正确导致的错误。然后将他改过来就可以了。 

如果一切顺利，那么祝贺你，你会得到一个和上面格式类似的而且是合法的页面；）无论动态页面在哪里出现，你都可以构造自己的语句应对自如。 

3.2.8.WHERE关键字 

报错为“无效的列名'EmployeeID'”,这个问题可能是由我们注入的语句结尾的WHERE关键字引起的，举例说明： 






SQLString="SELECT FirstName,LastName,
Title FROM Employees WHERE City='"&amp;strcity&amp;"'AND Country ='USA'"

如果我们注入的语句是UNION ALL SELECT OtherField FROM OtherTable WHERE 1=1 那么会得到如下的提交语句： 






SELECT FirstName, LastName,
Title FROM Employees WHERE City = 'NoSuchCity' 
UNION ALL SELECT OtherField FROM OtherTable WHERE 1=1 AND Country = 'USA'

这样就会报错：[Microsoft][ODBC SQL Server Driver][SQL Server]无效的列名 'Country'。 

其实问题就是因为你注入的语句后，系统没有在从数据库的表中找到一个叫'Country'的列名。我们这里可以简单的用“;--”注释符号将其注释掉（如果我们是SQL Server）。或者干脆继续猜其他的列名，然后构造合法请求就如我们上一节讲到的一样。 



表名的枚举 

我们已经开始掌握如何来使用注入进行攻击，但是我们还要确定要从哪个表得到信息，换句话说就是我们要的到关键的表名才能获得我们想要的有用信息。如何获得表名呢？在SQL Server中,你可以很容易得从数据库中得到全部的表名和列名。但是在Oracle和Access中，你就不一定能如此轻易的得到了，这要看WEB程序对数据库的访问权限了。关键在于是否能得到系统建立时自动生成的表中包含的表名和列名。如在SQL Server中,它们分别为'sysobjects'和'syscolumns',（在本文最后我们将给出其他数据库系统自建表和相应的列名）我们用以下的句子可以在这些表中列出数据库的所有列名和表名，（根据情况自行修改）： 

SELECT name FROM sysobjects WHERE xtype = 'U' 

这句话会返回数据库中用户定义的所有表,如果我们看到我们感兴趣的或者是想要看的表，那么我们就把他打开，这里以Orders为例构造语句：SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = 'Orders')得到结果如图。 

3.2.10.单一纪录 

上面我们构造的语句返回了大量的信息，如果你只想显示一条数据纪录也是可以的。你完全可以构造你的注入语句来得到你想要的唯一的信息。我们只要在WHERE子句中添加关键字来避免某些行的关键字被选中就可以了。我来举个列子：' UNION ALL SELECT name, FieldTwo, FieldThree FROM TableOne WHERE ''=' 

我们这样就可以得到FieldOne,FieldTwo和FieldThree的第一个值，假设我们的到的分别是"Alpha", "Beta"和"Delta"。注意，更有意思的来了，我们要得到第2行的值，怎么构造下面的语句呢？这样来：' UNION ALL SELECT FieldOne, FieldTwo, FieldThree FROM TableOne WHERE FieldOne NOT IN ('Alpha') AND FieldTwo NOT IN ('Beta') AND FieldThree NOT IN ('Delta') AND ''=' 

这里有一个子句“NOT IN VALUES”，它的作用是不再返回我们已经得到的信息，即不是alpha,不是beta,不是delta.既然都不是，数据库就会傻乎乎的告诉我们第二行的值。我们再假设我们得到第二行的值为"AlphaAlpha", "BetaBeta"和"DeltaDelta"。 

我们来获得第三行的值，构造语句如下：' UNION ALL SELECT FieldOne, FieldTwo, FieldThree FROM TableOne WHERE FieldOne NOT IN ('Alpha', 'AlphaAlpha') AND FieldTwo NOT IN ('Beta', 'BetaBeta') AND FieldThree NOT IN ('Delta', 'DeltaDelta') AND ''=' 

这样就避免了得到第一次和第二次我们已经得到的值，我们就这样试下去会得到数据库中所有的值。这看起来好像确实比较麻烦，但在这里却是最有效的，不是么？ 

3.3 插入 

3.3.1 插入基础 

关键字INSERT 被用于向数据库添加信息，通常使用INSERT主要在包括用户注册，论坛，添加商品到购物车，等等。检查INSERT使用的弱点和检查WHERE一样。你可能不想使用INSERT,如何避免被利用弱点是一个重要的考虑问题。INSERT注入尝试常常会让数据库以行形式返回结果导致泛滥的单独的引用和SQL关健字的意义可能改变.取决于管理员的注意和信息对数据库的操作，这个是要引起注意的，刚刚说过的那些，INSERT注入和SELECT注入的不同。我们在一个允许用户进行各种注册，这就提供了一个你输入你的名字，地址，电话等等的表单。在你提交了这个表单之后，为了得到进一步的INSERT的弱点，你必须能够看到你提交的信息。它在那里不要紧。可能当你登陆根据在数据库里存储的名字的给予你权利的时候，可能在发送你的spam邮件的。。，谁知道，寻找一个途径至少可以看到你输入的信息。 

一个插入的请求看起来象这样：INSERT INTO TableName VALUES ('Vaule One','Value Two','Value Three') 你想可能利用一个在参数VALUES中的子句来看到其他的数据。我们可以使用这种办法，sql的代码象这样：SQLString ="INSERT INTO TableName VALUES ('" &amp; strValueOne &amp; "', '" &amp; strValueTwo &amp; "', '" &amp; strValueThree &amp; "')"我们象这样填写表单：Name: ' + (SELECT TOP 1 FieldName FROM TableName) + ' Email: blah@blah.com Phone: 333-333-3333 使SQL的声明象这样 : INSERT INTO TableName VALUES ('' + (SELECT TOP 1 FieldName FROM TableName) + '', 'blah@blah.com', '333-333-3333')当你到了个人设置页面查看你的使用信息，你将看到的第一个字段这个通常是用户名r如果你使不在你的subselect中使用TOP 1，你将得到一个错误信息说你的subselect返回了太多记录，你能查看表中所有的行，使用NOT IN()同样的方法你可以得到单独的记录。 






3.4. SQL服务器存储过程利用 

3.4.1 存储过程基础 

4. 一个完整安装的MSSQL服务器有上千的存储过程。如果你能在一个后台使用mssql的网页应用程序得到SQL注入，你能使用这些存储过程完成一些非凡的成果。我将讨论很少的特殊的过程。取决于网页程序使用数据库的用户，只有一些可以工作，并不是所有的用户都可以利用。第一件事你应该知道存储过程注入不能通过存储过程的返回值来确定你的注入是否成功.取决于你想完成什么，你可能不需要得到数据。你可以找到返回给你的数据的其他意义。存储过程注入比一般的查询注入要容易些，存储过程的注入的弱点利用看起来象这样。 

simplequoted.asp?city=seattle';EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:' 

注意, 

Notice how a valid argument is supplied at the beginning and followed by a quote and the final argument to the stored procedure has no closing quote. This will satisfy the syntax requirements inherent in most quoted vulnerabilities. You may also have to deal with parentheses, additional WHERE statements, etc.但是在这以后将不需要担心列和数据的类型的匹配。这个可能弱点的输出象程序无法返回错误信息一样。我最喜欢存储过程。 

5. 3.4.2. xp_cmdshell 

xp_cmdshell {'command_string'} [, no_output] 

master.dbo.xp_cmdshell是存储过程的圣杯，它带来了一个问题，能够调用命令行的数据库用户的和他的运行权限，这个并不可用除非这个网页程序使用的数据库用户是SA. 运行级别为6 

sp_makewebtask [@outputfile =] 'outputfile', [@query =] 'query' 

6. 另外一个好的调用对象是master.dbo.sp_makewebtask，象你所看的，它是一个本地的输出文件和一个SQL statement。sp_makewebtask可以查询并建立一个包含输出的网页。注意你可以象使用一个UNC路径名一样使用一个本地输出。这个意思就是这个输出文件可以放有在任何一台连在Internet并且有个可写的SMB共享(SMB请求不需要任何的身份验证)。如果有一个防火墙限制了服务器对Internet，试着把输出文件放在网页目录下(你要知道或者猜测网页的目录)。同样值得注意的是引用查询可能是 包括执行其他的存储过程。Making "EXEC xp_cmdshell 'dir c:'" 这个查询将在网页中给出"dir c:"的输出。当你进行嵌套引用的时候，记得单独的引用和双引号. 

4.1数据处理 

所有的客户端数据可以被恶意的提交的字符或字符串清除。这些可能在所有的应用程序做到，不仅仅是使用SQL查询的。Stripping quotes or putting backslashes in front of them is nowhere near enough.最好的过滤数据的方式是不用规则的表达方式，使它只包括你所想要的字符类型。举个例子，下边的regxp将只能返回字母和数字，尽可能的过滤象s/[^0-9a-zA-Z]//g 这样的特殊字符。可能的时候尽量使用数字，在这以后只使用数字和字母。如果你需要包括各种各样的标志或标点。确信完全的把它们转换成html标记，像“"e;" or "&gt;”。例如，一个用户提交了一个email地址只允许使用数字和字母还有"@", "_", "." 和"-"。仅仅只有这些字符可以转换成html标记。 

4.2. 编写安全的web程序 

这里同样有很少的特殊的sql注入规则。First, prepend and append a quote to all user input。 

尽管数据使数字。其次，限制网页应用程序的数据库用户在数据库里的权限。不要给这个用户访问所有的存储过程的权利如果这个用户只需要访问一些预定义的。 这部分包括了所有在sql注入中有用的系统表，你可以在google上搜索到每一个的表的列的定义 

5.1. MS SQL Server 






　　Sysobjects 
    syscolumns

5.2. MS Access Server 






　　MSysACEs 

　　MSysObjects 

　　MSysQueries 

　　MSysRelationships 

　　5.3. Oracle 

　　SYS.USER_OBJECTS 

　　SYS.TAB SYS.USER_TABLES 

　　SYS.USER_VIEWS SYS.ALL_TABLE 

　　S SYS.USER_TAB_COLUMNS 

　　SYS.USER_CONSTRAINTS SYS.USER_TRIGGERS 

　　SYS.USER_CATALOG


]]></description>
		</item>
		<item>
			<title>SQL Server 2000启动1069错误解决方法</title>
			<link>http://www.kingmx.com/article.php?id=14592</link>
			<pubDate>2006-11-30</pubDate>
			<description><![CDATA[

首先介绍网络上常用的两种解决方法： 

1.我的电脑--控制面板--管理工具--服务--右键 MSSQLSERVER--属性--登陆--登陆身份--选择"本地系统帐户" 

或: 

2.我的电脑--控制面板--管理工具--服务--右键 MSSQLSERVER--属性--登陆--登陆身份--选择"此帐户"--密码和确认密码中输入你修改后的administrator密码. 

两者的区别: 

选择第一种方式,以后修改了administrator密码,不用再调整(但要求登陆操作系统的是系统管理员) 

选择第二种方式,以后修改了administrator密码,还要再重复做上面的操作. 

下面是我遇到的一种情况： 

今天上午同事又告诉我他的SQL不能登陆自己的“企业管理器”了，报出的错误就是“1069 错误，由于登录失败而无法启动服务”，上网查到了以上两种方案，但是当我看到了服务的窗口又发现了一个可能引起此问题的地方，我们先找到MSSQLSERVER服务，然后查看它的属性,发现是使用域帐户在启动服务时进行验证，于是便询问是否修改过登陆域的密码，得到答案是修改过，因为域中作了设置，一定时期后要求用户修改密码，而且不能与以前密码相同（空密码除外，这个我做过实验^_^）。于是将这里的密码重新进行设置，再重新启动服务成功，SQL也可登陆成功。 

通过这个问题发现，当域的密码被修改过后，相应服务使用的登陆验证信息不会自动更新需要手动来更新，才能解决此问题。如果大家嫌比较麻烦，还是像上面的解决方案那样直接将登陆身份修改为“本地系统帐户”比较简单。 
]]></description>
		</item>
		<item>
			<title>深入浅出SQL教程之SELECT语句的自连接</title>
			<link>http://www.kingmx.com/article.php?id=14591</link>
			<pubDate>2006-11-30</pubDate>
			<description><![CDATA[
到目前为止，我们连接的都是两张不同的表，那么能不能对一张表进行自我连接呢？答案是肯定的。 
　　有没有必要对一张表进行自我连接呢？答案也是肯定的。 

　　表的别名：

　　一张表可以自我连接。进行自连接时我们需要一个机制来区分一个表的两个实例。 

　　在FROM clause（子句）中我们可以给这个表取不同的别名， 然后在语句的其它需要使用到该别名的地方用dot（点）来连接该别名和字段名。

　　我们在这里同样给出两个表来对自连接进行解释。

　　爱丁堡公交线路，

　　车站表：

　　stops(id, name)

　　公交线路表：

　　route(num, company, pos, stop)

　　一、对公交线路表route进行自连接。

SELECT * FROM route R1, route R2 WHERE R1.num=R2.num AND R1.company=R2.company 

　　我们route表用字段(num, company)来进行自连接． 结果是什么意思呢？

　　你可以知道每条公交线路的任意两个可联通的车站。

　　二、用stop字段来对route（公交线路表）进行自连接。

SELECT * FROM route R1, route R2 WHERE R1.stop=R2.stop; 

　　查询的结果就是共用同一车站的所有公交线。这个结果对换乘是不是很有意义呢。

　　从这两个例子我们可以看出，自连接的语法结构很简单，但语意结果往往不是那么容易理解。就我们这里所列出的两个表，如果运用得当，能解决很多实际问题，例如，任意两个站点之间如何换乘。

SELECT R1.company, R1.num FROM route R1, route R2, stops S1, stops S2
WHERE R1.num=R2.num AND R1.company=R2.company AND R1.stop=S1.id AND R2.stop=S2.id
AND S1.name='Craiglockhart' AND S2.name='Tollcross' 
]]></description>
		</item>
		<item>
			<title>SQL Server 2005—数据库管理10个特点</title>
			<link>http://www.kingmx.com/article.php?id=14590</link>
			<pubDate>2006-11-30</pubDate>
			<description><![CDATA[1.数据库镜像 通过新数据库镜像方法，将记录档案传送性能进行延伸。您将可以使用数据库镜像，通过将自动失效转移建立到一个待用服务器上，增强您SQL服务器系统的可用性。 2.在线恢复 使用SQL2005版服务器，数据库管理人员将可以在SQL服务器运行的情况下，执行恢复操作。在线恢复改进了SQL服务器的可用性，因为只有正在被恢复的数据是无法使用的，而数据库的其他部分依然在线、可供使用。 3.在线检索操作 在线检索选项可以在指数数据定义语言（DDL）执行期间，允许对基底表格、或集簇索引数据和任何有关的检索，进行同步修正。例如，当一个集簇索引正在重建的时候，您可以对基底数据继续进行更新、并且对数据进行查询。 4.快速恢复 新的、速度更快的恢复选项可以改进SQL服务器数据库的可用性。管理人员将能够在事务日志向前滚动之后，重新连接到正在恢复的数据库。 5.安全性能的提高 SQL Server 2005包括了一些在安全性能上的改进，例如数据库加密、设置安全默认值、增强密码政策、缜密的许可控制、以及一个增强型的安全模式。 6.新的SQL Server Management Studio SQL Server 2005引入了SQL Server Management Studio，这是一个新型的统一的管理工具组。这个工具组将包括一些新的功能，以开发、配置SQL Server数据库，发现并修理其中的故障，同时这个工具组还对从前的功能进行了一些改进。 7.专门的管理员连接 SQL Server 2005将引进一个专门的管理员连接，即使在一个服务器被锁住，或者因为其他原因不能使用的时候，管理员可以通过这个连接，接通这个正在运行的服务器。这一功能将能让管理员，通过操作诊断功能、或Transact—SQL指令，找到并解决发现的问题。 8.快照隔离 我们将在数据库层面上提供一个新的快照隔离（SI）标准。通过快照隔离，使用者将能够使用与传统一致的视野观看数据库，存取最后执行的一行数据。这一功能将为服务器提供更大的可升级性。 9.数据分割 数据分割 将加强本地表检索分割，这使得大型表和索引可以得到高效的管理。 10.增强复制功能 对于分布式数据库而言，SQL Server 2005提供了全面的方案修改（DDL）复制、下一代监控性能、从甲骨文（Oracle）到SQL Server的内置复制功能、对多个超文本传输协议（http）进行合并复制，以及就合并复制的可升级性和运行，进行了重大的改良。另外，新的对等交易式复制性能，通过使用复制，改进了其对数据向外扩展的支持。]]></description>
		</item>
		<item>
			<title>数据库死锁导致站点访问故障解决方案</title>
			<link>http://www.kingmx.com/article.php?id=14589</link>
			<pubDate>2006-11-30</pubDate>
			<description><![CDATA[

前段时间完成了一个项目，但是现在该网站访问不了，真是郁闷，主机重启之后，网站运行正常，“狗”（google）也放了，“csdn”也帖了，没有解决，苦恼，后来发现是数据库死锁造成的问题。 通过这个问题，我对数据库思索也小小研究了一下，写一点相关知识。 

死锁原因： 

提取查询数据相应数据，修改Stat表，都是修改同一条数据，进行大数据量的操作，多用户同时操作时，造成数据库死锁和阻塞； 

相关知识： 

1、SQL死锁和阻塞。 

2、死锁测试方法：程序中将数据库操作，循环操作1万次，打开多个窗口同时执行。 

3、查找数据库死锁原因的方法。 

下面的SQL语句运行之后，便可以查找出SQLServer的死锁和阻塞的源头。 

use master
go
declare @spid int,@bl int
DECLARE s_cur CURSOR FOR 
select&nbsp; 0 ,blocked
from (select * from sysprocesses where&nbsp; blocked&gt;0 ) a 
where not exists(select * from (select * from sysprocesses where&nbsp; blocked&gt;0 ) b 
where a.blocked=spid)
union select spid,blocked from sysprocesses where&nbsp; blocked&gt;0
OPEN s_cur
FETCH NEXT FROM s_cur INTO @spid,@bl
WHILE @@FETCH_STATUS = 0
begin
if @spid =0 
&nbsp;select '引起数据库死锁的是: 
'+ CAST(@bl AS VARCHAR(10)) + '进程号,其执行的SQL语法如下'
else
select '进程号SPID：'+ CAST(@spid AS VARCHAR(10))+ '被' + '
进程号SPID：'+ CAST(@bl AS VARCHAR(10)) +'阻塞,其当前进程执行的SQL语法如下'
DBCC INPUTBUFFER (@bl )
FETCH NEXT FROM s_cur INTO @spid,@bl
end
CLOSE s_cur
DEALLOCATE s_cur

exec sp_who2 

4、查看当前进程,或死锁进程,并能自动杀掉死进程： 

处理死锁 

查看当前进程,或死锁进程,并能自动杀掉死进程。因为是针对死的,所以如果有死锁进程,只能查看死锁进程。当然,你可以通过参数控制,不管有没有死锁,都只查看死锁进程。 

调用示例 

exec p_lockinfo
--*/
create proc p_lockinfo
@kill_lock_spid bit=1, --是否杀掉死锁的进程,1 杀掉, 0 仅显示
@show_spid_if_nolock bit=1 --如果没有死锁的进程,
是否显示正常进程信息,1 显示,0 不显示
as
declare @count int,@s nvarchar(1000),@i int
select id=identity(int,1,1),标志,
进程ID=spid,线程ID=kpid,块进程ID=blocked,数据库ID=dbid,
数据库名=db_name(dbid),用户ID=uid,用户名=loginame,累计CPU时间=cpu,
登陆时间=login_time,打开事务数=open_tran, 进程状态=status,
工作站名=hostname,应用程序名=program_name,工作站进程ID=hostprocess,
域名=nt_domain,网卡地址=net_address
into #t from(
select 标志='死锁的进程',
spid,kpid,a.blocked,dbid,uid,loginame,cpu,login_time,open_tran,
status,hostname,program_name,hostprocess,nt_domain,net_address,
s1=a.spid,s2=0
from master..sysprocesses a join (
select blocked from master..sysprocesses group by blocked
)b on a.spid=b.blocked where a.blocked=0
union all
select '|_牺牲品_&gt;',
spid,kpid,blocked,dbid,uid,loginame,cpu,login_time,open_tran,
status,hostname,program_name,hostprocess,nt_domain,net_address,
s1=blocked,s2=1
from master..sysprocesses a where blocked&lt;&gt;0
)a order by s1,s2

select @count=@@rowcount,@i=1

if @count=0 and @show_spid_if_nolock=1
begin
insert #t
select 标志='正常的进程',
spid,kpid,blocked,dbid,db_name(dbid),uid,loginame,cpu,login_time,
open_tran,status,hostname,program_name,hostprocess,nt_domain,net_address
from master..sysprocesses
set @count=@@rowcount
end

if @count&gt;0
begin
create table #t1(id int identity(1,1),a nvarchar(30),
b Int,EventInfo nvarchar(255))
if @kill_lock_spid=1
begin
declare @spid varchar(10),@标志 varchar(10)
while @i&lt;=@count
begin
select @spid=进程ID,@标志=标志 from #t where id=@i
insert #t1 exec('dbcc inputbuffer('+@spid+')')
if @标志='死锁的进程' exec('kill '+@spid)
set @i=@i+1
end
end
else
while @i&lt;=@count
begin
select @s='dbcc inputbuffer('+cast(进程ID as varchar)+')'
&nbsp;from #t where id=@i
insert #t1 exec(@s)
set @i=@i+1
end
select a.*,进程的SQL语句=b.EventInfo
from #t a join #t1 b on a.id=b.id
end
go 

OK，多多指教! 

]]></description>
		</item>
	</channel>
 </rss>
