﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-时间的痕迹-文章分类-SqlServer</title><link>http://www.cppblog.com/ivenher/category/197.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 21 May 2008 09:23:17 GMT</lastBuildDate><pubDate>Wed, 21 May 2008 09:23:17 GMT</pubDate><ttl>60</ttl><item><title>SQL Server 索引结构及其使用（四）[转] </title><link>http://www.cppblog.com/ivenher/articles/12165.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 08 Sep 2006 05:49:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12165.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12165.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12165.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12165.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12165.html</trackback:ping><description><![CDATA[
		<p>
				<b>聚集索引的重要性和如何选择聚集索引</b>
				<br />
				<br />　　在<a href="http://www.vckbase.com/document/viewdoc/?id=1309" target="_blank">上一节</a>的标题中，笔者写的是：实现小数据量和海量数据的通用分页显示存储过程。这是因为在将本存储过程应用于“办公自动化”系统的实践中时，笔者发现这第三种存储过程在小数据量的情况下，有如下现象： <br /><br />1、分页速度一般维持在1秒和3秒之间。 <br /><br />2、在查询最后一页时，速度一般为5秒至8秒，哪怕分页总数只有3页或30万页。 <br /><br />　　虽然在超大容量情况下，这个分页的实现过程是很快的，但在分前几页时，这个1－3秒的速度比起第一种甚至没有经过优化的分页方法速度还要慢，借用户的话说就是“还没有ACCESS数据库速度快”，这个认识足以导致用户放弃使用您开发的系统。 <br />　　笔者就此分析了一下，原来产生这种现象的症结是如此的简单，但又如此的重要：排序的字段不是聚集索引！ <br />　　本篇文章的题目是：“查询优化及分页算法方案”。笔者只所以把“查询优化”和“分页算法”这两个联系不是很大的论题放在一起，就是因为二者都需要一个非常重要的东西――聚集索引。 <br />在前面的讨论中我们已经提到了，聚集索引有两个最大的优势： <br /><br />1、以最快的速度缩小查询范围。 <br /><br />2、以最快的速度进行字段排序。 <br /><br />　　第1条多用在查询优化时，而第2条多用在进行分页时的数据排序。 <br /><br />　　而聚集索引在每个表内又只能建立一个，这使得聚集索引显得更加的重要。聚集索引的挑选可以说是实现“查询优化”和“高效分页”的最关键因素。 <br />　　但要既使聚集索引列既符合查询列的需要，又符合排序列的需要，这通常是一个矛盾。笔者前面“索引”的讨论中，将fariqi，即用户发文日期作为了聚集索引的起始列，日期的精确度为“日”。这种作法的优点，前面已经提到了，在进行划时间段的快速查询中，比用ID主键列有很大的优势。 <br />　　但在分页时，由于这个聚集索引列存在着重复记录，所以无法使用max或min来最为分页的参照物，进而无法实现更为高效的排序。而如果将ID主键列作为聚集索引，那么聚集索引除了用以排序之外，没有任何用处，实际上是浪费了聚集索引这个宝贵的资源。 <br />　　为解决这个矛盾，笔者后来又添加了一个日期列，其默认值为getdate()。用户在写入记录时，这个列自动写入当时的时间，时间精确到毫秒。即使这样，为了避免可能性很小的重合，还要在此列上创建UNIQUE约束。将此日期列作为聚集索引列。 <br />　　有了这个时间型聚集索引列之后，用户就既可以用这个列查找用户在插入数据时的某个时间段的查询，又可以作为唯一列来实现max或min，成为分页算法的参照物。 <br />　　经过这样的优化，笔者发现，无论是大数据量的情况下还是小数据量的情况下，分页速度一般都是几十毫秒，甚至0毫秒。而用日期段缩小范围的查询速度比原来也没有任何迟钝。聚集索引是如此的重要和珍贵，所以笔者总结了一下，一定要将聚集索引建立在： <br /><br />1、您最频繁使用的、用以缩小查询范围的字段上； <br /><br />2、您最频繁使用的、需要排序的字段上。 <br /><br /><b>结束语</b><br /><br />　　本篇文章汇集了笔者近段在使用数据库方面的心得，是在做“办公自动化”系统时实践经验的积累。希望这篇文章不仅能够给大家的工作带来一定的帮助，也希望能让大家能够体会到分析问题的方法；最重要的是，希望这篇文章能够抛砖引玉，掀起大家的学习和讨论的兴趣，以共同促进，共同为公安科技强警事业和金盾工程做出自己最大的努力。 <br />　　最后需要说明的是，在试验中，我发现用户在进行大数据量查询的时候，对数据库速度影响最大的不是内存大小，而是CPU。在我的P4 2.4机器上试验的时候，查看“资源管理器”，CPU经常出现持续到100%的现象，而内存用量却并没有改变或者说没有大的改变。即使在我们的HP ML 350 G3服务器上试验时，CPU峰值也能达到90%，一般持续在70%左右。 <br />　　本文的试验数据都是来自我们的HP ML 350服务器。服务器配置：双Inter Xeon 超线程 CPU 2.4G，内存1G，操作系统Windows Server 2003 Enterprise Edition，数据库SQL Server 2000 SP3 <br /><br />文章引用：<a href="http://www.vckbase.com/document/viewdoc/?id=1310">http://www.vckbase.com/document/viewdoc/?id=1310</a><br /></p>
<img src ="http://www.cppblog.com/ivenher/aggbug/12165.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-08 13:49 <a href="http://www.cppblog.com/ivenher/articles/12165.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL Server 索引结构及其使用（三）[转] </title><link>http://www.cppblog.com/ivenher/articles/12164.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 08 Sep 2006 05:48:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12164.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12164.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12164.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12164.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12164.html</trackback:ping><description><![CDATA[
		<strong>实现小数据量和海量数据的通用分页显示存储过程</strong>
		<br />
		<br />　　建立一个 Web 应用，分页浏览功能必不可少。这个问题是数据库处理中十分常见的问题。经典的数据分页方法是:ADO 纪录集分页法，也就是利用ADO自带的分页功能（利用游标）来实现分页。但这种分页方法仅适用于较小数据量的情形，因为游标本身有缺点：游标是存放在内存中，很费内存。游标一建立，就将相关的记录锁住，直到取消游标。游标提供了对特定集合中逐行扫描的手段，一般使用游标来逐行遍历数据，根据取出数据条件的不同进行不同的操作。而对于多表和大表中定义的游标（大的数据集合）循环很容易使程序进入一个漫长的等待甚至死机。 <br />　　更重要的是，对于非常大的数据模型而言，分页检索时，如果按照传统的每次都加载整个数据源的方法是非常浪费资源的。现在流行的分页方法一般是检索页面大小的块区的数据，而非检索所有的数据，然后单步执行当前行。 <br />　　最早较好地实现这种根据页面大小和页码来提取数据的方法大概就是“俄罗斯存储过程”。这个存储过程用了游标，由于游标的局限性，所以这个方法并没有得到大家的普遍认可。 <br />　　后来，网上有人改造了此存储过程，下面的存储过程就是结合我们的办公自动化实例写的分页存储过程： <pre>CREATE procedure pagination1
(@pagesize int, --页面大小，如每页存储20条记录
@pageindex int --当前页码
)
as

set nocount on

begin
declare @indextable table(id int identity(1,1),nid int) --定义表变量
declare @PageLowerBound int --定义此页的底码
declare @PageUpperBound int --定义此页的顶码
set @PageLowerBound=(@pageindex-1)*@pagesize
set @PageUpperBound=@PageLowerBound+@pagesize
set rowcount @PageUpperBound
insert into @indextable(nid) select gid from TGongwen 
　　　　　　where fariqi &gt;dateadd(day,-365,getdate()) order by fariqi desc
select O.gid,O.mid,O.title,O.fadanwei,O.fariqi from TGongwen O,@indextable t 
           where O.gid=t.nid and t.id&gt;@PageLowerBound 
                        and t.id&lt;=@PageUpperBound order by t.id
end

set nocount off</pre><p>　　以上存储过程运用了SQL SERVER的最新技术――表变量。应该说这个存储过程也是一个非常优秀的分页存储过程。当然，在这个过程中，您也可以把其中的表变量写成临时表：CREATE TABLE #Temp。但很明显，在SQL SERVER中，用临时表是没有用表变量快的。所以笔者刚开始使用这个存储过程时，感觉非常的不错，速度也比原来的ADO的好。但后来，我又发现了比此方法更好的方法。 <br />　　笔者曾在网上看到了一篇小短文《从数据表中取出第n条到第m条的记录的方法》，全文如下： </p><pre>从publish 表中取出第 n 条到第 m 条的记录： 
SELECT TOP m-n+1 * 
FROM publish 
WHERE (id NOT IN 
　　　　(SELECT TOP n-1 id 
　　　　 FROM publish)) 

id 为publish 表的关键字 </pre><p>　　我当时看到这篇文章的时候，真的是精神为之一振，觉得思路非常得好。等到后来，我在作办公自动化系统（ASP.NET+ C#＋SQL SERVER）的时候，忽然想起了这篇文章，我想如果把这个语句改造一下，这就可能是一个非常好的分页存储过程。于是我就满网上找这篇文章，没想到，文章还没找到，却找到了一篇根据此语句写的一个分页存储过程，这个存储过程也是目前较为流行的一种分页存储过程，我很后悔没有争先把这段文字改造成存储过程：</p><pre>CREATE PROCEDURE pagination2
(
@SQL nVARCHAR(4000), --不带排序语句的SQL语句
@Page int, --页码
@RecsPerPage int, --每页容纳的记录数
@ID VARCHAR(255), --需要排序的不重复的ID号
@Sort VARCHAR(255) --排序字段及规则
)
AS

DECLARE @Str nVARCHAR(4000)

SET @Str=''SELECT TOP ''+CAST(@RecsPerPage AS VARCHAR(20))+'' * FROM 
(''+@SQL+'') T WHERE T.''+@ID+''NOT IN (SELECT TOP ''+CAST((@RecsPerPage*(@Page-1)) 
AS VARCHAR(20))+'' ''+@ID+'' FROM (''+@SQL+'') T9 ORDER BY ''+@Sort+'') ORDER BY ''+@Sort

PRINT @Str

EXEC sp_ExecuteSql @Str
GO</pre><p>其实，以上语句可以简化为：</p><pre>SELECT TOP 页大小 *
FROM Table1 WHERE (ID NOT IN (SELECT TOP 页大小*页数 id FROM 表 ORDER BY id))
ORDER BY ID</pre><p>但这个存储过程有一个致命的缺点，就是它含有NOT IN字样。虽然我可以把它改造为：</p><pre>SELECT TOP 页大小 *
FROM Table1 WHERE not exists
(select * from (select top (页大小*页数) * from table1 order by id) b where b.id=a.id )
order by id</pre><p>　　即，用not exists来代替not in，但我们前面已经谈过了，二者的执行效率实际上是没有区别的。既便如此，用TOP 结合NOT IN的这个方法还是比用游标要来得快一些。 <br />　　虽然用not exists并不能挽救上个存储过程的效率，但使用SQL SERVER中的TOP关键字却是一个非常明智的选择。因为分页优化的最终目的就是避免产生过大的记录集，而我们在前面也已经提到了TOP的优势，通过TOP 即可实现对数据量的控制。 <br />　　在分页算法中，影响我们查询速度的关键因素有两点：TOP和NOT IN。TOP可以提高我们的查询速度，而NOT IN会减慢我们的查询速度，所以要提高我们整个分页算法的速度，就要彻底改造NOT IN，同其他方法来替代它。 <br />　　我们知道，几乎任何字段，我们都可以通过max(字段)或min(字段)来提取某个字段中的最大或最小值，所以如果这个字段不重复，那么就可以利用这些不重复的字段的max或min作为分水岭，使其成为分页算法中分开每页的参照物。在这里，我们可以用操作符“&gt;”或“&lt;”号来完成这个使命，使查询语句符合SARG形式。如： </p><pre>Select top 10 * from table1 where id&gt;200</pre><p>于是就有了如下分页方案：</p><pre>select top 页大小 *
from table1 
where id&gt;
(select max (id) from 
(select top ((页码-1)*页大小) id from table1 order by id) as T
) 
order by id</pre><p>　　在选择即不重复值，又容易分辨大小的列时，我们通常会选择主键。下表列出了笔者用有着1000万数据的办公自动化系统中的表，在以GID（GID是主键，但并不是聚集索引。）为排序列、提取gid,fariqi,title字段，分别以第1、10、100、500、1000、1万、10万、25万、50万页为例，测试以上三种分页方案的执行速度：（单位：毫秒）</p><table id="AutoNumber1" style="COLOR: #000000; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" width="70%" border="1"><tbody><tr><td align="middle" width="22%"><b>页码</b></td><td align="middle" width="25%"><b>方案1</b></td><td align="middle" width="30%"><b>方案2</b></td><td align="middle" width="23%"><b>方案3</b></td></tr><tr><td width="22%">1</td><td width="25%">60</td><td width="30%">30</td><td width="23%">76</td></tr><tr><td width="22%">10</td><td width="25%">46</td><td width="30%">16</td><td width="23%">63</td></tr><tr><td width="22%">100</td><td width="25%">1076</td><td width="30%">720</td><td width="23%">130</td></tr><tr><td width="22%">500</td><td width="25%">540</td><td width="30%">12943</td><td width="23%">83</td></tr><tr><td width="22%">1000</td><td width="25%">17110</td><td width="30%">470</td><td width="23%">250</td></tr><tr><td width="22%">10000</td><td width="25%">24796</td><td width="30%">4500</td><td width="23%">140</td></tr><tr><td width="22%">100000</td><td width="25%">38326</td><td width="30%">42283</td><td width="23%">1553</td></tr><tr><td width="22%">250000</td><td width="25%">28140</td><td width="30%">128720</td><td width="23%">2330</td></tr><tr><td width="22%">500000</td><td width="25%">121686</td><td width="30%">127846</td><td width="23%">7168</td></tr></tbody></table><p>　　从上表中，我们可以看出，三种存储过程在执行100页以下的分页命令时，都是可以信任的，速度都很好。但第一种方案在执行分页1000页以上后，速度就降了下来。第二种方案大约是在执行分页1万页以上后速度开始降了下来。而第三种方案却始终没有大的降势，后劲仍然很足。 <br />　　在确定了第三种分页方案后，我们可以据此写一个存储过程。大家知道SQL SERVER的存储过程是事先编译好的SQL语句，它的执行效率要比通过WEB页面传来的SQL语句的执行效率要高。下面的存储过程不仅含有分页方案，还会根据页面传来的参数来确定是否进行数据总数统计。 <br /><br />--获取指定页的数据： </p><pre>CREATE PROCEDURE pagination3
@tblName varchar(255), -- 表名
@strGetFields varchar(1000) = ''*'', -- 需要返回的列 
@fldName varchar(255)='''', -- 排序的字段名
@PageSize int = 10, -- 页尺寸
@PageIndex int = 1, -- 页码
@doCount bit = 0, -- 返回记录总数, 非 0 值则返回
@OrderType bit = 0, -- 设置排序类型, 非 0 值则降序
@strWhere varchar(1500) = '''' -- 查询条件 (注意: 不要加 where)
AS

