该文被密码保护。
posted @ 2009-10-10 01:17 JasonLin 阅读(144) 评论(0) 编辑

SQL Server 索引结构及其使用(二)

作者:freedk

一、深入浅出理解索引结构

改善SQL语句

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

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

和执行:

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

  一些人不知道以上两条语句的执行效率是否一样,因为如果简单的从语句先后上看,这两个语句的确是不一样,如果tID是一个聚合索引,那么后一句仅仅从表的10000条以后的记录中查找就行了;而前一句则要先从全表中查找看有几个name=''zhangsan''的,而后再根据限制条件条件tID>10000来提出查询结果。
  事实上,这样的担心是不必要的。SQL SERVER中有一个“查询分析优化器”,它可以计算出where子句中的搜索条件并确定哪个索引能缩小表扫描的搜索空间,也就是说,它能实现自动优化。
  虽然查询优化器可以根据where子句自动的进行查询优化,但大家仍然有必要了解一下“查询优化器”的工作原理,如非这样,有时查询优化器就会不按照您的本意进行快速查询。
  在查询分析阶段,查询优化器查看查询的每个阶段并决定限制需要扫描的数据量是否有用。如果一个阶段可以被用作一个扫描参数(SARG),那么就称之为可优化的,并且可以利用索引快速获得所需数据。
  SARG的定义:用于限制搜索的一个操作,因为它通常是指一个特定的匹配,一个值得范围内的匹配或者两个以上条件的AND连接。形式如下:

列名 操作符 <常数 或 变量>

或

<常数 或 变量> 操作符列名

列名可以出现在操作符的一边,而常数或变量出现在操作符的另一边。如:

Name=’张三’

价格>5000

5000<价格

Name=’张三’ and 价格>5000

  如果一个表达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是SQL SERVER必须对每一行都判断它是否满足WHERE子句中的所有条件。所以一个索引对于不满足SARG形式的表达式来说是无用的。
  介绍完SARG后,我们来总结一下使用SARG以及在实践中遇到的和某些资料上结论不同的经验:

1、Like语句是否属于SARG取决于所使用的通配符的类型

如:name like ‘张%’ ,这就属于SARG

而:name like ‘%张’ ,就不属于SARG。

原因是通配符%在字符串的开通使得索引无法使用。

2、or 会引起全表扫描
  Name=’张三’ and 价格>5000 符号SARG,而:Name=’张三’ or 价格>5000 则不符合SARG。使用or会引起全表扫描。

3、非操作符、函数引起的不满足SARG形式的语句
  不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等,另外还有函数。下面就是几个不满足SARG形式的例子:

ABS(价格)<5000

Name like ‘%三’

有些表达式,如:

WHERE 价格*2>5000

SQL SERVER也会认为是SARG,SQL SERVER会将此式转化为:
WHERE 价格>2500/2

但我们不推荐这样使用,因为有时SQL SERVER不能保证这种转化与原始表达式是完全等价的。

4、IN 的作用相当与OR

语句:

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

和

Select * from table1 where tid=2 or tid=3

是一样的,都会引起全表扫描,如果tid上有索引,其索引也会失效。

5、尽量少用NOT

6、exists 和 in 的执行效率是一样的
  很多资料上都显示说,exists要比in的执行效率要高,同时应尽可能的用not exists来代替not in。但事实上,我试验了一下,发现二者无论是前面带不带not,二者之间的执行效率都是一样的。因为涉及子查询,我们试验这次用SQL SERVER自带的pubs数据库。运行前我们可以把SQL SERVER的statistics I/O状态打开:

(1)select title,price from titles where title_id in (select title_id from sales where qty>30)

该句的执行结果为:

表 ''sales''。扫描计数 18,逻辑读 56 次,物理读 0 次,预读 0 次。
表 ''titles''。扫描计数 1,逻辑读 2 次,物理读 0 次,预读 0 次。

(2)select title,price from titles 
       where exists (select * from sales 
       where sales.title_id=titles.title_id and qty>30)

第二句的执行结果为:

表 ''sales''。扫描计数 18,逻辑读 56 次,物理读 0 次,预读 0 次。
表 ''titles''。扫描计数 1,逻辑读 2 次,物理读 0 次,预读 0 次。