declare @strSQL varchar(5000) -- 主语句
declare @strTmp varchar(110) -- 临时变量
declare @strOrder varchar(400) -- 排序类型

if @doCount != 0
begin
if @strWhere !=''''
set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere
else
set @strSQL = "select count(*) as Total from [" + @tblName + "]"
end </pre><p>--以上代码的意思是如果@doCount传递过来的不是0，就执行总数统计。以下的所有代码都是@doCount为0的情况：</p><pre>else
begin
if @OrderType != 0
begin
set @strTmp = "&lt;(select min"
set @strOrder = " order by [" + @fldName +"] desc"</pre><p>--如果@OrderType不是0，就执行降序，这句很重要！</p><pre>end
else
begin
set @strTmp = "&gt;(select max"
set @strOrder = " order by [" + @fldName +"] asc"
end

if @PageIndex = 1
begin
if @strWhere != '''' 

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "
　　　　　　　　from [" + @tblName + "] where " + @strWhere + " " + @strOrder
else

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " 
　　　　　　　　from ["+ @tblName + "] "+ @strOrder</pre><p>--如果是第一页就执行以上代码，这样会加快执行速度</p><pre>end
else
begin</pre><p>--以下代码赋予了@strSQL以真正执行的SQL代码 <br />　 </p><pre>set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["
+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "]) 
　　　　　　from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] 
　　　　　　from [" + @tblName + "]" + @strOrder + ") as tblTmp)"+ @strOrder