我们从此可以看到用exists和用in的执行效率是一样的。

7、用函数charindex()和前面加通配符%的LIKE执行效率一样
  前面,我们谈到,如果在LIKE前面加上通配符%,那么将会引起全表扫描,所以其执行效率是低下的。但有的资料介绍说,用函数charindex()来代替LIKE速度会有大的提升,经我试验,发现这种说明也是错误的:
 

select gid,title,fariqi,reader from tgongwen 
         where charindex(''刑侦支队'',reader)>0 and fariqi>''2004-5-5''

用时:7秒,另外:扫描计数 4,逻辑读 7155 次,物理读 0 次,预读 0 次。

select gid,title,fariqi,reader from tgongwen 
         where reader like ''%'' + ''刑侦支队'' + ''%'' and fariqi>''2004-5-5''

用时:7秒,另外:扫描计数 4,逻辑读 7155 次,物理读 0 次,预读 0 次。

8、union并不绝对比or的执行效率高
  我们前面已经谈到了在where子句中使用or会引起全表扫描,一般的,我所见过的资料都是推荐这里用union来代替or。事实证明,这种说法对于大部分都是适用的。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
          where fariqi=''2004-9-16'' or gid>9990000

用时:68秒。扫描计数 1,逻辑读 404008 次,物理读 283 次,预读 392163 次。

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

用时:9秒。扫描计数 8,逻辑读 67489 次,物理读 216 次,预读 7499 次。

看来,用union在通常情况下比用or的效率要高的多。

  但经过试验,笔者发现如果or两边的查询列是一样的话,那么用union则反倒和用or的执行速度差很多,虽然这里union扫描的是索引,而or扫描的是全表。
 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen 
          where fariqi=''2004-9-16'' or fariqi=''2004-2-5''

用时:6423毫秒。扫描计数 2,逻辑读 14726 次,物理读 1 次,预读 7176 次。

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''

用时:11640毫秒。扫描计数 8,逻辑读 14806 次,物理读 108 次,预读 1144 次。

9、字段提取要按照“需多少、提多少”的原则,避免“select *”
  我们来做一个试验:

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

用时:4673毫秒

select top 10000 gid,fariqi,title from tgongwen order by gid desc

用时:1376毫秒

select top 10000 gid,fariqi from tgongwen order by gid desc

用时:80毫秒

  由此看来,我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。

10、count(*)不比count(字段)慢
  某些资料上说:用*会统计所有列,显然要比一个世界的列名效率低。这种说法其实是没有根据的。我们来看:

select count(*) from Tgongwen

用时:1500毫秒

select count(gid) from Tgongwen 

用时:1483毫秒

select count(fariqi) from Tgongwen

用时:3140毫秒

select count(title) from Tgongwen

用时:52050毫秒

  从以上可以看出,如果用count(*)和用count(主键)的速度是相当的,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总的速度就越慢。我想,如果用count(*), SQL SERVER可能会自动查找最小字段来汇总的。当然,如果您直接写count(主键)将会来的更直接些。

11、order by按聚集索引列排序效率最高
  我们来看:(gid是主键,fariqi是聚合索引列):

select top 10000 gid,fariqi,reader,title from tgongwen

用时:196 毫秒。 扫描计数 1,逻辑读 289 次,物理读 1 次,预读 1527 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc

用时:4720毫秒。 扫描计数 1,逻辑读 41956 次,物理读 0 次,预读 1287 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

用时:4736毫秒。 扫描计数 1,逻辑读 55350 次,物理读 10 次,预读 775 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc

用时:173毫秒。 扫描计数 1,逻辑读 290 次,物理读 0 次,预读 0 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc

用时:156毫秒。 扫描计数 1,逻辑读 289 次,物理读 0 次,预读 0 次。

  从以上我们可以看出,不排序的速度以及逻辑读次数都是和“order by 聚集索引列” 的速度是相当的,但这些都比“order by 非聚集索引列”的查询速度是快得多的。
  同时,按照某个字段进行排序的时候,无论是正序还是倒序,速度是基本相当的。

12、高效的TOP
  事实上,在查询和提取超大容量的数据集时,影响数据库响应时间的最大因素不是数据查找,而是物理的I/0操作。如:

select top 10 * from (
select top 10000 gid,fariqi,title from tgongwen
where neibuyonghu=''办公室''
order by gid desc) as a
order by gid asc

  这条语句,从理论上讲,整条语句的执行时间应该比子句的执行时间长,但事实相反。因为,子句执行后返回的是10000条记录,而整条语句仅返回10条语句,所以影响数据库响应时间最大的因素是物理I/O操作。而限制物理I/O操作此处的最有效方法之一就是使用TOP关键词了。TOP关键词是SQL SERVER中经过系统优化过的一个用来提取前几条或前几个百分比数据的词。经笔者在实践中的应用,发现TOP确实很好用,效率也很高。但这个词在另外一个大型数据库ORACLE中却没有,这不能说不是一个遗憾,虽然在ORACLE中可以用其他方法(如:rownumber)来解决。在以后的关于“实现千万级数据的分页显示存储过程”的讨论中,我们就将用到TOP这个关键词。
  到此为止,我们上面讨论了如何实现从大容量的数据库中快速地查询出您所需要的数据方法。当然,我们介绍的这些方法都是“软”方法,在实践中,我们还要考虑各种“硬”因素,如:网络性能、服务器的性能、操作系统的性能,甚至网卡、交换机等。

(待续...)

文章引自http://www.vckbase.com/document/viewdoc/?id=1307
posted @ 2009-08-14 14:40 JasonLin 阅读(26) 评论(0) 编辑
 

今天部署个网站出现IIS 500错误,马上google之,发现网上的绝大部分解决方案都是什么同步IIS密码的,一大堆看了就晕倒。接着查看了下错误日志,发现是Distributed Transaction Coordinator服务(MSDTC)有问题,无法正常启动。网上查找,找到一篇类似解决方法。链接:http://www.blogjava.net/lusm/archive/2008/01/03/172542.html(感谢原作者)

过程如下:

首先确定你需要确定的COM+是否配置正确,打开开始>运行>cmd>确定

输入 >regsvr32 asptxn.dll

如果出现一个返回值0x8×××问题,那么,说明COM+出现问题啦!

现象是在打开控制面板>管理工具>组件服务>计算机>我的电脑>"COM+应用程序",时弹出错误对话框,报告8004EOOF错误。

解决方法:这是msdtc服务没有正常启动。

直接 删除注册表 (开始>运行>regedit>确定)中的键:

HKEY_LOCAL_MACHINE "" SYSTEM""CurrentControlSet""Services""MSDTC

HKEY_LOCAL_MACHINE""SOFTWARE""Microsoft""MSDTC

HKEY_CLASSES_ROOT""CID

Step2 停止MSDTC服务:net stop msdtc

Step3 卸载MSDTC服务:msdtc -uninstall

Step4 重新安装MSDTC服务:msdtc -install

然后,你会看到你的com+下多了不少的文件夹(如:分布式事务处理协调器)

 

是不是很兴奋 嘿嘿 还没好呢

 

接着在cmd下运行 这几个命令

> cd %windir%"system32"inetsrv

> rundll32 wamreg.dll, CreateIISPackage

> regsvr32 asptxn.dll

 

找到的另外一篇文章也是MSDTC的问题:金碟K3服务器 中间层无法创建对象 MSDTC错误,3221229584 (0xC0001010)

我按照上面的方法解决问题了,所以这个我并没试过,不知道适合不。做个参考吧。

posted @ 2008-08-07 14:10 JasonLin 阅读(254) 评论(0) 编辑
最近客户提出根据用户姓名的拼音来查找用户的要求,于是很自然的想到了autosuggest控件。autosuggest控件是Anthem.net里的扩展控件,效果相当不错。但是有两点不是很好,我接下来根据自己的要求修改一下这个控件。
1.下拉DIV的界面实在有点难看,黑白搭配不怎么好看。
修改过程如下:
首先将注入式脚本注释掉
    //Page.ClientScript.RegisterClientScriptBlock(typeof(AutoSuggestTextBox), script, script, false);
然后在你用到autosuggest控件的页面联入JS文件:
    <script type="text/javascript" src="AutoSuggestTextBox.js"></script>。