if @strWhere != ''''
set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["
+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["
+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["
+ @fldName + "] from [" + @tblName + "] where " + @strWhere + " "
+ @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder
end 

end 

exec (@strSQL)

GO
</pre>　　上面的这个存储过程是一个通用的存储过程，其注释已写在其中了。 在大数据量的情况下，特别是在查询最后几页的时候，查询时间一般不会超过9秒；而用其他存储过程，在实践中就会导致超时，所以这个存储过程非常适用于大容量数据库的查询。 笔者希望能够通过对以上存储过程的解析，能给大家带来一定的启示，并给工作带来一定的效率提升，同时希望同行提出更优秀的实时数据分页算法。 <br /><br />文章引自：<a href="http://www.vckbase.com/document/viewdoc/?id=1309">http://www.vckbase.com/document/viewdoc/?id=1309</a><img src ="http://www.cppblog.com/ivenher/aggbug/12164.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-08 13:48 <a href="http://www.cppblog.com/ivenher/articles/12164.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL Server 索引结构及其使用（二）[转] </title><link>http://www.cppblog.com/ivenher/articles/12163.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 08 Sep 2006 05:45:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12163.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12163.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12163.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12163.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12163.html</trackback:ping><description><![CDATA[
		<p>
				<b>改善SQL语句</b>
				<br />
				<br />　　很多人不知道SQL语句在SQL SERVER中是如何执行的，他们担心自己所写的SQL语句会被SQL SERVER误解。比如： </p>
		<pre>select * from table1 where name=''zhangsan'' and tID &gt; 10000</pre>
		<p>和执行:</p>
		<pre>select * from table1 where tID &gt; 10000 and name=''zhangsan''</pre>
		<p>　　一些人不知道以上两条语句的执行效率是否一样，因为如果简单的从语句先后上看，这两个语句的确是不一样，如果tID是一个聚合索引，那么后一句仅仅从表的10000条以后的记录中查找就行了；而前一句则要先从全表中查找看有几个name=''zhangsan''的，而后再根据限制条件条件tID&gt;10000来提出查询结果。 <br />　　事实上，这样的担心是不必要的。SQL SERVER中有一个“查询分析优化器”，它可以计算出where子句中的搜索条件并确定哪个索引能缩小表扫描的搜索空间，也就是说，它能实现自动优化。 <br />　　虽然查询优化器可以根据where子句自动的进行查询优化，但大家仍然有必要了解一下“查询优化器”的工作原理，如非这样，有时查询优化器就会不按照您的本意进行快速查询。 <br />　　在查询分析阶段，查询优化器查看查询的每个阶段并决定限制需要扫描的数据量是否有用。如果一个阶段可以被用作一个扫描参数（SARG），那么就称之为可优化的，并且可以利用索引快速获得所需数据。 <br />　　SARG的定义：用于限制搜索的一个操作，因为它通常是指一个特定的匹配，一个值得范围内的匹配或者两个以上条件的AND连接。形式如下： </p>
		<pre>列名 操作符 &lt;常数 或 变量&gt;

或

&lt;常数 或 变量&gt; 操作符列名</pre>
		<p>列名可以出现在操作符的一边，而常数或变量出现在操作符的另一边。如：</p>
		<pre>Name=’张三’

价格&gt;5000

5000&lt;价格

Name=’张三’ and 价格&gt;5000</pre>
		<p>　　如果一个表达式不能满足SARG的形式，那它就无法限制搜索的范围了，也就是SQL SERVER必须对每一行都判断它是否满足WHERE子句中的所有条件。所以一个索引对于不满足SARG形式的表达式来说是无用的。 <br />　　介绍完SARG后，我们来总结一下使用SARG以及在实践中遇到的和某些资料上结论不同的经验： <br /><br />1、Like语句是否属于SARG取决于所使用的通配符的类型 </p>
		<pre>如：name like ‘张%’ ，这就属于SARG

而：name like ‘%张’ ,就不属于SARG。</pre>
		<p>原因是通配符%在字符串的开通使得索引无法使用。 <br /><br />2、or 会引起全表扫描 <br />　　Name=’张三’ and 价格&gt;5000 符号SARG，而：Name=’张三’ or 价格&gt;5000 则不符合SARG。使用or会引起全表扫描。 <br /><br />3、非操作符、函数引起的不满足SARG形式的语句 <br />　　不满足SARG形式的语句最典型的情况就是包括非操作符的语句，如：NOT、!=、&lt;&gt;、!&lt;、!&gt;、NOT EXISTS、NOT IN、NOT LIKE等，另外还有函数。下面就是几个不满足SARG形式的例子： </p>
		<pre>ABS(价格)&lt;5000

Name like ‘%三’

有些表达式，如：

WHERE 价格*2&gt;5000

SQL SERVER也会认为是SARG，SQL SERVER会将此式转化为：
WHERE 价格&gt;2500/2</pre>
		<p>但我们不推荐这样使用，因为有时SQL SERVER不能保证这种转化与原始表达式是完全等价的。 <br /><br />4、IN 的作用相当与OR <br /><br />语句： </p>
		<pre>Select * from table1 where tid in (2,3)

和

Select * from table1 where tid=2 or tid=3</pre>
		<p>是一样的，都会引起全表扫描，如果tid上有索引，其索引也会失效。 <br /><br />5、尽量少用NOT <br /><br />6、exists 和 in 的执行效率是一样的 <br />　　很多资料上都显示说，exists要比in的执行效率要高，同时应尽可能的用not exists来代替not in。但事实上，我试验了一下，发现二者无论是前面带不带not，二者之间的执行效率都是一样的。因为涉及子查询，我们试验这次用SQL SERVER自带的pubs数据库。运行前我们可以把SQL SERVER的statistics I/O状态打开： </p>
		<pre>（1）select title,price from titles where title_id in (select title_id from sales where qty&gt;30)</pre>
		<p>该句的执行结果为： <br /><br />表 ''sales''。扫描计数 18，逻辑读 56 次，物理读 0 次，预读 0 次。 <br />表 ''titles''。扫描计数 1，逻辑读 2 次，物理读 0 次，预读 0 次。 </p>
		<pre>（2）select title,price from titles 
　　　　　　　where exists (select * from sales 
　　　　　　　where sales.title_id=titles.title_id and qty&gt;30)</pre>
		<p>第二句的执行结果为： <br /><br />表 ''sales''。扫描计数 18，逻辑读 56 次，物理读 0 次，预读 0 次。 <br />表 ''titles''。扫描计数 1，逻辑读 2 次，物理读 0 次，预读 0 次。 <br /><br />我们从此可以看到用exists和用in的执行效率是一样的。 <br /><br />7、用函数charindex()和前面加通配符%的LIKE执行效率一样 <br />　　前面，我们谈到，如果在LIKE前面加上通配符%，那么将会引起全表扫描，所以其执行效率是低下的。但有的资料介绍说，用函数charindex()来代替LIKE速度会有大的提升，经我试验，发现这种说明也是错误的： <br />　 </p>
		<pre>select gid,title,fariqi,reader from tgongwen 
　　　　　　　　　where charindex(''刑侦支队'',reader)&gt;0 and fariqi&gt;''2004-5-5''</pre>
		<p>用时：7秒，另外：扫描计数 4，逻辑读 7155 次，物理读 0 次，预读 0 次。</p>
		<pre>select gid,title,fariqi,reader from tgongwen 
　　　　　　　　　where reader like ''%'' + ''刑侦支队'' + ''%'' and fariqi&gt;''2004-5-5''</pre>
		<p>用时：7秒，另外：扫描计数 4，逻辑读 7155 次，物理读 0 次，预读 0 次。 <br /><br />8、union并不绝对比or的执行效率高 <br />　　我们前面已经谈到了在where子句中使用or会引起全表扫描，一般的，我所见过的资料都是推荐这里用union来代替or。事实证明，这种说法对于大部分都是适用的。 </p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
　　　　　　　　　　where fariqi=''2004-9-16'' or gid&gt;9990000</pre>
		<p>用时：68秒。扫描计数 1，逻辑读 404008 次，物理读 283 次，预读 392163 次。</p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16'' 
union
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid&gt;9990000</pre>
		<p>用时：9秒。扫描计数 8，逻辑读 67489 次，物理读 216 次，预读 7499 次。 <br /><br />看来，用union在通常情况下比用or的效率要高的多。 <br /><br />　　但经过试验，笔者发现如果or两边的查询列是一样的话，那么用union则反倒和用or的执行速度差很多，虽然这里union扫描的是索引，而or扫描的是全表。 <br />　 </p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
　　　　　　　　　　where fariqi=''2004-9-16'' or fariqi=''2004-2-5''</pre>
		<p>用时：6423毫秒。扫描计数 2，逻辑读 14726 次，物理读 1 次，预读 7176 次。</p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16'' 
union
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-2-5''</pre>
		<p>用时：11640毫秒。扫描计数 8，逻辑读 14806 次，物理读 108 次，预读 1144 次。 <br /><br />9、字段提取要按照“需多少、提多少”的原则，避免“select *” <br />　　我们来做一个试验： </p>
		<pre>select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc</pre>
		<p>用时：4673毫秒</p>
		<pre>select top 10000 gid,fariqi,title from tgongwen order by gid desc</pre>
		<p>用时：1376毫秒</p>
		<pre>select top 10000 gid,fariqi from tgongwen order by gid desc</pre>
		<p>用时：80毫秒 <br /><br />　　由此看来，我们每少提取一个字段，数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。 <br /><br />10、count(*)不比count(字段)慢 <br />　　某些资料上说：用*会统计所有列，显然要比一个世界的列名效率低。这种说法其实是没有根据的。我们来看： </p>
		<pre>select count(*) from Tgongwen</pre>
		<p>用时：1500毫秒</p>
		<pre>select count(gid) from Tgongwen </pre>
		<p>用时：1483毫秒</p>
		<pre>select count(fariqi) from Tgongwen</pre>
		<p>用时：3140毫秒</p>
		<pre>select count(title) from Tgongwen</pre>
		<p>用时：52050毫秒 <br /><br />　　从以上可以看出，如果用count(*)和用count(主键)的速度是相当的，而count(*)却比其他任何除主键以外的字段汇总速度要快，而且字段越长，汇总的速度就越慢。我想，如果用count(*)， SQL SERVER可能会自动查找最小字段来汇总的。当然，如果您直接写count(主键)将会来的更直接些。 <br /><br />11、order by按聚集索引列排序效率最高 <br />　　我们来看：（gid是主键，fariqi是聚合索引列）： </p>
		<pre>select top 10000 gid,fariqi,reader,title from tgongwen</pre>
		<p>用时：196 毫秒。 扫描计数 1，逻辑读 289 次，物理读 1 次，预读 1527 次。</p>
		<pre>select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc</pre>
		<p>用时：4720毫秒。 扫描计数 1，逻辑读 41956 次，物理读 0 次，预读 1287 次。</p>
		<pre>select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc</pre>
		<p>用时：4736毫秒。 扫描计数 1，逻辑读 55350 次，物理读 10 次，预读 775 次。</p>
		<pre>select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc</pre>
		<p>用时：173毫秒。 扫描计数 1，逻辑读 290 次，物理读 0 次，预读 0 次。</p>
		<pre>select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc</pre>
		<p>用时：156毫秒。 扫描计数 1，逻辑读 289 次，物理读 0 次，预读 0 次。 <br /><br />　　从以上我们可以看出，不排序的速度以及逻辑读次数都是和“order by 聚集索引列” 的速度是相当的，但这些都比“order by 非聚集索引列”的查询速度是快得多的。 <br />　　同时，按照某个字段进行排序的时候，无论是正序还是倒序，速度是基本相当的。 <br /><br />12、高效的TOP <br />　　事实上，在查询和提取超大容量的数据集时，影响数据库响应时间的最大因素不是数据查找，而是物理的I/0操作。如： </p>
		<pre>select top 10 * from (
select top 10000 gid,fariqi,title from tgongwen
where neibuyonghu=''办公室''
order by gid desc) as a
order by gid asc</pre>
		<p>　　这条语句，从理论上讲，整条语句的执行时间应该比子句的执行时间长，但事实相反。因为，子句执行后返回的是10000条记录，而整条语句仅返回10条语句，所以影响数据库响应时间最大的因素是物理I/O操作。而限制物理I/O操作此处的最有效方法之一就是使用TOP关键词了。TOP关键词是SQL SERVER中经过系统优化过的一个用来提取前几条或前几个百分比数据的词。经笔者在实践中的应用，发现TOP确实很好用，效率也很高。但这个词在另外一个大型数据库ORACLE中却没有，这不能说不是一个遗憾，虽然在ORACLE中可以用其他方法（如：rownumber）来解决。在以后的关于“实现千万级数据的分页显示存储过程”的讨论中，我们就将用到TOP这个关键词。 <br />　　到此为止，我们上面讨论了如何实现从大容量的数据库中快速地查询出您所需要的数据方法。当然，我们介绍的这些方法都是“软”方法，在实践中，我们还要考虑各种“硬”因素，如：网络性能、服务器的性能、操作系统的性能，甚至网卡、交换机等。 <br /><br />文章引自：<a href="http://www.vckbase.com/document/viewdoc/?id=1308">http://www.vckbase.com/document/viewdoc/?id=1308</a></p>
<img src ="http://www.cppblog.com/ivenher/aggbug/12163.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-08 13:45 <a href="http://www.cppblog.com/ivenher/articles/12163.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL Server 索引结构及其使用（一）</title><link>http://www.cppblog.com/ivenher/articles/12162.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 08 Sep 2006 05:38:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12162.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12162.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12162.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12162.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12162.html</trackback:ping><description><![CDATA[
		<p>
				<b>一、深入浅出理解索引结构</b>
				<br />
				<br />　　实际上，您可以把索引理解为一种特殊的目录。微软的SQL SERVER提供了两种索引：聚集索引（clustered index，也称聚类索引、簇集索引）和非聚集索引（nonclustered index，也称非聚类索引、非簇集索引）。下面，我们举例来说明一下聚集索引和非聚集索引的区别： <br />　　其实，我们的汉语字典的正文本身就是一个聚集索引。比如，我们要查“安”字，就会很自然地翻开字典的前几页，因为“安”的拼音是“an”，而按照拼音排序汉字的字典是以英文字母“a”开头并以“z”结尾的，那么“安”字就自然地排在字典的前部。如果您翻完了所有以“a”开头的部分仍然找不到这个字，那么就说明您的字典中没有这个字；同样的，如果查“张”字，那您也会将您的字典翻到最后部分，因为“张”的拼音是“zhang”。也就是说，字典的正文部分本身就是一个目录，您不需要再去查其他目录来找到您需要找的内容。我们把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。 <br />　　如果您认识某个字，您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字，不知道它的发音，这时候，您就不能按照刚才的方法找到您要查的字，而需要去根据“偏旁部首”查到您要找的字，然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序并不是真正的正文的排序方法，比如您查“张”字，我们可以看到在查部首之后的检字表中“张”的页码是672页，检字表中“张”的上面是“驰”字，但页码却是63页，“张”的下面是“弩”字，页面是390页。很显然，这些字并不是真正的分别位于“张”字的上下方，现在您看到的连续的“驰、张、弩”三字实际上就是他们在非聚集索引中的排序，是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字，但它需要两个过程，先找到目录中的结果，然后再翻到您所需要的页码。我们把这种目录纯粹是目录，正文纯粹是正文的排序方式称为“非聚集索引”。 <br />　　通过以上例子，我们可以理解到什么是“聚集索引”和“非聚集索引”。进一步引申一下，我们可以很容易的理解：每个表只能有一个聚集索引，因为目录只能按照一种方法进行排序。 <br /><br /><b>二、何时使用聚集索引或非聚集索引</b><br /><br />下面的表总结了何时使用聚集索引或非聚集索引（很重要）： </p>
		<table id="AutoNumber1" style="COLOR: #000000; BORDER-COLLAPSE: collapse" height="107" cellspacing="0" cellpadding="0" width="62%" border="1">
				<tbody>
						<tr>
								<td align="middle" width="40%" height="23">动作描述</td>
								<td align="middle" width="29%" height="23">使用聚集索引</td>
								<td align="middle" width="31%" height="23">使用非聚集索引</td>
						</tr>
						<tr>
								<td width="40%" height="20">列经常被分组排序</td>
								<td width="29%" height="20">应</td>
								<td width="31%" height="20">应</td>
						</tr>
						<tr>
								<td width="40%" height="20">返回某范围内的数据</td>
								<td width="29%" height="20">应</td>
								<td width="31%" height="20">不应</td>
						</tr>
						<tr>
								<td width="40%" height="20">一个或极少不同值</td>
								<td width="29%" height="20">不应</td>
								<td width="31%" height="20">不应</td>
						</tr>
						<tr>
								<td width="40%" height="20">小数目的不同值</td>
								<td width="29%" height="20">应</td>
								<td width="31%" height="20">不应</td>
						</tr>
						<tr>
								<td width="40%" height="20">大数目的不同值</td>
								<td width="29%" height="20">不应</td>
								<td width="31%" height="20">应</td>
						</tr>
						<tr>
								<td width="40%" height="20">频繁更新的列</td>
								<td width="29%" height="20">不应</td>
								<td width="31%" height="20">应</td>
						</tr>
						<tr>
								<td width="40%" height="20">外键列</td>
								<td width="29%" height="20">应</td>
								<td width="31%" height="20">应</td>
						</tr>
						<tr>
								<td width="40%" height="20">主键列</td>
								<td width="29%" height="20">应</td>
								<td width="31%" height="20">应</td>
						</tr>
						<tr>
								<td width="40%" height="20">频繁修改索引列</td>
								<td width="29%" height="20">不应</td>
								<td width="31%" height="20">应</td>
						</tr>
				</tbody>
		</table>
		<p>　　事实上，我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如：返回某范围内的数据一项。比如您的某个表有一个时间列，恰好您把聚合索引建立在了该列，这时您查询2004年1月1日至2004年10月1日之间的全部数据时，这个速度就将是很快的，因为您的这本字典正文是按日期进行排序的，聚类索引只需要找到要检索的所有数据中的开头和结尾数据即可；而不像非聚集索引，必须先查到目录中查到每一项数据对应的页码，然后再根据页码查到具体内容。 <br /><br /><b>三、结合实际，谈索引使用的误区</b><br /><br />　　理论的目的是应用。虽然我们刚才列出了何时应使用聚集索引或非聚集索引，但在实践中以上规则却很容易被忽视或不能根据实际情况进行综合分析。下面我们将根据在实践中遇到的实际问题来谈一下索引使用的误区，以便于大家掌握索引建立的方法。 <br /><br />1、主键就是聚集索引 <br />　　这种想法笔者认为是极端错误的，是对聚集索引的一种浪费。虽然SQL SERVER默认是在主键上建立聚集索引的。 <br />　　通常，我们会在每个表中都建立一个ID列，以区分每条数据，并且这个ID列是自动增大的，步长一般为1。我们的这个办公自动化的实例中的列Gid就是如此。此时，如果我们将这个列设为主键，SQL SERVER会将此列默认为聚集索引。这样做有好处，就是可以让您的数据在数据库中按照ID进行物理排序，但笔者认为这样做意义不大。 <br />　　显而易见，聚集索引的优势是很明显的，而每个表中只能有一个聚集索引的规则，这使得聚集索引变得更加珍贵。 <br />　　从我们前面谈到的聚集索引的定义我们可以看出，使用聚集索引的最大好处就是能够根据查询要求，迅速缩小查询范围，避免全表扫描。在实际应用中，因为ID号是自动生成的，我们并不知道每条记录的ID号，所以我们很难在实践中用ID号来进行查询。这就使让ID号这个主键作为聚集索引成为一种资源浪费。其次，让每个ID号都不同的字段作为聚集索引也不符合“大数目的不同值情况下不应建立聚合索引”规则；当然，这种情况只是针对用户经常修改记录内容，特别是索引项的时候会负作用，但对于查询速度并没有影响。 <br />　　在办公自动化系统中，无论是系统首页显示的需要用户签收的文件、会议还是用户进行文件查询等任何情况下进行数据查询都离不开字段的是“日期”还有用户本身的“用户名”。 <br />　　通常，办公自动化的首页会显示每个用户尚未签收的文件或会议。虽然我们的where语句可以仅仅限制当前用户尚未签收的情况，但如果您的系统已建立了很长时间，并且数据量很大，那么，每次每个用户打开首页的时候都进行一次全表扫描，这样做意义是不大的，绝大多数的用户1个月前的文件都已经浏览过了，这样做只能徒增数据库的开销而已。事实上，我们完全可以让用户打开系统首页时，数据库仅仅查询这个用户近3个月来未阅览的文件，通过“日期”这个字段来限制表扫描，提高查询速度。如果您的办公自动化系统已经建立的2年，那么您的首页显示速度理论上将是原来速度8倍，甚至更快。 <br />　　在这里之所以提到“理论上”三字，是因为如果您的聚集索引还是盲目地建在ID这个主键上时，您的查询速度是没有这么高的，即使您在“日期”这个字段上建立的索引（非聚合索引）。下面我们就来看一下在1000万条数据量的情况下各种查询的速度表现（3个月内的数据为25万条）： <br /><br />（1）仅在主键上建立聚集索引，并且不划分时间段： </p>
		<pre>Select gid,fariqi,neibuyonghu,title from tgongwen</pre>
		<p>用时：128470毫秒（即：128秒） <br /><br />（2）在主键上建立聚集索引，在fariq上建立非聚集索引： </p>
		<pre>select gid,fariqi,neibuyonghu,title from Tgongwen
where fariqi&gt; dateadd(day,-90,getdate())</pre>
		<p>用时：53763毫秒（54秒） <br /><br />（3）将聚合索引建立在日期列（fariqi）上： </p>
		<pre>select gid,fariqi,neibuyonghu,title from Tgongwen
where fariqi&gt; dateadd(day,-90,getdate())</pre>
		<p>用时：2423毫秒（2秒） <br /><br />　　虽然每条语句提取出来的都是25万条数据，各种情况的差异却是巨大的，特别是将聚集索引建立在日期列时的差异。事实上，如果您的数据库真的有1000万容量的话，把主键建立在ID列上，就像以上的第1、2种情况，在网页上的表现就是超时，根本就无法显示。这也是我摒弃ID列作为聚集索引的一个最重要的因素。得出以上速度的方法是：在各个select语句前加： </p>
		<pre>declare @d datetime
set @d=getdate()</pre>
		<p>并在select语句后加：</p>
		<pre>select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())</pre>
		<p>2、只要建立索引就能显著提高查询速度 <br />　　事实上，我们可以发现上面的例子中，第2、3条语句完全相同，且建立索引的字段也相同；不同的仅是前者在fariqi字段上建立的是非聚合索引，后者在此字段上建立的是聚合索引，但查询速度却有着天壤之别。所以，并非是在任何字段上简单地建立索引就能提高查询速度。 <br />　　从建表的语句中，我们可以看到这个有着1000万数据的表中fariqi字段有5003个不同记录。在此字段上建立聚合索引是再合适不过了。在现实中，我们每天都会发几个文件，这几个文件的发文日期就相同，这完全符合建立聚集索引要求的：“既不能绝大多数都相同，又不能只有极少数相同”的规则。由此看来，我们建立“适当”的聚合索引对于我们提高查询速度是非常重要的。 <br /><br />3、把所有需要提高查询速度的字段都加进聚集索引，以提高查询速度 <br />　　上面已经谈到：在进行数据查询时都离不开字段的是“日期”还有用户本身的“用户名”。既然这两个字段都是如此的重要，我们可以把他们合并起来，建立一个复合索引（compound index）。 <br />　　很多人认为只要把任何字段加进聚集索引，就能提高查询速度，也有人感到迷惑：如果把复合的聚集索引字段分开查询，那么查询速度会减慢吗？带着这个问题，我们来看一下以下的查询速度（结果集都是25万条数据）：（日期列fariqi首先排在复合聚集索引的起始列，用户名neibuyonghu排在后列）： </p>
		<pre>（1）select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi&gt;''2004-5-5'' </pre>
		<p>查询速度：2513毫秒</p>
		<pre>（2）select gid,fariqi,neibuyonghu,title from Tgongwen 
　　　　　　　　　　　　where fariqi&gt;''2004-5-5'' and neibuyonghu=''办公室''</pre>
		<p>查询速度：2516毫秒</p>
		<pre>（3）select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu=''办公室''</pre>
		<p>查询速度：60280毫秒 <br /><br />　　从以上试验中，我们可以看到如果仅用聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一样的，甚至比用上全部的复合索引列还要略快（在查询结果集数目一样的情况下）；而如果仅用复合聚集索引的非起始列作为查询条件的话，这个索引是不起任何作用的。当然，语句1、2的查询速度一样是因为查询的条目数一样，如果复合索引的所有列都用上，而且查询结果少的话，这样就会形成“索引覆盖”，因而性能可以达到最优。同时，请记住：无论您是否经常使用聚合索引的其他列，但其前导列一定要是使用最频繁的列。 <br /><br /><b>四、其他书上没有的索引使用经验总结</b><br /><br />1、用聚合索引比用不是聚合索引的主键速度快 <br />　　下面是实例语句：（都是提取25万条数据） </p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16''</pre>
		<p>使用时间：3326毫秒</p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid&lt;=250000</pre>
		<p>使用时间：4470毫秒 <br /><br />这里，用聚合索引比用不是聚合索引的主键速度快了近1/4。 <br /><br />2、用聚合索引比用一般的主键作order by时速度快，特别是在小数据量情况下 </p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi</pre>
		<p>用时：12936</p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid</pre>
		<p>用时：18843 <br /><br />　　这里，用聚合索引比用一般的主键作order by时，速度快了3/10。事实上，如果数据量很小的话，用聚集索引作为排序列要比使用非聚集索引速度快得明显的多；而数据量如果很大的话，如10万以上，则二者的速度差别不明显。 <br /><br />3、使用聚合索引内的时间段，搜索时间会按数据占整个数据表的百分比成比例减少，而无论聚合索引使用了多少个： </p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi&gt;''2004-1-1''</pre>
		<p>用时：6343毫秒（提取100万条） </p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi&gt;''2004-6-6''</pre>
		<p>用时：3170毫秒（提取50万条）</p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16''</pre>
		<p>用时：3326毫秒（和上句的结果一模一样。如果采集的数量一样，那么用大于号和等于号是一样的）</p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
　　　　　　　　　　　　where fariqi&gt;''2004-1-1'' and fariqi&lt;''2004-6-6''</pre>
		<p>用时：3280毫秒 <br /><br />4、日期列不会因为有分秒的输入而减慢查询速度 <br />　　下面的例子中，共有100万条数据，2004年1月1日以后的数据有50万条，但只有两个不同的日期，日期精确到日；之前有数据50万条，有5000个不同的日期，日期精确到秒。 </p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
　　　　　　　　　　where fariqi&gt;''2004-1-1'' order by fariqi</pre>
		<p>用时：6390毫秒</p>
		<pre>select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
　　　　　　　　　　　　where fariqi&lt;''2004-1-1'' order by fariqi</pre>
		<p>用时：6453毫秒 <br /><br /><b>五、其他注意事项</b><br /><br />　　“水可载舟，亦可覆舟”，索引也一样。索引有助于提高检索性能，但过多或不当的索引也会导致系统低效。因为用户在表中每加进一个索引，数据库就要做更多的工作。过多的索引甚至会导致索引碎片。 <br />　　所以说，我们要建立一个“适当”的索引体系，特别是对聚合索引的创建，更应精益求精，以使您的数据库能得到高性能的发挥。 <br />　　当然，在实践中，作为一个尽职的数据库管理员，您还要多测试一些方案，找出哪种方案效率最高、最为有效。 <br /><br /><span style="COLOR: red" twffan="done"><p>听棠注：此文章引自<a href="http://www.vckbase.com/document/viewdoc/?id=1307">http://www.vckbase.com/document/viewdoc/?id=1307</a><br /> 感觉笔者讲比较透彻，并参考了另一篇：<a href="http://www.20cn.net/ns/wz/soft/data/20040111171601.htm" target="_blank">索引的使用和优化</a></p><p> 思想基本一致的，总结下来，对日期建立聚集索引比较合适。</p><p> 还有一有关索引性能的MS的文章：<a href="http://www.microsoft.com/china/msdn/Archives/msdnonline/features/articles/Indexedviews.ASP" target="_blank" name="indexedviews">使用 <font face="arial">SQL Server 2000</font> 索引视图提高性能</a></p></span></p>
<img src ="http://www.cppblog.com/ivenher/aggbug/12162.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-08 13:38 <a href="http://www.cppblog.com/ivenher/articles/12162.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC数据库编程笔记（一）</title><link>http://www.cppblog.com/ivenher/articles/4917.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Sun, 02 Apr 2006 14:51:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/4917.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/4917.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/4917.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/4917.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/4917.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="mso-bidi-font-family: 宋体">
						<span style="mso-list: Ignore">一、</span>
				</span>
				<span lang="EN-US">VC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供的数据库访问技术</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
				<span lang="EN-US">ODBC API</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span>
				<span lang="EN-US">MFC ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span>
				<span lang="EN-US">DAO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span>
				<span lang="EN-US">OLE DB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span>
				<span lang="EN-US">ADO</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">访问速度：传统的</span>
				<span lang="EN-US">ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">速度较慢。</span>
				<span lang="EN-US">OLE DB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span>
				<span lang="EN-US"> ADO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">都是基于</span>
				<span lang="EN-US">COM</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">技术，使用该技术可以直接访问数据库的驱动程序，速度大大提高。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?>
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可扩展性：通过</span>
				<span lang="EN-US">OLE DB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span>
				<span lang="EN-US"> ActiveX</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">技术，可以利用</span>
				<span lang="EN-US">VC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供的各种组件，控件和第三方提供的组建。从而实现应用程序组件化。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">访问不同数据源：传统</span>
				<span lang="EN-US">ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">只能访问关系数据库。</span>
				<span lang="EN-US">VC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中提供</span>
				<span lang="EN-US">OLD DB </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">技术可以解决该问题。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="mso-bidi-font-family: 宋体">
						<span style="mso-list: Ignore">二、</span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">几种技术概述</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo2; tab-stops: list 18.0pt">
				<span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">1、<span style="FONT: 7pt 'Times New Roman'">  </span></span>
				</span>
				<span lang="EN-US">ODBC API</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供一个通用接口，为</span>
				<span lang="EN-US">ORACLE</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span>
				<span lang="EN-US">SQLSERVER</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">都提供了驱动程序。用户可以</span>
				<span lang="EN-US">SQL</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">语句对数据库进行直接的底层功能操作。使用时应包含以下头文件。</span>
				<span lang="EN-US">”SQL.H”,”SQLEXT.H”,”SQLTYPES.H”.</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用步骤如下：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第一步：分配</span>
				<span lang="EN-US">ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">环境，初始化一些内部结构。完成该步，需要分配一个</span>
				<span lang="EN-US">SQLHENV</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类型的变量在</span>
				<span lang="EN-US">ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">环境中做句柄使用。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第二步：为将要使用的每一个数据源分配一个连接句柄，有函数</span>
				<span lang="EN-US">SQLALLocHandle</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（）完成。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第三步：使用</span>
				<span lang="EN-US">SQLConnect</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（）把连接句柄与数据库连接，可以先通过</span>
				<span lang="EN-US">SQLSetConnectAttr</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（）设置连接属性。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第四步：进行</span>
				<span lang="EN-US">SQL</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">语句操作。操作完就可以断开与数据库的连接。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第五步：释放</span>
				<span lang="EN-US">ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">环境。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">特点：功能强大，提供异步操作，事务处理等高级功能。目前所有关系数据库都提供了</span>
				<span lang="EN-US">ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的驱动程序，使用很广泛。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">缺点：很难访问对象数据库和非关系数据库。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo2; tab-stops: list 18.0pt">
				<span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">2、<span style="FONT: 7pt 'Times New Roman'">  </span></span>
				</span>
				<span lang="EN-US">MFC ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为简化使用</span>
				<span lang="EN-US">ODBC API</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span>
				<span lang="EN-US">VC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供了</span>
				<span lang="EN-US">MFC ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类，封装了</span>
				<span lang="EN-US">ODBC API</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">主要</span>
				<span lang="EN-US">MFC ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类如下：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">CDatabase</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类：一个</span>
				<span lang="EN-US">CDatabase</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象表示一个到数据源的连接，通过它可以操作数据源。一般不需要直接使用</span>
				<span lang="EN-US">CDatabase</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象，因为</span>
				<span lang="EN-US">CDecordSet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象可以实现大多数功能，但在进行事务处理时，</span>
				<span lang="EN-US">CDatabase</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">就起到关键作用。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">CRecordSet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类：一个</span>
				<span lang="EN-US">CRecordSet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象代表一个从数据源选择的一组记录的集合</span>
				<span lang="EN-US">-----</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">记录集。记录集有两种形式：</span>
				<span lang="EN-US">snapshot</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span>
				<span lang="EN-US">dynaset</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。前者表示是静态视图。后者表示记录集与其它用户对数据库的更新保持同步。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">CRecordView</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类：是在空间中显示数据库记录的视图。这种视图是直接连到一个</span>
				<span lang="EN-US">CRecordSet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象的格式视图。他从一个对话框模版资源创建。并将</span>
				<span lang="EN-US">CRecordSet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象的字段显示在对话框模版的控件里。对象利用</span>
				<span lang="EN-US">DDX</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span>
				<span lang="EN-US">RFX</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">机制。使格式上的控件和记录集的字段之间数据移动自动化。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">CDBException</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类：由</span>
				<span lang="EN-US">Cexception</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类派生，以</span>
				<span lang="EN-US">3</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个继承的变量反映对数据库操作时的异常。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-spacerun: yes"> </span>M_nRetCode:<span style="mso-spacerun: yes">  </span>ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">返回码。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">M_strError: </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字符串，描述造成抛出异常的错误原因。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">M_strStateNativeOrigin: </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字符串，描述以</span>
				<span lang="EN-US">ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">错误码表示的异常错误。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo2; tab-stops: list 18.0pt">
				<span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">3、<span style="FONT: 7pt 'Times New Roman'">  </span></span>
				</span>
				<span lang="EN-US">MFC DAO</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">MFC DAO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是微软提供的用于访问</span>
				<span lang="EN-US">Microsoft Jet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数据库文件（</span>
				<span lang="EN-US">*</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span>
				<span lang="EN-US">Mdb</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）的工具。当只需访问</span>
				<span lang="EN-US">Access</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数据库时用该技术很方便。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo2; tab-stops: list 18.0pt">
				<span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">4、<span style="FONT: 7pt 'Times New Roman'">  </span></span>
				</span>
				<span lang="EN-US">OLE DB</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">与</span>
				<span lang="EN-US">ODBC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">技术类似，</span>
				<span lang="EN-US">OLE DB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">属于数据库访问技术中的底层接口。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">直接使用</span>
				<span lang="EN-US">OLEDB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">需要大量代码，</span>
				<span lang="EN-US">VC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中提供了</span>
				<span lang="EN-US">ATL</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">模版，</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">OLEDB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">框架定义了应用的</span>
				<span lang="EN-US">3</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个基本类。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数据提供程序</span>
				<span lang="EN-US">Data Provider</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">拥有自己的数据并以表格形式显示数据的应用程序。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用者</span>
				<span lang="EN-US">Consumers</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：试用</span>
				<span lang="EN-US">OLEDB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口对存储在数据提供程序中对数据进行控制的应用程序。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">服务提供程序</span>
				<span lang="EN-US">ServiceProvider</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：是数据提供程序和使用者的组合。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用</span>
				<span lang="EN-US">OLE DB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">编程时，用户使用组件对象开发程序，这些组件包括：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">枚举器：用于列出可用的数据源；</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数据源：代表单独的数据和服务提供程序，用于创建对话；</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对话：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">    </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于创建事务和命令；</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">事务：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">    </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于将多个操作归并为单一事务处理；</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">命令：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">    </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于向数据源发送文本命令（</span>
				<span lang="EN-US">SQL</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">），返回行集；</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">错误：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">    </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于获得错误信息。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo2; tab-stops: list 18.0pt">
				<span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">5、<span style="FONT: 7pt 'Times New Roman'">  </span></span>
				</span>
				<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /?>
				<st1:city w:st="on">
						<st1:place w:st="on">
								<span lang="EN-US">ADO</span>
						</st1:place>
				</st1:city>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">ADO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">技术是基于</span>
				<span lang="EN-US">OLE DB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的访问接口。继承了</span>
				<span lang="EN-US">OLEDB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的优点，并对</span>
				<span lang="EN-US">OLEDB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的接口作了封装，定义了</span>
				<span lang="EN-US">ADO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象，使开发简化。</span>
				<span lang="EN-US">ADO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">属于数据库访问的高层接口。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">ADO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在服务器应用方面非常有效，特别是动态服务器页面（</span>
				<span lang="EN-US">ASP</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）的支持。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">ADO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象结构类似于</span>
				<span lang="EN-US">OLEDB</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，但并不依靠对象层次。大多数情况用户只需创建并使用需要的对象。下面的对象类组成了</span>
				<span lang="EN-US">ADO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Connection</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">  </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于表示与数据库的连接，以及处理一些事务和命令。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Command</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">   </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于处理传送给数据源的命令。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Recordset</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">   </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于处理数据的表格集，</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">包括获取和修改数据。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Field</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 2">           </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于表示记录集中的列信息，包括列值和其他信息。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Parameter</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">   </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在传送给数据源的命令之间传递数据。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Property</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">     </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于操作在</span>
				<span lang="EN-US">ADO</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中使用的其它对象的详细属性。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Errro</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 2">          </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于获取可能发生的详细错误信息。</span>
		</p>
<img src ="http://www.cppblog.com/ivenher/aggbug/4917.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-04-02 22:51 <a href="http://www.cppblog.com/ivenher/articles/4917.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Sybase 数据源建立</title><link>http://www.cppblog.com/ivenher/articles/1011.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Wed, 09 Nov 2005 08:19:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1011.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1011.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1011.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1011.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1011.html</trackback:ping><description><![CDATA[1、打开Sybase ASE OLE DB Congiguraton Manager.<BR>新建一个datasource取名ssa<BR><IMG height=503 alt="sybase datasource.JPG" src="http://www.cppblog.com/images/cppblog_com/ivenher/sybase%20datasource.JPG" width=512 border=0><BR><BR>server name为机器名字。database name 为数据库名。其他默认。<BR>然后点 Test Connect测试是否成功。<BR><IMG height=384 alt="connect test.JPG" src="http://www.cppblog.com/images/cppblog_com/ivenher/connect%20test.JPG" width=512 border=0><BR><BR>提示成功。<img src ="http://www.cppblog.com/ivenher/aggbug/1011.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-09 16:19 <a href="http://www.cppblog.com/ivenher/articles/1011.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ALTER TABLE </title><link>http://www.cppblog.com/ivenher/articles/829.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Mon, 24 Oct 2005 09:22:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/829.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/829.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/829.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/829.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/829.html</trackback:ping><description><![CDATA[<TABLE cellSpacing=0 cellPadding=0 width=680 border=0>
<TBODY>
<TR>
<TD vAlign=top height=63>
<TABLE class=zhi12 cellSpacing=0 cellPadding=0 width="96%" align=center border=0>
<TBODY>
<TR>
<TD style="FONT-WEIGHT: normal; FONT-SIZE: 16pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" height=49>
<DIV align=center><B><FONT color=#003399>ALTER TABLE </FONT></B></DIV></TD></TR><INPUT type=hidden value=http://www.chinaitlab.com/www/news/article_show.asp?id=8728 name=location1>
<SCRIPT language=javascript>
	 document.all.location1.value=location.href
</SCRIPT>

<SCRIPT language=JavaScript>
function AddPortal (FpanelID)
{
	var exe ="Tencent://AddPortal/?Menu=Yes&PanelID="+FpanelID; 		
	location.href=exe;				
}
</SCRIPT>
 
<TR>
<TD bgColor=#e2ffff height=28></TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD vAlign=top>
<TABLE class=zhi14 height=38 cellSpacing=0 cellPadding=0 width=648 align=center border=0>
<TBODY>
<TR>
<TD width=648 height=20>&nbsp;</TD></TR>
<TR>
<TD style="WORD-BREAK: break-all" vAlign=top width=648 height=18><BR>　　通过更改、添加、除去列和约束，或者通过启用或禁用约束和触发器来更改表的定义。<BR>　　<BR>　　语法<BR>　　ALTER TABLE table <BR>　　{ [ ALTER COLUMN column_name <BR>　　 { new_data_type [ ( precision [ , scale ] ) ]<BR>　　 [ COLLATE &lt; collation_name &gt; ]<BR>　　 [ NULL | NOT NULL ]<BR>　　 | {ADD | DROP } ROWGUIDCOL }<BR>　　 ] <BR>　　 | ADD<BR>　　 { [ &lt; column_definition &gt; ]<BR>　　 | column_name AS computed_column_expression<BR>　　 } [ ,...n ]<BR>　　 | [ WITH CHECK | WITH NOCHECK ] ADD<BR>　　 { &lt; table_constraint &gt; } [ ,...n ] <BR>　　 | DROP<BR>　　 { [ CONSTRAINT ] constraint_name <BR>　　 | COLUMN column } [ ,...n ] <BR>　　 | { CHECK | NOCHECK } CONSTRAINT<BR>　　 { ALL | constraint_name [ ,...n ] }<BR>　　 | { ENABLE | DISABLE } TRIGGER<BR>　　 { ALL | trigger_name [ ,...n ] } <BR>　　}<BR>　　<BR>　　&lt; column_definition &gt; ::=<BR>　　 { column_name data_type }<BR>　　 [ [ DEFAULT constant_expression ] [ WITH VALUES ]<BR>　　 | [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ]<BR>　　 ] <BR>　　 [ ROWGUIDCOL ]<BR>　　 [ COLLATE &lt; collation_name &gt; ]<BR>　　 [ &lt; column_constraint &gt; ] [ ...n ]<BR>　　<BR>　　&lt; column_constraint &gt; ::=<BR>　　 [ CONSTRAINT constraint_name ]<BR>　　 { [ NULL | NOT NULL ]<BR>　　 | [ { PRIMARY KEY | UNIQUE }<BR>　　 [ CLUSTERED | NONCLUSTERED ]<BR>　　 [ WITH FILLFACTOR = fillfactor ]<BR>　　 [ ON { filegroup | DEFAULT } ]<BR>　　 ] <BR>　　 | [ [ FOREIGN KEY ]<BR>　　 REFERENCES ref_table [ ( ref_column ) ]<BR>　　 [ ON DELETE { CASCADE | NO ACTION } ]<BR>　　 [ ON UPDATE { CASCADE | NO ACTION } ]<BR>　　 [ NOT FOR REPLICATION ]<BR>　　 ] <BR>　　 | CHECK [ NOT FOR REPLICATION ]<BR>　　 ( logical_expression ) <BR>　　 }<BR>　　<BR>　　&lt; table_constraint &gt; ::=<BR>　　 [ CONSTRAINT constraint_name ]<BR>　　 { [ { PRIMARY KEY | UNIQUE }<BR>　　 [ CLUSTERED | NONCLUSTERED ]<BR>　　 { ( column [ ,...n ] ) } <BR>　　 [ WITH FILLFACTOR = fillfactor ]<BR>　　 [ ON { filegroup | DEFAULT } ]<BR>　　 ] <BR>　　 | FOREIGN KEY<BR>　　 [ ( column [ ,...n ] ) ]<BR>　　 REFERENCES ref_table [ ( ref_column [ ,...n ] ) ]<BR>　　 [ ON DELETE { CASCADE | NO ACTION } ]<BR>　　 [ ON UPDATE { CASCADE | NO ACTION } ]<BR>　　 [ NOT FOR REPLICATION ]<BR>　　 | DEFAULT constant_expression<BR>　　 [ FOR column ] [ WITH VALUES ]<BR>　　 | CHECK [ NOT FOR REPLICATION ]<BR>　　 ( search_conditions ) <BR>　　 }<BR>　　<BR>　　参数<BR>　　table<BR>　　<BR>　　是要更改的表的名称。如果表不在当前数据库中或者不属于当前用户所拥有，可以显式指定数据库和所有者。<BR>　　<BR>　　ALTER COLUMN<BR>　　<BR>　　指定要更改给定列。如果兼容级别是 65 或小于 65，将不允许使用 ALTER COLUMN。<BR>　　要更改的列不能是： <BR>　　<BR>　　数据类型为 text、image、ntext 或 timestamp 的列。<BR>　　<BR>　　<BR>　　表的 ROWGUIDCOL 列。<BR>　　<BR>　　<BR>　　计算列或用于计算列中的列。<BR>　　<BR>　　<BR>　　被复制列。<BR>　　<BR>　　<BR>　　用在索引中的列，除非该列数据类型是 varchar、nvarchar 或 varbinary，数据类型没有更改，而且新列大小等于或者大于旧列大小。<BR>　　<BR>　　<BR>　　用在由 CREATE STATISTICS 语句创建的统计中的列。首先用 DROP STATISTICS 语句删除统计。由查询优化器自动生成的统计会由 ALTER COLUMN 自动除去。<BR>　　<BR>　　<BR>　　用在 PRIMARY KEY 或 [FOREIGN KEY] REFERENCES 约束中的列。<BR>　　<BR>　　<BR>　　用在 CHECK 或 UNIQUE 约束中的列，除非用在 CHECK 或 UNIQUE 约束中的可变长度列的长度允许更改。<BR>　　<BR>　　<BR>　　有相关联的默认值的列，除非在不更改数据类型的情况下允许更改列的长度、精度或小数位数。 <BR>　　有些数据类型的更改可能导致数据的更改。例如，将数据类型为 nchar 或 nvarchar 的列更改为 char 或 varchar 类型，将导致扩展字符的转换。降低列的精度和小数位数可能导致数据截断。<BR>　　column_name<BR>　　<BR>　　是要更改、添加或除去的列的名称。对于新列，如果数据类型为 timestamp，column_name 可以省略。对于 timestamp 数据类型的列，如果未指定 column_name，将使用名称 timestamp。<BR>　　<BR>　　new_data_type<BR>　　<BR>　　是要更改的列的新数据类型。要更改的列的 new_data_type 应符合下列准则： <BR>　　<BR>　　原来的数据类型必须可以隐式转换为新数据类型。<BR>　　<BR>　　<BR>　　new_data_type 类型不能为 timestamp。<BR>　　<BR>　　<BR>　　对 ALTER COLUMN，ANSI 空默认值始终打开；如果没有指定，列将可为空。<BR>　　<BR>　　<BR>　　对 ALTER COLUMN，ANSI 填充始终打开。<BR>　　<BR>　　<BR>　　如果要更改的列是标识列，new_data_type 必须是支持标识属性的数据类型。<BR>　　<BR>　　<BR>　　将忽略 SET ARITHABORT 的当前设置。ALTER TABLE 语句的行为如同 ARITHABORT 选项为 ON 时一样。 <BR>　　precision<BR>　　<BR>　　是指定数据类型的精度。<BR>　　scale<BR>　　<BR>　　是指定数据类型的小数位数。<BR>　　COLLATE &lt; collation_name &gt;<BR>　　<BR>　　为更改列指定新的排序规则。排序规则名称既可以是 Windows 排序规则名称，也可以是 SQL 排序规则名称。<BR>　　COLLATE 子句只能用于更改数据类型为 char、varchar、text、nchar、nvarchar 和 ntext 的列的排序规则。如果未指定，则此列采用数据库的默认排序规则。<BR>　　<BR>　　若满足下列条件，则 ALTER COLUMN 不能更改排序规则： <BR>　　<BR>　　检查约束、外键约束或计算列引用了更改列。 <BR>　　<BR>　　<BR>　　在此列上创建了索引、统计或全文索引。更改列的排序规则时，该列上自动创建的统计将除去。<BR>　　<BR>　　<BR>　　SCHEMABOUND 视图或函数引用了此列。 <BR>　　NULL | NOT NULL<BR>　　<BR>　　指定该列是否可接受空值。不允许空值的列只有在指定了默认值的情况下，才能用 ALTER TABLE 语句向表中添加。添加到表中的新列要么允许空值，要么必须指定默认值。<BR>　　<BR>　　如果新列允许空值，而且没有指定默认值，那么新列在表中每一行都包含空值。如果新列允许空值并且指定了新列的默认值，那么可以使用 WITH VALUES 选项在表中所有现有行的新列中存储默认值。<BR>　　<BR>　　如果新列不允许空值，那么新列必须具有 DEFAULT 定义，而且新列的所有现有行中将自动装载该默认值。<BR>　　<BR>　　可在 ALTER COLUMN 语句中指定 NULL 以使 NOT NULL 列允许空值，但 PRIMARY KEY 约束中的列除外。只有列中不包含空值时，ALTER COLUMN 中才可指定 NOT NULL。必须将空值更新为非空值后，才允许执行 ALTER COLUMN NOT NULL 语句，比如：<BR>　　<BR>　　UPDATE MyTable SET NullCol = N'some_value' WHERE NullCol IS NULL<BR>　　<BR>　　ALTER TABLE MyTable ALTER COLUMN NullCOl NVARCHAR(20) NOT NULL<BR>　　<BR>　　如果 ALTER COLUMN 中指定了 NULL 或 NOT NULL，那么必须同时指定 new_data_type [(precision [, scale ])]。如果不更改数据类型、精度和小数位数，请指定列的这些值的当前值。<BR>　　<BR>　　[ {ADD | DROP} ROWGUIDCOL ]<BR>　　<BR>　　指定在指定列上添加或除去 ROWGUIDCOL 属性。ROWGUIDCOL 是一个关键字，表示列是行全局唯一标识符列。对于每个表只能指派一个 uniqueidentifier 列作为 ROWGUIDCOL 列。ROWGUIDCOL 属性只能指派给 uniqueidentifier 列。<BR>　　<BR>　　ROWGUIDCOL 属性并不强制列中所存储值的唯一性。该属性也不会为插入到表中的新行自动生成值。若要为每列生成唯一值，那么或者在 INSERT 语句中使用 NEWID 函数，或者将 NEWID 函数指定为该列的默认值。<BR>　　<BR>　　ADD<BR>　　<BR>　　指定要添加一个或多个列定义、计算列定义或者表约束。<BR>　　<BR>　　computed_column_expression<BR>　　<BR>　　是一个定义计算列的值的表达式。计算列是并不物理地存储在表中的虚拟列，该列用表达式计算得出，该表达式使用同一表中的其它列。例如，计算列的定义可以是：cost AS price * qty。表达式可以是非计算列的列名、常量、函数、变量，也可以是用一个或多个运算符连接的上述元素的任意组合。表达式不能为子查询。<BR>　　<BR>　　计算列可用于选择列表、WHERE 子句、ORDER BY 字句或其它任何可以使用常规表达式的位置，但下列情况除外： <BR>　　<BR>　　计算列不能用作 DEFAULT 或 FOREIGN KEY 约束定义，也不能与 NOT NULL 约束定义一起使用。但是，如果计算列由具有确定性的表达式定义，并且索引列中允许计算结果的数据类型，则可将该列用作索引中的键列，或用作 PRIMARY KEY 或 UNIQUE 约束的一部分。 <BR>　　例如，如果表中有整数列 a 和 b，那么计算列 a+b 上可建立索引，而计算列 a+DATEPART(dd, GETDATE()) 上则不能，因为该值将在后续调用时更改。<BR>　　<BR>　　计算列不能作为 INSERT 或 UPDATE 语句的目标。 <BR>　　<BR>　　<BR>　　说明 由于表中计算列所用列中的各行可能有不同的值，所以计算列的每一行可能有不同的值。<BR>　　<BR>　　n<BR>　　<BR>　　是表示前面的项可重复 n 次的占位符。<BR>　　<BR>　　WITH CHECK | WITH NOCHECK<BR>　　<BR>　　指定表中的数据是否用新添加的或重新启用的 FOREIGN KEY 或 CHECK 约束进行验证。如果没有指定，对于新约束，假定为 WITH CHECK，对于重新启用的约束，假定为 WITH NOCHECK。<BR>　　<BR>　　WITH CHECK 和 WITH NOCHECK 子句不能用于 PRIMARY KEY 和 UNIQUE 约束。<BR>　　<BR>　　如果不想用新 CHECK 或 FOREIGN KEY 约束对现有数据进行验证，请用 WITH NOCHECK，除了个别情况，不建议这样使用。新约束将在以后的所有更新中生效。任何在添加约束时由 WITH NOCHECK 抑制的约束违规都可能导致将来的更新失败，如果这些更新操作要更新的行中包含不符合约束条件的数据。<BR>　　<BR>　　查询优化器不考虑用 WITH NOCHECK 定义的约束。将忽略这些约束，直到使用 ALTER TABLE table CHECK CONSTRAINT ALL语句重新启用这些约束为止。<BR>　　<BR>　　DROP { [CONSTRAINT] constraint_name | COLUMN column_name }<BR>　　<BR>　　指定从表中删除 constraint_name 或者 column_name。如果兼容级别小于或等于 65，将不允许 DROP COLUMN。可以列出多个列或约束。下面的列不能除去： <BR>　　<BR>　　被复制列。<BR>　　<BR>　　<BR>　　用在索引中的列。<BR>　　<BR>　　<BR>　　用在 CHECK、FOREIGN KEY、UNIQUE 或 PRIMARY KEY 约束中的列。<BR>　　<BR>　　<BR>　　有相关联的默认值（由 DEFAULT 关键字定义）的列，或绑定到默认对象的列。<BR>　　<BR>　　<BR>　　绑定到规则的列。 <BR>　　{ CHECK | NOCHECK} CONSTRAINT<BR>　　<BR>　　指定启用或禁用 constraint_name。如果禁用，将来插入或更新该列时将不用该约束条件进行验证。此选项只能与 FOREIGN KEY 和 CHECK 约束一起使用。 <BR>　　<BR>　　ALL <BR>　　指定使用 NOCHECK 选项禁用所有约束，或者使用 CHECK 选项启用所有约束。 <BR>　　{ENABLE | DISABLE} TRIGGER<BR>　　<BR>　　指定启用或禁用 trigger_name。当一个触发器被禁用时，它对表的定义依然存在；然而，当在表上执行 INSERT、UPDATE 或 DELETE 语句时，触发器中的操作将不执行，除非重新启用该触发器。 <BR>　　<BR>　　ALL <BR>　　指定启用或禁用表中所有的触发器。<BR>　　<BR>　　trigger_name <BR>　　指定要启用或禁用的触发器名称。 <BR>　　column_name data_type<BR>　　<BR>　　新列的数据类型。data_type 可以是任何 Microsoft® SQL Server™ 数据类型或用户定义数据类型。<BR>　　<BR>　　DEFAULT<BR>　　<BR>　　是指定列默认值的关键字。DEFAULT 定义可用于为表中现有行的新列提供值。DEFAULT 定义不能添加到具有 timestamp 数据类型、IDENTITY 属性、现有 DEFAULT 定义或绑定默认值的列。如果列已有默认值，必须除去旧默认值后才能添加新默认值。为同 SQL Server 先前版本保持兼容性，向 DEFAULT 赋予约束名是可能的。<BR>　　<BR>　　IDENTITY<BR>　　<BR>　　指定新列是标识列。在表中添加新行时，SQL Server 为列提供一个唯一的增量值。标识列通常与 PRIMARY KEY 约束一起用作表的唯一行标识符。IDENTITY 属性可赋予 tinyint、smallint、int、bigint、decimal(p,0) 或者 numeric(p,0) 列。对于每个表只能创建一个标识列。DEFAULT 关键字和绑定默认值不能用于标识列。要么种子和增量都同时指定，要么都不指定。如果二者都未指定，则取默认值 (1,1)。 <BR>　　<BR>　　Seed <BR>　　是用于表中所装载的第一行的值。<BR>　　<BR>　　Increment <BR>　　是添加到前一行的标识值的增量值。 <BR>　　NOT FOR REPLICATION<BR>　　<BR>　　指定当复制登录（如 sqlrepl）向表中插入数据时，不强制 IDENTITY 属性。也可对约束指定 NOT FOR REPLICATION。当复制登录向表中插入数据时，不检查约束条件。<BR>　　<BR>　　CONSTRAINT<BR>　　<BR>　　指定 PRIMARY KEY、UNIQUE、FOREIGN KEY 或 CHECK 约束的开始，或者指定 DEFAULT 定义的开始。<BR>　　<BR>　　constrain_name<BR>　　<BR>　　是新约束。约束的名称必须符合标识符规则，但其名称的首字符不能为 #。如果没有提供 constraint_name，约束使用系统生成的名称。<BR>　　<BR>　　PRIMARY KEY<BR>　　<BR>　　是通过唯一索引对给定的一列或多列强制实体完整性的约束。对每个表只能创建一个 PRIMARY KEY 约束。<BR>　　<BR>　　UNIQUE<BR>　　<BR>　　是通过唯一索引为给定的一列或多列提供实体完整性的约束。<BR>　　<BR>　　CLUSTERED | NONCLUSTERED<BR>　　<BR>　　指定为 PRIMARY KEY 或 UNIQUE 约束创建聚集或非聚集索引。PRIMARY KEY 约束默认为 CLUSTERED；UNIQUE 约束默认为 NONCLUSTERED。<BR>　　<BR>　　如果表中已存在聚集约束或索引，那么在 ALTER TABLE 中就不能指定 CLUSTERED。如果表中已存在聚集约束或索引，PRIMARY KEY 约束默认为 NONCLUSTERED。<BR>　　<BR>　　WITH FILLFACTOR = fillfactor<BR>　　<BR>　　指定 SQL Server 存储索引数据时每个索引页的充满程度。用户指定的 fillfactor 取值范围从 1 到 100。如果没有指定，那么默认值为 0。创建索引时，fillfactor 值越低，不必分配新空间即可添加的新索引条目的可用空间就越多。<BR>　　<BR>　　ON {filegroup | DEFAULT}<BR>　　<BR>　　指定为约束创建的索引的存储位置。如果指定了 filegroup，索引将在该文件组内创建。如果指定了 DEFAULT，索引将在默认文件组内创建。如果未指定 ON，索引将在表所在的文件组内创建。当为 PRIMARY KEY 或 UNIQUE 约束添加聚集索引时，如果指定了 ON，那么创建聚集索引时整个表都将移到指定的文件组中。<BR>　　<BR>　　在这里，DEFAULT 不是一个关键字。DEFAULT 是默认文件组的标识符，必须用符号界定，如 ON "DEFAULT" 或 ON [DEFAULT]。<BR>　　<BR>　　FOREIGN KEY...REFERENCES<BR>　　<BR>　　是为列中数据提供引用完整性的约束。FOREIGN KEY 约束要求列中的每个值在被引用表的指定列中都存在。<BR>　　<BR>　　ref_table<BR>　　<BR>　　是 FOREIGN KEY 约束所引用的表。<BR>　　<BR>　　ref_column<BR>　　<BR>　　是新 FOREIGN KEY 约束所引用的一列或多列（置于括号中）。<BR>　　<BR>　　ON DELETE {CASCADE | NO ACTION}<BR>　　<BR>　　指定当表中被更改的行具有引用关系，并且该行所引用的行从父表中删除时，要对被更改行采取的操作。默认设置为 NO ACTION。 <BR>　　<BR>　　如果指定 CASCADE，则从父表中删除被引用行时，也将从引用表中删除引用行。如果指定 NO ACTION，SQL Server 将产生一个错误并回滚父表中的行删除操作。<BR>　　<BR>　　如果表中已存在 ON DELETE 的 INSTEAD OF 触发器，那么就不能定义 ON DELETE 的CASCADE 操作。<BR>　　<BR>　　例如，在 Northwind 数据库中，Orders 表和 Customers 表之间有引用关系。Orders.CustomerID 外键引用 Customers.CustomerID 主键。<BR>　　<BR>　　如果对 Customers 表的某行执行 DELETE 语句，并且为 Orders.CustomerID 指定 ON DELETE CASCADE 操作，则 SQL Server 将在 Orders 表中检查是否有与被删除的行相关的一行或多行。如果存在相关行，那么 Orders 表中的相关行将随 Customers 表中的被引用行一同删除。<BR>　　<BR>　　反之，如果指定 NO ACTION，若在 Orders 表中至少有一行引用 Customers 表中要删除的行，则 SQL Server 将产生一个错误并回滚 Customers 表中的删除操作。<BR>　　<BR>　　ON UPDATE {CASCADE | NO ACTION}<BR>　　<BR>　　指定当表中被更改的行具有引用关系，并且该行所引用的行在父表中更新时，要对被更改行采取的操作。默认设置为 NO ACTION。 <BR>　　<BR>　　如果指定 CASCADE，则在父表中更新被引用行时，也将在引用表中更新引用行。如果指定 NO ACTION，SQL Server 将产生一个错误并回滚父表中的行更新操作。<BR>　　<BR>　　如果表中已存在 ON DELETE 的 INSTEAD OF 触发器，那么就不能定义 ON DELETE 的CASCADE 操作。<BR>　　<BR>　　例如，在 Northwind 数据库中，Orders 表和 Customers 表之间有引用关系。Orders.CustomerID 外键引用 Customers.CustomerID 主键。<BR>　　<BR>　　如果对 Customers 表的某行执行 UPDATE 语句，并且为 Orders.CustomerID 指定 ON UPDATE CASCADE 操作，则 SQL Server 将在 Orders 表中检查是否有与被更新行相关的一行或多行。如果存在相关行，那么 Orders 表中的相关行将随 Customers 表中的被引用行一同更新。<BR>　　<BR>　　反之，如果指定了 NO ACTION，若在 Orders 表中至少存在一行引用 Customers 表中要更新的行，那么 SQL Server 将引发一个错误并回滚 Customers 表中的更新操作。<BR>　　<BR>　　[ASC | DESC]<BR>　　<BR>　　指定加入到表约束中的一列或多列的排序次序。默认设置为 ASC。<BR>　　<BR>　　WITH VALUES<BR>　　<BR>　　指定在添加到现有行的新列中存储 DEFAULT constant_expression 中所给定的值。只有在 ADD 列子句中指定了 DEFAULT 的情况下，才能使用 WITH VALUES。如果要添加的列允许空值且指定了 WITH VALUES，那么将在现有行的新列中存储默认值。如果没有指定 WITH VALUES 且列允许空值，那么将在现有行的新列中存储 NULL 值。如果新列不允许空值，那么不论是否指定 WITH VALUES，都将在现有行的新列中存储默认值。<BR>　　<BR>　　column[,...n]<BR>　　<BR>　　是新约束所用的一列或多列（置于括号中）。<BR>　　<BR>　　constant_expression<BR>　　<BR>　　是用作列的默认值的字面值、NULL 或者系统函数。<BR>　　<BR>　　FOR column<BR>　　<BR>　　指定与表级 DEFAULT 定义相关联的列。<BR>　　<BR>　　CHECK<BR>　　<BR>　　是通过限制可输入到一列或多列中的可能值强制域完整性的约束。<BR>　　<BR>　　logical_expression<BR>　　<BR>　　是用于 CHECK 约束的返回 TRUE 或 FALSE 的逻辑表达式。用于 CHECK 约束的 Logical_expression 不能引用其它表，但可引用同一表中同一行的其它列。<BR>　　<BR>　　注释<BR>　　若要添加新数据行，请使用 INSERT 语句。若要删除数据行，请使用 DELETE 或 TRUNCATE TABLE 语句。若要更改现有行中的值，请使用 UPDATE 语句。<BR>　　<BR>　　ALTER TABLE 语句指定的更改将立即实现。如果这些更改需要修改表中的行，ALTER TABLE 将更新这些行。ALTER TABLE 将获取表上的架构修改锁，以确保在更改期间其它连接不能引用该表（甚至不能引用其元数据）。对表进行的更改将记录于日志中，并且可以完全恢复。影响非常大的表中所有行的更改，比如除去一列或者用默认值添加 NOT NULL 列，可能需要较长时间才能完成，并会生成大量日志记录。如同影响大量行的 INSERT、UPDATE 或者 DELETE 语句一样，这一类 ALTER TABLE 语句也应小心使用。<BR>　　<BR>　　如果过程高速缓存中存在引用该表的执行计划，ALTER TABLE 会将这些执行计划标记为下次执行时重新编译。<BR>　　<BR>　　如果 ALTER TABLE 语句指定更改其它表所引用的列值，那么根据引用表中 ON UPDATE 或者 ON DELETE 所指定的操作，将发生以下两个事件之一。 <BR>　　<BR>　　如果在引用表中没有指定值或指定了 NO ACTION（默认值），那么 ALTER TABLE 语句导致的更改父表中被引用列的操作将回滚，并且 SQL Server 将引发一个错误。<BR>　　<BR>　　<BR>　　如果在引用表中指定了 CASCADE，那么由 ALTER TABLE 语句导致的对父表的更改将应用于父表及其相关表。 <BR>　　添加 sql_variant 列的 ALTER TABLE 语句会生成下列警告：<BR>　　<BR>　　The total row size (xx) for table 'yy' exceeds the maximum number of bytes per row (8060). Rows that exceed the maximum number of bytes will not be added.<BR>　　因为 sql_variant 的最大长度为 8016 个字节，所以产生该警告。当某 sql_variant 列所含值接近最大长度时，即会超过行长度的最大字节限制。<BR>　　<BR>　　ALTER TABLE 语句对具有架构绑定视图的表执行时，所受限制与当前在更改具有简单索引的表时所受的限制相同。添加列是允许的。但是，不允许删除或更改参与架构绑定视图的表中的列。如果 ALTER TABLE 语句要求更改用在架构绑定视图中的列，更改操作将失败，并且 SQL Server 将引发一条错误信息。有关 SCHEMABINDING 和索引视图的更多信息，请参见 CREATE VIEW。<BR>　　<BR>　　创建引用表的架构绑定视图不会影响在基表上添加或删除触发器。<BR>　　<BR>　　当除去约束时，作为约束的一部分而创建的索引也将除去。而通过 CREATE INDEX 创建的索引必须使用 DROP INDEX 语句来除去。DBCC DBREINDEX 语句可用来重建约束定义的索引部分；而不必使用 ALTER TABLE 先除去再重新添加约束。<BR>　　<BR>　　必须删除所有基于列的索引和约束后，才能删除列。<BR>　　<BR>　　添加约束时，所有现有数据都要进行约束违规验证。如果发生违规，ALTER TABLE 语句将失败并返回一个错误。<BR>　　<BR>　　当在现有列上添加新 PRIMARY KEY 或 UNIQUE 约束时，该列中的数据必须唯一。如果存在重复值，ALTER TABLE 语句将失败。当添加 PRIMARY KEY 或 UNIQUE 约束时，WITH NOCHECK 选项不起作用。<BR>　　<BR>　　每个 PRIMARY KEY 和 UNIQUE 约束都将生成一个索引。UNIQUE 和 PRIMARY KEY 约束的数目不能导致表上非聚集索引的数目大于 249，聚集索引的数目大于 1。<BR>　　<BR>　　如果要添加的列的数据类型为 uniqueidentifier，那么该列可以使用 NEWID() 函数作为默认值，以向表中现有行的新列提供唯一标识符值。<BR>　　<BR>　　SQL Server 在列定义中并不强制以特定的顺序指定 DEFAULT、IDENTITY、ROWGUIDCOL 或列约束。<BR>　　<BR>　　ALTER TABLE 的 ALTER COLUMN 子句并不会在列上绑定或取消绑定任何规则。必须分别使用 sp_bindrule 或 sp_unbindrule 来绑定或取消绑定规则。<BR>　　<BR>　　可将规则绑定到用户定义数据类型。然后 CREATE TABLE 将自动在以该用户定义数据类型定义的列上绑定该规则。当用 ALTER COLUMN 更改列数据类型时，并不会取消绑定这些规则。原用户定义数据类型上的规则仍然绑定在该列上。在 ALTER COLUMN 更改了列的数据类型之后，随后执行的任何从该用户定义数据类型上取消绑定规则的 sp_unbindrule 都不会导致从更改了数据类型的列上取消绑定该规则。如果 ALTER COLUMN 将列的数据类型更改为绑定了规则的用户定义数据类型，那么绑定到新数据类型的规则不会绑定到该列。<BR>　　<BR>　　权限<BR>　　ALTER TABLE 权限默认授予表的所有者、sysadmin 固定服务器角色成员、db_owner 和 db_ddladmin 固定数据库角色成员且不可转让。<BR>　　<BR>　　示例<BR>　　A. 更改表以添加新列<BR>　　下例添加一个允许空值的列，而且没有通过 DEFAULT 定义提供值。各行的新列中的值将为 NULL。<BR>　　<BR>　　CREATE TABLE doc_exa ( column_a INT) <BR>　　GO<BR>　　ALTER TABLE doc_exa ADD column_b VARCHAR(20) NULL<BR>　　GO<BR>　　EXEC sp_help doc_exa<BR>　　GO<BR>　　DROP TABLE doc_exa<BR>　　GO<BR>　　<BR>　　B. 更改表以除去列<BR>　　下例修改表以删除一列。<BR>　　<BR>　　CREATE TABLE doc_exb ( column_a INT, column_b VARCHAR(20) NULL) <BR>　　GO<BR>　　ALTER TABLE doc_exb DROP COLUMN column_b<BR>　　GO<BR>　　EXEC sp_help doc_exb<BR>　　GO<BR>　　DROP TABLE doc_exb<BR>　　GO<BR>　　<BR>　　C. 更改表以添加具有约束的列<BR>　　下例向表中添加具有 UNIQUE 约束的新列。 <BR>　　<BR>　　CREATE TABLE doc_exc ( column_a INT) <BR>　　GO<BR>　　ALTER TABLE doc_exc ADD column_b VARCHAR(20) NULL <BR>　　 CONSTRAINT exb_unique UNIQUE<BR>　　GO<BR>　　EXEC sp_help doc_exc<BR>　　GO<BR>　　DROP TABLE doc_exc<BR>　　GO<BR>　　<BR>　　D. 更改表以添加未验证的约束<BR>　　下例向表中的现有列上添加约束。该列中存在一个违反约束的值；因此，利用 WITH NOCHECK 来防止对现有行验证约束，从而允许该约束的添加。<BR>　　<BR>　　CREATE TABLE doc_exd ( column_a INT) <BR>　　GO<BR>　　INSERT INTO doc_exd VALUES (-1)<BR>　　GO<BR>　　ALTER TABLE doc_exd WITH NOCHECK <BR>　　ADD CONSTRAINT exd_check CHECK (column_a &gt; 1)<BR>　　GO<BR>　　EXEC sp_help doc_exd<BR>　　GO<BR>　　DROP TABLE doc_exd<BR>　　GO<BR>　　<BR>　　E. 更改表以添加多个带有约束的列<BR>　　下例向表中添加多个带有约束的新列。第一个新列具有 IDENTITY 属性；表中每一行的标识列都将具有递增的新值。<BR>　　<BR>　　CREATE TABLE doc_exe ( column_a INT CONSTRAINT column_a_un UNIQUE) <BR>　　GO<BR>　　ALTER TABLE doc_exe ADD <BR>　　<BR>　　/* Add a PRIMARY KEY identity column. */ <BR>　　column_b INT IDENTITY<BR>　　CONSTRAINT column_b_pk PRIMARY KEY, <BR>　　<BR>　　/* Add a column referencing another column in the same table. */ <BR>　　column_c INT NULL <BR>　　CONSTRAINT column_c_fk <BR>　　REFERENCES doc_exe(column_a),<BR>　　<BR>　　/* Add a column with a constraint to enforce that */ <BR>　　/* nonnull data is in a valid phone number format. */<BR>　　column_d VARCHAR(16) NULL <BR>　　CONSTRAINT column_d_chk<BR>　　CHECK <BR>　　(column_d IS NULL OR <BR>　　column_d LIKE "[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]" OR<BR>　　column_d LIKE<BR>　　"([0-9][0-9][0-9]) [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]"),<BR>　　<BR>　　/* Add a nonnull column with a default. */ <BR>　　column_e DECIMAL(3,3)<BR>　　CONSTRAINT column_e_default<BR>　　DEFAULT .081<BR>　　GO<BR>　　EXEC sp_help doc_exe<BR>　　GO<BR>　　DROP TABLE doc_exe<BR>　　GO<BR>　　<BR>　　F. 添加具有默认值的可为空的列<BR>　　下例添加可为空的、具有 DEFAULT 定义的列，并使用 WITH VALUES 为表中的各现有行提供值。如果没有使用 WITH VALUES，那么每一行的新列中都将具有 NULL 值。<BR>　　<BR>　　ALTER TABLE MyTable <BR>　　ADD AddDate smalldatetime NULL<BR>　　CONSTRAINT AddDateDflt<BR>　　DEFAULT getdate() WITH VALUES<BR>　　<BR>　　G. 禁用并重新启用一个约束<BR>　　下例禁用用于限制可接受的薪水数据的约束。WITH NOCHECK CONSTRAINT 与 ALTER TABLE 一起使用，以禁用该约束并使正常情况下会引起约束违规的插入操作得以执行。WITH CHECK CONSTRAINT 重新启用该约束。<BR>　　<BR>　　CREATE TABLE cnst_example <BR>　　(id INT NOT NULL,<BR>　　 name VARCHAR(10) NOT NULL,<BR>　　 salary MONEY NOT NULL<BR>　　 CONSTRAINT salary_cap CHECK (salary &lt; 100000)<BR>　　)<BR>　　<BR>　　-- Valid inserts<BR>　　INSERT INTO cnst_example VALUES (1,"Joe Brown",65000)<BR>　　INSERT INTO cnst_example VALUES (2,"Mary Smith",75000)<BR>　　<BR>　　-- This insert violates the constraint.<BR>　　INSERT INTO cnst_example VALUES (3,"Pat Jones",105000)<BR>　　<BR>　　-- Disable the constraint and try again.<BR>　　ALTER TABLE cnst_example NOCHECK CONSTRAINT salary_cap<BR>　　INSERT INTO cnst_example VALUES (3,"Pat Jones",105000)<BR>　　<BR>　　-- Reenable the constraint and try another insert, will fail.<BR>　　ALTER TABLE cnst_example CHECK CONSTRAINT salary_cap<BR>　　INSERT INTO cnst_example VALUES (4,"Eric James",110000)<BR>　　<BR>　　H. 禁用并重新启用触发器<BR>　　下例使用 ALTER TABLE 的 DISABLE TRIGGER 选项来禁用触发器，以使正常情况下会违反触发器条件的插入操作得以执行。然后下例使用 ENABLE TRIGGER 重新启用触发器。<BR>　　<BR>　　CREATE TABLE trig_example <BR>　　(id INT, <BR>　　name VARCHAR(10),<BR>　　salary MONEY)<BR>　　go<BR>　　-- Create the trigger.<BR>　　CREATE TRIGGER trig1 ON trig_example FOR INSERT<BR>　　as <BR>　　IF (SELECT COUNT(*) FROM INSERTED<BR>　　WHERE salary &gt; 100000) &gt; 0<BR>　　BEGIN<BR>　　print "TRIG1 Error: you attempted to insert a salary &gt; $100,000"<BR>　　ROLLBACK TRANSACTION<BR>　　END<BR>　　GO<BR>　　-- Attempt an insert that violates the trigger.<BR>　　INSERT INTO trig_example VALUES (1,"Pat Smith",100001)<BR>　　GO<BR>　　-- Disable the trigger.<BR>　　ALTER TABLE trig_example DISABLE TRIGGER trig1<BR>　　GO<BR>　　-- Attempt an insert that would normally violate the trigger<BR>　　INSERT INTO trig_example VALUES (2,"Chuck Jones",100001)<BR>　　GO<BR>　　-- Re-enable the trigger.<BR>　　ALTER TABLE trig_example ENABLE TRIGGER trig1<BR>　　GO<BR>　　-- Attempt an insert that violates the trigger.<BR>　　INSERT INTO trig_example VALUES (3,"Mary Booth",100001)<BR>　　GO<BR>　　<BR></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><img src ="http://www.cppblog.com/ivenher/aggbug/829.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-10-24 17:22 <a href="http://www.cppblog.com/ivenher/articles/829.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>   初学T-SQL笔记之ON[PRIMARY]</title><link>http://www.cppblog.com/ivenher/articles/828.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Mon, 24 Oct 2005 08:57:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/828.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/828.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/828.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/828.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/828.html</trackback:ping><description><![CDATA[<H3>&nbsp;&nbsp; 初学T-SQL笔记之ON[PRIMARY]</H3>
<DIV>
<P>&nbsp;</P>
<P>&nbsp; 这些天什么都没做。年前似乎有忙不完的事，年后了却又有了好逸的毛病。。。。</P>
<P>&nbsp; 今天才开始看学校实验指导的数据库开发实例。以前一直没有时间来看。。。</P>
<P>&nbsp; 创建表的语句中，最后总来一句on[primary]，这是什么意思？</P>
<P>&nbsp; 翻翻联机丛书。在CREATE TABLE的语法下似乎没有找到。硬着头皮看下去，终于明白了一些。</P>
<P>&nbsp; 写出来吧。侯捷老师说，发表是最好的记忆。：）</P>
<P>&nbsp; 在CREATE TABLE的语法中有这样一句可选语法项目：</P>
<P>&nbsp; [ ON { filegroup | DEFAULT } ]</P>
<P>&nbsp; 用来指定存储表的文件组。</P>
<P>&nbsp; 如果指定 filegroup，则表将存储在指定的文件组中。数据库中必须存在该文件组。如果指定 DEFAULT，或者根本未指定 ON 参数，则表存储在默认文件组中。</P>
<P>&nbsp; （DEFAULT 并不是关键字。DEFAULT 是默认文件组的标识符并需对其进行定界，如 ON "DEFAULT"、ON [DEFAULT]。）</P>
<P>&nbsp; ON [PRIMARY]是表示表是建立在主文件组上。PRIMARY表示主文件组。如果没有指定默认文件组，则主文件组是默认文件组，ON [PRIMARY]也可以省略掉了。</P>
<P>&nbsp; 由数据库说开来。Microsoft® SQL Server™ 2000 使用一组操作系统文件映射数据库，也可以说将数据库映射到一组操作系统文件上（看你怎么理解了）。数据库中的所有数据和对象（如表、存储过程、触发器和视图）都存储在操作系统文件（数据库文件）：主要数据文件 、次要数据文件 和事务日志 文件中。</P>
<P>&nbsp; 1.主要数据文件</P>
<P>&nbsp; 该文件包含数据库的启动信息，并用于存储数据。是数据库的起点，指向数据库中文件的其它部分。每个数据库都有一个主要数据文件。主要数据文件的推荐文件扩展名是 .mdf。</P>
<P>&nbsp; 2.次要数据文件</P>
<P>&nbsp; 这些文件含有不能置于主要数据文件中的所有数据即包含除主要数据文件外的所有数据文件。有些数据库可能没有次要数据文件，而有些数据库则有多个次要数据文件。（如果主文件可以包含数据库中的所有数据，那么数据库就不需要次要数据文件。有些数据库可能足够大故需要多个次要数据文件，或使用位于不同磁盘驱动器上的辅助文件将数据扩展到多个磁盘。）次要数据文件的推荐文件扩展名是 .ndf。</P>
<P>&nbsp; 3.事务日志文件</P>
<P>&nbsp; 该数据库的日志信息。每个数据库都必须至少有一个日志文件。日志文件的推荐文件扩展名是 .ldf。</P>
<P>&nbsp; 文件组</P>
<P>&nbsp; 出于分配和管理目的，可以将数据库文件分成不同的文件组。文件组是SQL Server 2000数据文件的一种逻辑管理单位。SQL Server中一个或多个文件的命名集合，它构成分配或用于数据库管理的单个单元。在首次建数据库，或者以后将更多文件添加到数据库时，可以创建文件组。文件组不能独立于数据库文件创建。文件组是在数据库中对文件进行分组的一种管理机制。</P>
<P>&nbsp; 有两种类型的文件组：主要文件组和用户定义文件组。（可以说，数据库由一个主文件组和任意用户定义的文件组组成。）</P>
<P>&nbsp; 1.主文件组 （PRIMARY）</P>
<P>&nbsp; 用户定义文件组 默认文件组 同为文件组的一种类型。</P>
<P>&nbsp; 其包含主要数据文件和任何没有明确指派给其它文件组的其它文件。系统表的所有页均分配在主文件组.</P>
<P>&nbsp; 2.用户定义文件组</P>
<P>&nbsp; 用户定义文件组是在 CREATE DATABASE 或 ALTER DATABASE 语句中，使用 FILEGROUP 关键字或在 SQL Server 企业管理器内的"属性"对话框指定的文件组。</P>
<P>&nbsp; 另：默认文件组 （DEFAULT 文件组）</P>
<P>&nbsp; 文件组的一种类型，其包含在创建时没有指定文件组的所有表和索引的页。在每个数据库中，每次只能有一个文件组是默认文件组。如果没有指定默认文件组，则默认文件组是主文件组。 可用 ALTER DATABASE 语句更改默认文件组。通过更改默认文件组，创建时没有指定文件组的任何对象都被分配到新默认文件组中的数据文件。然而，系统对象和表仍然保留在 PRIMARY 文件组内，而不是新默认文件组。（每个数据库中都有一个文件组作为默认文件组运行。当 SQL Server 给创建时没有为其指定文件组的表或索引分配页时，将从默认文件组中进行分配。一次只能有一个文件组作为默认文件组。db_owner 固定数据库角色成员可以将默认文件组从一个文件组切换到另一个。如果没有指定默认文件组，则主文件组是默认文件组。）</P>
<P>&nbsp; 注:SQL Server 2000 在没有文件组时也能有效地工作，因此许多系统不需要指定用户定义文件组。在这种情况下，所有文件都包含在主文件组中，而且 SQL Server 2000 可以在数据库内的任何位置分配数据。文件组不是在多个驱动器之间分配 I/O 的唯一方法。</P>
<P>&nbsp; 附：</P>
<P>&nbsp; . 为什么要建立文件组</P>
<P>&nbsp; 建立文件组有两个目的。</P>
<P>&nbsp; q 一是可以更好地分配和管理存储空间，通过控制在特定磁盘驱动器上放置数据和索引来提高数据库的性能。</P>
<P>&nbsp; q 二是由于操作系统对物理文件的大小进行了限制，所以当某个磁盘上的数据文件超过单个文件允许的最大值时，可以使用文件组中存</P>
<P>&nbsp; 贮在其他驱动器上的数据文件继续扩充存储空间。</P>
<P>&nbsp; . 数据文件和文件组的使用规则</P>
<P>&nbsp; SQL Server 2000中的数据文件和文件组的使用规则包括：</P>
<P>&nbsp; q 数据文件或文件组不能由一个以上的数据库使用。</P>
<P>&nbsp; q 数据文件只能是一个文件组的成员。</P>
<P>&nbsp; q 数据文件和日志文件不能属于同一文件或文件组。</P>
<P>&nbsp; q 日志文件不能属于任何文件组。</P>
<P>&nbsp; q 只有文件组中的所有数据文件都没有空间了，文件组的文件才会自动增长。</P>
<P>&nbsp; . 文件组的工作原理</P>
<P>&nbsp; 文件组对组内的所有文件都使用按比例填充策略。当将数据写入文件组时，SQL Server 2000根据文件中的可用空间量将一定比例的数据写入文</P>
<P>&nbsp; 件组的每个文件，而不是将所有的数据先写满第一个文件，接着再写入下一个文件。例如，如果文件1有100MB的可用空间，文件2有200MB的可</P>
<P>&nbsp; 用空间，则从文件1中分配一个盘区，从文件2中分配两个盘区，依此类推。这样，两个文件几乎同时填满。</P>
<P>&nbsp; 一旦文件组内的所有文件已满，SQL Server 2000就自动地采用循环方式一次扩展一个文件，以容纳更多的数据（假定数据库设置为自动增长）</P>
<P>&nbsp; 。例如，某个文件组由3个文件组成，它们都设置为自动增长。当文件组中的所有文件的空间用完时，只扩展第一个文件。当第一个文件已满，</P>
<P>&nbsp; 不能将更多的数据写入该文件组时，扩展第二个文件。当第二个文件已满，不能将更多的数据写入该文件组时，扩展第3个文件。如果第3个文</P>
<P>&nbsp; 件已满，不能将更多的数据写入该文件组，那么再次扩展第一个文件，以此类推。</P>
<P>&nbsp; 正时由于文件组的这种特性，允许跨多个磁盘、多个磁盘控制器或 RAID（廉价磁盘冗余阵列）系统创建数据库，可提高数据库性能。例如，如</P>
<P>&nbsp; 果计算机中有4个磁盘，那么可以创建一个由3个数据文件和一个日志文件组成的数据库，每个磁盘上放置一个文件。在对数据进行访问时，四</P>
<P>&nbsp; 个读/写磁头可以同时并行地访问数据，从而加速数据库操作。</P>
<P>&nbsp; 另外，文件和文件组允许数据布局，可以在特定的文件组中创建表。因为特定表的所有输入/输出都可以定向到特定的磁盘，所以性能得以改善</P>
<P>&nbsp; 。例如，可以将最常用的表放在一个文件组中的一个文件中，该文件组位于一个磁盘上；而将数据库中其它的不常访问的表放在另一个文件组</P>
<P>&nbsp; 中的其它文件中，该文件组位于第二个磁盘上。</P>
<P>&nbsp; . 如何使用文件组的建议</P>
<P>&nbsp; q 大多数数据库在只有单个数据文件和单个事务日志文件的情况下可以很好地运行。</P>
<P>&nbsp; q 如果使用多个文件，请为附加文件创建第二个文件组，并将其设置为默认文件组。这样，主文件将仅包含系统表和对象。</P>
<P>&nbsp; q 若要获得最佳性能，请在尽可能多的可用本地物理磁盘上创建文件或文件组，并将争夺空间最激烈的对象置于不同的文件组中。</P>
<P>&nbsp; q 使用文件组以允许将对象放置在特定的物理磁盘上。</P>
<P>&nbsp; q 将在同一联接查询中使用的不同表置于不同的文件组中。由于采用并行磁盘输入/输出对联接数据进行搜索，所以性能将得以改善。</P>
<P>&nbsp; q 将最常访问的表和属于这些表的非聚集索引置于不同的文件组上。如果文件位于不同的物理磁盘上，由于采用并行输入/输出，所以</P>
<P>&nbsp; 性能得以提高。</P>
<P>&nbsp; q 不要将日志文件与其它文件和文件组置于同一物理磁盘上。</P></DIV><img src ="http://www.cppblog.com/ivenher/aggbug/828.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-10-24 16:57 <a href="http://www.cppblog.com/ivenher/articles/828.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>