接下来就修改这个JS文件。
修改边框颜色:oDiv.style.borderColor = 'lightblue';
再修改选择时的背景颜色:this.txtArray[selectedElem].style.backgroundColor = '#FFD53B';
实现的效果如图:



2.另外一个不满足的情况是键入的是拼音,而下拉产生的是姓名,autoSuggest会自动选择将结果显示到TextBox上,对输入拼音造成干扰,如上图所示。我接下来要修改源代码让控件不自动选择。
首先加入一个自动选择属性,默认为ture:
        private bool _isAutoSuggest = true;
        public bool IsAutoSuggest
        {
            get { return _isAutoSuggest; }
            set { _isAutoSuggest = value; }
        }
修改要插入客户端的脚本的string,以将IsAutoSuggest值传进去:
acScript.AppendFormat("var {0} = new ASTextBox('{1}','{2}','{4}','{5}','{6}','{7}'); {0}.AllowEditing = '{3}';", jsId, newUid, divId, allowEd, ifrId, minCharTypedBeforeSearch, delayTimeBeforeSearch, IsAutoSuggest);
最后修改AutoSuggestTextBox.js脚本文件:
this.DoAutoSuggestStore = IsAutoSuggest=="True"?true:false;
ASTextBox.prototype.DoAutoSuggestStore = true;
  else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode <= 46) ||
  (iKeyCode >= 112 && iKeyCode <= 123))
  {
    return;
  }
  else
  {
    this.DoAutoSuggest = this.DoAutoSuggestStore;
  }
具体看上传的文件,就不多说了。
OK。在用到该控件的地方加上IsAutoSuggest=“false”就可以实现自动选择的取消。效果如下图:




文件下载:http://files.cnblogs.com/JasonLin/AutoSuggestTextBox.rar

posted @ 2008-05-17 23:55 JasonLin 阅读(423) 评论(0) 编辑
posted @ 2008-05-15 18:06 JasonLin 阅读(53) 评论(0) 编辑

最近项目要求,有个类似用户注册的唯一性检 查的功能,虽然写上了但是交互性不够,用户体验太差。于是开始学习AJAX。刚开始的想法是直接用JSXMLHttpRequest来实现,难度不大。 找了点书再从用AJAX实现注册功能的网站把注册网页源码COPY下来,很简单的封装了下。用的时候发现要改的东西多不是很方便。用ASP.NET AJAX 控件吧Web.config改动实在太大,也不知道会有什么问题,用AJAX.NET又是刚接触AJAX要快速进入有难度。网上看到ASP.NET AJAX(Atlas)Anthem.NET——管中窥豹般小小比较》,于是下载下来使用。正如网上的评价一样:轻量、快速。使用非常简单:

1.将DLL文件添加到Bin目录中,需要的话把控件加到控件栏以后直接拖动添加。
2.设置Web.config:configuration>\ <system.web>\ <pages>\ <controls>中添加<add tagPrefix="anthem" namespace="Anthem" assembly="Anthem"/>,注册Anthem.NET控件,一劳永逸。或者在你需要用的页面中添加注册<%@ Register TagPrefix="anthem" Namespace="Anthem" Assembly="Anthem" %>。

      环境构建完毕就可以开始使用了。
前台代码如下:
   <anthem:TextBox ID="txtTitle" runat="server" Width="250px" TextMode="multiLine" Height="23px" AutoCallBack="true" OnTextChanged="txtTitle_TextChanged"/>
   <anthem:Image  ID="imageIndicator" runat="server" Visible="false"/>
   <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="txtTitle" ErrorMessage="请输入标题!" Display="dynamic" Width="106px"></asp:RequiredFieldValidator>
   <anthem:Label ID="lblMsg" runat="server" Text="" ForeColor="red"/>

后台代码如下:
    protected void txtTitle_TextChanged(object sender, EventArgs e)
    {
        //检查标题的唯一性
        DocumentUtility du = new DocumentUtility();
        if (du.CheckTitle(txtTitle.Text.Trim()) == true)
        {
            lblMsg.Text = "以此为标题的文档已存在!";
            lblMsg.UpdateAfterCallBack = true;
            imageIndicator.Visible = true;
            imageIndicator.ImageUrl = "../image/check_error.gif";
            imageIndicator.UpdateAfterCallBack = true;
        }
        else
        {
            lblMsg.Text = "";
            lblMsg.UpdateAfterCallBack = true;
            imageIndicator.Visible = true;
            imageIndicator.ImageUrl = "../image/check_right.gif";
            imageIndicator.UpdateAfterCallBack = true;
        }
    }

我只是把原来的TextBox改为Anthem.NET的TextBox,再加入个指示图片,可以说极少的修改,非常简单就实现了无刷新的唯一性检查。截图如下:
o_checkError.jpg
o_checkRight.jpg

使用初感:Anthem.Net的学习曲线几乎为0,马上就能上手。Anthem.NET不愧是优秀的AJAX框架,虽然固定不容易扩展,但是轻量、快速。
这是博客园的高手的评价:

#42楼  2006-11-23 09:33 | Terry Deng     

刚刚接触ASP.NET AJAX没多久,又看到Dflying Chen这篇文章,立刻动手将原有用ASP.NET AJAX开发的简单项目移植到Anthem.NET,虽然花了不少时间,但出来的效果绝对是喜人的!页面的执行效率从肉眼就能明显感觉有不少的提升,正如Dflying Chen所说Anthem.NET是ASP.NET AJAX的轻量级实现,甚至可以说是完美的轻量级实现。而在实践之后得出Anthem.NET相比ASP.NET AJAX的优势:

1.性能优势非常明显,在原有项目asp.net ajax结构中所用到的Microsoft.Web.Extensions.dll及Microsoft.Web.Preview.dll分别是646KB和898KB,而移植到Anthem.NET所用到的Anthem.dll仅仅120KB。换言而之,Anthem.NET的代码量仅仅是asp.net ajax的12分之一。无疑Anthem.NET代码的简洁换来的是AJAX执行效率的高效及页面性能的提升。可以说,Anthem.NET相比asp.net ajax最大的优势及吸引人的亮点就是性能方面的优势!

2.感觉Anthem.NET每一个控件单独设置异步回调的AJAX方式比asp.net ajax的updatepanel局部页面刷新实现的异步回调的AJAX方式更加合理化及细致化一点。

3.Anthem.NET代码的简洁使脚本的出错机率大大降低,原来项目用asp.net ajax时频繁点击页面有时会出现脚本的错误,在Anthem.NET中就不再存在了。

当然相比ASP.NET AJAX的不足也是显然易见的:

1.从原有项目移植到AJAX框架的便捷性来说asp.net ajax无疑更具优势,从普通框架的项目移植到AJAX框架,使用asp.net ajax只需将原有页面的所有东西嵌套到Updatepanel之内即可简单实现AJAX,但Anthem.NET却需要一个个地修改原有控件及增加相关属性,如遇到控件比较多的项目就需要花上大量的时间。

2.从技术文档及相关资源来说asp.net ajax绝对占据优势,从长远的开发前景来说,拥有微软官方支持的asp.net ajax比个人开源项目的Anthem.NET来说更容易普及开来。

3.asp.net ajax能开发更加复杂的Ajax应用,从各自相关例子就能看出,asp.net ajax能实现更为复杂的应用,毕竟Anthem.NET代码量仅仅是asp.net ajax的12分之一,不可以兼顾那么多的应用。不过从Anthem.NET提供的例子也可以看出,基本上实际开发所需要到的应用Anthem.NET都已经提供了。毕竟实际开发中我们并不需要太多的复杂应用,所以Anthem.Net还是不错的。

个人感觉从Asp.NET执行性能上来讲Anthem.NET>Ajax.net>Asp.net ajax,从ASP.NET适用性来讲ASP.NET AJAX>Anthem.NET>Ajax.net。

Anthem.NET下载地址:http://nchc.dl.sourceforge.net/sourceforge/anthem-dot-net/anthem-1.5.2.zip

参考资料:

Anthem.NET forum:http://forums.anthemdotnet.com/forums/
Anthem.NET Samples:http://anthem.talloaksoftware.com/
Anthem Documentation:http://anthem-dot-net.sourceforge.net/docs/
Anthem.NET - 木野狐(Neil Chen) - 博客园:http://www.cnblogs.com/RChen/category/69922.html





posted @ 2008-05-15 17:07 JasonLin 阅读(888) 评论(4) 编辑