| Feng's profileLudwig的骇客帝国BlogLists | Help |
|
August 13 索引技术(转载)索引技术
一、数据表的基本结构
为认识索引工作原理,首先有必要对数据表的基本结构作一次全面的复习。
SQLS 当一个新表被创建之时,系统将在磁盘中分配一段以8K为单位的连续空间,当字段的值从内存写入磁盘时,就在这一既定空间随机保存,当一个8K用完的时候, SQLS指针会自动分配一个8K的空间。这里,每个8K空间被称为一个数据页(Page),又名页面或数据页面,并分配从0-7的页号,每个文件的第0页记录引导信息,叫文件头(File header);每8个数据页(64K)的组合形成扩展区(Extent),称为扩展。全部数据页的组合形成堆(Heap)。
SQLS 规定行不能跨越数据页,所以,每行记录的最大数据量只能为8K。这就是char和varchar这两种字符串类型容量要限制在8K以内的原因,存储超过 8K的数据应使用text类型,实际上,text类型的字段值不能直接录入和保存,它只是存储一个指针,指向由若干8K的文本数据页所组成的扩展区,真正的数据正是放在这些数据页中。
页面有空间页面和数据页面之分。
当一个扩展区的8个数据页中既包含了空间页面又包括了数据或索引页面时,称为混合扩展(Mixed Extent),每张表都以混合扩展开始;反之,称为一致扩展(Uniform Extent),专门保存数据及索引信息。
表被创建之时,SQLS在混合扩展中为其分配至少一个数据页面,随着数据量的增长,SQLS可即时在混合扩展中分配出7个页面,当数据超过8个页面时,则从一致扩展中分配数据页面。
空间页面专门负责数据空间的分配和管理,包括:PFS页面(Page free space):记录一个页面是否已分配、位于混合扩展还是一致扩展以及页面上还有多少可用空间等信息;GAM页面(Global allocation map)和SGAM页面(Secodary global allocation map):用来记录空闲的扩展或含有空闲页面的混合扩展的位置。SQLS综合利用这三种类型的页面文件在必要时为数据表创建新空间;
数据页或索引页则专门保存数据及索引信息,SQLS使用4种类型的数据页面来管理表或索引:它们是IAM页、数据页、文本/图像页和索引页。
在WINDOWS 中,我们对文件执行的每一步操作,在磁盘上的物理位置只有系统(system)才知道;SQL SERVER沿袭了这种工作方式,在插入数据的过程中,不但每个字段值在数据页面中的保存位置是随机的,而且每个数据页面在“堆”中的排列位置也只有系统(system)才知道。
这是为什么呢?众所周知,OS 之所以能管理DISK,是因为在系统启动时首先加载了文件分配表:FAT(File Allocation Table),正是由它管理文件系统并记录对文件的一切操作,系统才得以正常运行;同理,作为管理系统级的SQL SERVER,也有这样一张类似FAT的表存在,它就是索引分布映像页:IAM(Index Allocation Map)。
IAM的存在,使SQLS对数据表的物理管理有了可能。
IAM 页从混合扩展中分配,记录了8个初始页面的位置和该扩展区的位置,每个IAM页面能管理512,000个数据页面,如果数据量太大,SQLS也可以增加更多的IAM页,可以位于文件的任何位置。第一个IAM页被称为FirstIAM,其中记录了以后的IAM页的位置。
数据页和文本/图像页互反,前者保存非文本/图像类型的数据,因为它们都不超过8K的容量,后者则只保存超过8K容量的文本或图像类型数据。而索引页顾名思义,保存的是与索引结构相关的数据信息。了解页面的问题有助我们下一步准确理解SQLS维护索引的方式,如页拆分、填充因子等。
二、索引的基本概念
索引是一种特殊类型的数据库对象,它与表有着密切的联系。
索引是为检索而存在的。如一些书籍的末尾就专门附有索引,指明了某个关键字在正文中的出现的页码位置,方便我们查找,但大多数的书籍只有目录,目录不是索引,只是书中内容的排序,并不提供真正的检索功能。可见建立索引要单独占用空间;索引也并不是必须要建立的,它们只是为更好、更快的检索和定位关键字而存在。
再进一步说,我们要在图书馆中查阅图书,该怎么办呢?图书馆的前台有很多叫做索引卡片柜的小柜子,里面分了若干的类别供我们检索图书,比如你可以用书名的笔画顺序或者拼音顺序作为查找的依据,你还可以从作者名的笔画顺序或拼音顺序去查询想要的图书,反正有许多检索方式,但有一点很明白,书库中的书并没有按照这些卡片柜中的顺序排列——虽然理论上可以这样做,事实上,所有图书的脊背上都人工的粘贴了一个特定的编号①,它们是以这个顺序在排列。索引卡片中并没有指明这本书摆放在书库中的第几个书架的第几本,仅仅指明了这个特定的编号。管理员则根据这一编号将请求的图书返回到读者手中。这是很形象的例子,以下的讲解将会反复用到它。
SQLS 在安装完成之后,安装程序会自动创建master、model、tempdb等几个特殊的系统数据库,其中master是SQLS的主数据库,用于保存和管理其它系统数据库、用户数据库以及SQLS的系统信息,它在SQLS中的地位与WINDOWS下的注册表相当。
master中有一个名为sysindexes的系统表,专门管理索引。SQLS查询数据表的操作都必须用到它,毫无疑义,它是本文主角之一。
查看一张表的索引属性,可以在查询分析器中使用以下命令:select * from sysindexes where id=object_id(‘tablename’) ;而要查看表的索引所占空间的大小,可以使用系统存储过程命令:sp_spaceused tablename,其中参数tablename为被索引的表名。
三、平衡树
如果你通过书后的索引知道了一个关键字所在的页码,你有可能通过随机的翻寻,最终到达正确的页码。但更科学更快捷的方法是:首先把书翻到大概二分之一的位置,如果要找的页码比该页的页码小,就把书向前翻到四分之一处,否则,就把书向后翻到四分之三的地方,依此类推,把书页续分成更小的部分,直至正确的页码。这叫“两分法”,微软在官方教程MOC里另有一种说法:叫B树(B-Tree,Balance Tree),即平衡树。
一个表索引由若干页面组成,这些页面构成了一个树形结构。B 树由“根”(root)开始,称为根级节点,它通过指向另外两个页,把一个表的记录从逻辑上分成两个部分:“枝”—--非叶级节点(Non-Leaf Level);而非叶级节点又分别指向更小的部分:“叶”——叶级节点(Leaf Level)。根节点、非叶级节点和叶级节点都位于索引页中,统称为索引节点,属于索引页的范筹。这些“枝”、“叶”最终指向了具体的数据页(Page)。在根级节点和叶级节点之间的叶又叫数据中间页。
“根”(root)对应了sysindexes表的Root字段,其中记载了非叶级节点的物理位置(即指针);非叶级节点位于根节点和叶节点之间,记载了指向叶级节点的指针;而叶级节点则最终指向数据页。这就是“平衡树”。
四、聚集索引和非聚集索引
从形式上而言,索引分为聚集索引(Clustered Indexes)和非聚集索引(NonClustered Indexes)。
聚集索引相当于书籍脊背上那个特定的编号。如果对一张表建立了聚集索引,其索引页中就包含着建立索引的列的值(下称索引键值),那么表中的记录将按照该索引键值进行排序。比如,我们如果在“姓名”这一字段上建立了聚集索引,则表中的记录将按照姓名进行排列;如果建立了聚集索引的列是数值类型的,那么记录将按照该键值的数值大小来进行排列。
非聚集索引用于指定数据的逻辑顺序,也就是说,表中的数据并没有按照索引键值指定的顺序排列,而仍然按照插入记录时的顺序存放。其索引页中包含着索引键值和它所指向该行记录在数据页中的物理位置,叫做行定位符(RID:Row ID)。好似书后面的的索引表,索引表中的顺序与实际的页码顺序也是不一致的。而且一本书也许有多个索引。比如主题索引和作者索引。
SQL Server在默认的情况下建立的索引是非聚集索引,由于非聚集索引不对表中的数据进行重组,而只是存储索引键值并用一个指针指向数据所在的页面。一个表如果没有聚集索引时,理论上可以建立249个非聚集索引。每个非聚集索引提供访问数据的不同排序顺序。
五、数据是怎样被访问的
若能真正理解了以上索引的基础知识,那么再回头来看索引的工作原理就简单和轻松多了。
(一)SQLS怎样访问没有建立任何索引数据表:
Heap 译成汉语叫做“堆”,其本义暗含杂乱无章、无序的意思,前面提到数据值被写进数据页时,由于每一行记录之间并没地有特定的排列顺序,所以行与行的顺序就是随机无序的,当然表中的数据页也就是无序的了,而表中所有数据页就形成了“堆”,可以说,一张没有索引的数据表,就像一个只有书柜而没有索引卡片柜的图书馆,书库里面塞满了一堆乱七八糟的图书。当读者对管理员提交查询请求后,管理员就一头钻进书库,对照查找内容从头开始一架一柜的逐本查找,运气好的话,在第一个书架的第一本书就找到了,运气不好的话,要到最后一个书架的最后一本书才找到。
SQLS 在接到查询请求的时候,首先会分析sysindexes表中一个叫做索引标志符(INDID: Index ID)的字段的值,如果该值为0,表示这是一张数据表而不是索引表,SQLS就会使用sysindexes表的另一个字段——也就是在前面提到过的 FirstIAM值中找到该表的IAM页链——也就是所有数据页集合。
这就是对一个没有建立索引的数据表进行数据查找的方式,是不是很没效率?对于没有索引的表,对于一“堆”这样的记录,SQLS也只能这样做,而且更没劲的是,即使在第一行就找到了被查询的记录,SQLS仍然要从头到尾的将表扫描一次。这种查询称为“遍历”,又叫“表扫描”。
可见没有建立索引的数据表照样可以运行,不过这种方法对于小规模的表来说没有什么太大的问题,但要查询海量的数据效率就太低了。
(二)SQLS怎样访问建立了非聚集索引的数据表:
如前所述,非聚集索引可以建多个,具有B树结构,其叶级节点不包含数据页,只包含索引行。假定一个表中只有非聚集索引,则每个索引行包含了非聚集索引键值以及行定位符(ROW ID,RID),他们指向具有该键值的数据行。每一个RID由文件ID、页编号和在页中行的编号组成。
当INDID 的值在2-250之间时,意味着表中存在非聚集索引页。此时,SQLS调用ROOT字段的值指向非聚集索引B树的ROOT,在其中查找与被查询最相近的值,根据这个值找到在非叶级节点中的页号,然后顺藤摸瓜,在叶级节点相应的页面中找到该值的RID,最后根据这个RID在Heap中定位所在的页和行并返回到查询端。
例如:假定在Lastname上建立了非聚集索引,则执行Select * From Member Where Lastname=’Ota’时,查询过程是:①SQLS 查询INDID值为2;②立即从根出发,在非叶级节点中定位最接近Ota的值“Martin”,并查到其位于叶级页面的第61页;③仅在叶级页面的第61 页的Martin下搜寻Ota的RID,其RID显示为N∶706∶4,表示Lastname字段中名为Ota的记录位于堆的第707页的第4行,N表示文件的ID值,与数据无关;④根据上述信息,SQLS立马在堆的第 707页第4行将该记录“揪”出来并显示于前台(客户端)。视表的数据量大小,整个查询过程费时从百分之几毫秒到数毫秒不等。
在谈到索引基本概念的时候,我们就提到了这种方式:
图书馆的前台有很多索引卡片柜,里面分了若干的类别,诸如按照书名笔画或拼音顺序、作者笔画或拼音顺序等等,但不同之处有二:① 索引卡片上记录了每本书摆放的具体位置——位于某柜某架的第几本——而不是“特殊编号”;② 书脊上并没有那个“特殊编号”。管理员在索引柜中查到所需图书的具体位置(RID)后,根据RID直接在书库中的具体位置将书提出来。
显然,这种查询方式效率很高,但资源占用极大,因为书库中书的位置随时在发生变化,必然要求管理员花费额外的精力和时间随时做好索引更新。
(三)SQLS怎样访问建立了聚集索引的数据表:
在聚集索引中,数据所在的数据页是叶级,索引数据所在的索引页是非叶级。
查询原理和上述对非聚集索引的查询相似,但由于记录是按照聚集索引中索引键值进行排序,换句话说,聚集索引的索引键值也就是具体的数据页。
这就好比书库中的书就是按照书名的拼音在排序,而且也只按照这一种排序方式建立相应的索引卡片,于是查询起来要比上述只建立非聚集索引的方式要简单得多。仍以上面的查询为例:
假定在Lastname字段上建立了聚集索引,则执行Select * From Member Where Lastname=’Ota’时,查询过程是:①SQLS查询INDID值为1,这是在系统中只建立了聚集索引的标志;②立即从根出发,在非叶级节点中定位最接近Ota的值“Martin”,并查到其位于叶级页面的第120页;③在位于叶级页面第120页的Martin下搜寻到Ota条目,而这一条目已是数据记录本身;④将该记录返回客户端。
这一次的效率比第二种方法更高,以致于看起来更美,然而它最大的优点也恰好是它最大的缺点——由于同一张表中同时只能按照一种顺序排列,所以在任何一种数据表中的聚集索引只能建立一个;并且建立聚集索引需要至少相当于源表120%的附加空间,以存放源表的副本和索引中间页!
难道鱼和熊掌就不能兼顾了吗?办法是有的。
(四)SQLS怎样访问既有聚集索引、又有非聚集索引的数据表:
如果我们在建立非聚集索引之前先建立了聚集索引的话,那么非聚集索引就可以使用聚集索引的关键字进行检索,就像在图书馆中,前台卡片柜中的可以有不同类别的图书索引卡,然而每张卡片上都载明了那个特殊编号——并不是书籍存放的具体位置。这样在最大程度上既照顾了数据检索的快捷性,又使索引的日常维护变得更加可行,这是最为科学的检索方法。
也就是说,在只建立了非聚集索引的情况下,每个叶级节点指明了记录的行定位符(RID);而在既有聚集索引又有非聚集索引的情况下,每个叶级节点所指向的是该聚集索引的索引键值,即数据记录本身。
假设聚集索引建立在Lastname上,而非聚集索引建立在Firstname上,当执行Select * From Member Where Firstname=’Mike’时,查询过程是:①SQLS查询INDID值为2;②立即从根出发,在Firstname的非聚集索引的非叶级节点中定位最接近Mike的值“Jose”条目;③从Jose条目下的叶级页面中查到Mike逻辑位置——不是RID而是聚集索引的指针;④根据这一指针所指示位置,直接进入位于Lastname的聚集索引中的叶级页面中到达Mike数据记录本身;⑤将该记录返回客户端。
这就完全和我们在“索引的基本概念”中讲到的现实场景完全一样了,当数据发生更新的时候,SQLS 只负责对聚集索引的健值驾以维护,而不必考虑非聚集索引,只要我们在ID类的字段上建立聚集索引,而在其它经常需要查询的字段上建立非聚集索引,通过这种科学的、有针对性的在一张表上分别建立聚集索引和非聚集索引的方法,我们既享受了索引带来的灵活与快捷,又相对规避了维护索引所导致的大量的额外资源消耗。
六、索引的优点和不足
索引有一些先天不足:1:建立索引,系统要占用大约为表的1.2倍的硬盘和内存空间来保存索引。2:更新数据的时候,系统必须要有额外的时间来同时对索引进行更新,以维持数据和索引的一致性——这就如同图书馆要有专门的位置来摆放索引柜,并且每当库存图书发生变化时都需要有人将索引卡片重整以保持索引与库存的一致。
当然建立索引的优点也是显而易见的:在海量数据的情况下,如果合理的建立了索引,则会大大加强SQLS执行查询、对结果进行排序、分组的操作效率。
实践表明,不恰当的索引不但于事无补,反而会降低系统性能。因为大量的索引在进行插入、修改和删除操作时比没有索引花费更多的系统时间。比如在如下字段建立索引应该是不恰当的:1、很少或从不引用的字段;2、逻辑型的字段,如男或女(是或否)等。
综上所述,提高查询效率是以消耗一定的系统资源为代价的,索引不能盲目的建立,必须要有统筹的规划,一定要在“加快查询速度”与“降低修改速度”之间做好平衡,有得必有失,此消则彼长。这是考验一个DBA是否优秀的很重要的指标。
上期,我们就索引的基本概念和数据查询原理作了详细阐述,知道了建立索引时一定要在“加快查询速度”与“降低修改速度”之间做好平衡,有得必有失,此消则彼长。那么,SQLS维护索引时究竟怎样消耗资源?应该从哪些方面对索引进行管理与优化?以下从六个方面来回答这些问题:
1)页分裂
微软MOC教导我们:当一个数据页达到了8K容量,如果此时发生插入或更新数据的操作,将导致页的分裂(又名页拆分):
1.有聚集索引的情况下:聚集索引将被插入和更新的行指向特定的页,该页由聚集索引关键字决定;
2.只有堆的情况下:只要有空间就可以插入新的行,但是如果我们对行数据的更新需要更多的空间,以致大于当前页的可用空间,行就被移到新的页中,并且在原位置留下一个转发指针,指向被移动的新行,如果具有转发指针的行又被移动了,那么原来的指针将重新指向新的位置;
3.如果堆中有非聚集索引,那么尽管插入和更新操作在堆中不会发生页分裂,但是在非聚集索引上仍然产生页分裂。
无论有无索引,大约一半的数据将保留在老页面,而另一半将放入新页面,并且新页面可能被分配到任何可用的页。所以,频繁页分裂,后果很严重,将使物理表产生大量数据碎片,导致直接造成I/O效率的急剧下降,最后,不得不停止SQLS的运行并重建索引。
2)填充因子
然而在“混沌之初”,就可以在一定程度上避免不愉快出现,在创建索引时,可以为这个索引指定一个填充因子,以便在索引的每个叶级页面上保留一定百分比的空间,将来数据可以进行扩充和减少页分裂。填充因子是从0到100的百分比数值,设为100时表示将数据页填满,只有当不会对数据进行更改时(例如只读表中)才用此设置。值越小则数据页上的空闲空间越大,这样可以减少在索引增长过程中进行页分裂的需要,但这一操作需要占用更多的硬盘空间。
填充因子只在创建索引时执行,索引创建以后,当表中进行数据的添加、删除或更新时,是不会保持填充因子的,如果想在数据页上保持额外的空间,则有悖于使用填充因子的本意,因为随着数据的输入,SQLS必须在每个页上进行页拆分,以保持填充因子指定的空闲空间。因此,只有在表中的数据进行了较大的变动,才可以填充数据页的空闲空间。这时,可以从容的重建索引,重新指定填充因子,重新分布数据。
反之,填充因子指定不当,就会降低数据库的读取性能,其降低量与填充因子设置值成反比。例如,当填充因子的值为50时,数据库的读取性能会降低两倍。所以,只有在表中根据现有数据创建新索引,并且可以预见将来会对这些数据进行哪些更改时,设置填充因子才有意义。
3)两道数学题
假定数据库设计没有问题,那么是否像上篇分析的那样,当你建立了众多的索引,在查询工作中SQLS就只能按照“最高指示”用索引处理每一个提交的查询呢?答案是否定的。
“数据是怎样被访问的”一文中提到的四种索引方案只是一种静态的、标准的和理论上的分析比较。实际上,SQLS几乎完全是“自主”的决定是否使用索引或使用哪一个索引
这是怎么回事呢?
让我们先来算一道题:如果某表的一条记录在磁盘上占用1000字节(1K)的话,我们对其中10字节的一个字段建立索引,那么该记录对应的索引大小只有10 字节(0.01K)。上篇说过,SQLS的最小空间分配单元是“页(Page)”,一个页面在磁盘上占用8K空间,所以一页只能存储8条“记录”,但可以存储800条“索引”。现在我们要从一个有8000条记录的表中检索符合某个条件的记录(有Where子句),如果没有索引的话,我们需要遍历8000条 ×1000字节/8K字节=1000个页面才能够找到结果。如果在检索字段上有上述索引的话,那么我们可以在8000条×10字节/8K字节=10个页面中就检索到满足条件的索引块,然后根据索引块上的指针逐一找到结果数据块,这样I/O访问量肯定要少得多。
然而有时用索引比不用索引还快。
同上,如果要无条件检索全部记录(不用Where子句),不用索引的话,需要访问8000条×1000字节/8K字节=1000个页面;而使用索引的话,首先检索索引,访问8000条×10字节/8K字节=10个页面得到索引检索结果,再根据索引检索结果去对应数据页面,由于是检索全部数据,所以需要再访问 8000条×1000字节/8K字节=1000个页面将全部数据读取出来,一共访问了1010个页面,这显然不如不用索引快。
SQLS内部有一套完整的数据索引优化技术,在上述情况下,SQLS会自动使用表扫描的方式检索数据而不会使用任何索引。那么SQLS是怎么知道什么时候用索引,什么时候不用索引的呢?因为SQLS除了维护数据信息外,还维护着数据统计信息。
4)统计信息
打开企业管理器,单击“Database”节点,右击Northwind数据库→单击“属性”→选择“Options”选项卡,观察“Settings”下的各项复选项,你发现了什么?
从Settings中我们可以看到,在数据库中,SQLS将默认的自动创建和更新统计信息,这些统计信息包括数据密度和分布信息,正是它们帮助SQLS确定最佳的查询策略:建立查询计划和是否使用索引以及使用什么样的索引。
在创建索引时,SQLS会创建分布数据页来存放有关索引的两种统计信息:分布表和密度表。查询优化器使用这些统计信息估算使用该索引进行查询的成本(Cost),并在此基础上判断该索引对某个特定查询是否有用。
随着表中的数据发生变化,SQLS自动定期更新这些统计信息。采样是在各个数据页上随机进行。从磁盘读取一个数据页后,该数据页上的所有行都被用来更新统计信息。统计信息更新的频率取决于字段或索引中的数据量以及数据更改量。比如,对于有一万条记录的表,当1000个索引键值发生改变时,该表的统计信息便可能需要更新,因为1000 个值在该表中占了10%,这是一个很大的比例。而对于有1千万条记录的表来说,1000个索引值发生更改的意义则可以忽略不计,因此统计信息就不会自动更新。
5)索引的人工维护
上面讲到,某些不合适的索引将影响到SQLS的性能,随着应用系统的运行,数据不断地发生变化,当数据变化达到某一个程度时将会影响到索引的使用。这时需要用户自己来维护索引。
随着数据行的插入、删除和数据页的分裂,有些索引页可能只包含几页数据,另外应用在执行大量I/O的时候,重建非聚聚集索引可以维护I/O的效率。重建索引实质上是重新组织B树。需要重建索引的情况有:
1.数据和使用模式大幅度变化;
2.排序的顺序发生改变;
3.要进行大量插入操作或已经完成;
4.使用I/O查询的磁盘读次数比预料的要多;
5.由于大量数据修改,使得数据页和索引页没有充分使用而导致空间的使用超出估算;
6.dbcc检查出索引有问题。
6)索引的使用原则
接近尾声的时候,让我们再从另一个角度认识索引的两个重要属性----惟一性索引和复合性索引。
惟一性索引保证在索引列中的全部数据是惟一的,不会包含冗余数据。如果表中已经有一个主键约束或者惟一性约束,那么当创建表或者修改表时,SQLS自动创建一个惟一性索引。但出于必须保证惟一性,那么应该创建主键约束或者惟一性键约束,而不是创建一个惟一性索引。
复合索引就是一个索引创建在两个列或者多个列上。在搜索时,当两个或者多个列作为一个关键值时,最好在这些列上创建复合索引。当创建复合索引时,应该考虑这些规则:最多可以把16个列合并成一个单独的复合索引,构成复合索引的列的总长度不能超过900字节;在复合索引中,所有的列必须来自同一个表中,不能跨表建立复合列;在复合索引中,列的排列顺序是非常重要的,原则上,应该首先定义最惟一的列,例如在(COL1,COL2)上的索引与在(COL2, COL1)上的索引是不相同的,因为两个索引的列的顺序不同;为了使查询优化器使用复合索引,查询语句中的WHERE子句必须参考复合索引中第一个列。 综上所述,我们总结了如下索引使用原则:
1.逻辑主键使用惟一的成组索引,对系统键(作为存储过程)采用惟一的非成组索引,对任何外键列采用非成组索引。考虑数据库的空间有多大,表如何进行访问,还有这些访问是否主要用作读写;
2.不要索引memo/note 字段,不要索引大型字段(有很多字符),这样作会让索引占用太多的存储空间;
3.不要索引常用的小型表;
4.一般不要为小型数据表设置过多的索引,如果经常有插入和删除操作就更不要设置索引,因为SQLS对插入和删除操作提供的索引维护可能比扫描表空间消耗的时间更多。
查询是一个物理过程,表面上是SQLS在东跑西跑,其实真正大部分压马路的工作是由磁盘输入输出系统(I/O)完成,全表扫描需要从磁盘上读表的每一个数据页,如果有索引指向数据值,则I/O读几次磁盘就可以了。但是,在随时发生的增、删、改操作中,索引的存在会大大增加工作量,因此,合理的索引设计是建立在对各种查询的分析和预测上的,只有正确地使索引与程序结合起来,才能产生最佳的优化方案。
SQLS是一个很复杂的系统,让索引以及查询背后的东西真相大白,可以帮助我们更为深刻的了解我们的系统。一句话,索引就像盐,少则无味多则咸。 April 29 和X509证书相关的一些命令
makecert -r -pe -n "CN=XYZ Company" -b 01/01/2005 -e 01/01/2010 -sky exchange -ss my -a sha1
March 27 一篇关于降低程序耦合度的好文《通过理顺软件的依赖关系提高应用程序灵活性》 主要讲述了: 依赖关系反转, 依赖关系注入, 使用Mock的Unit Test技术, IoC容器, ServiceLocator模式, 装饰模式以及Boo的DSL语言 March 20 使用Javascript 动态在表格里添加和删除行 //add a new row to the table
function addRow()
{
//add a row to the rows collection and get a reference to the newly added row
var newRow = document.all("tblGrid").insertRow();
//add 3 cells (<td>) to the new row and set the innerHTML to contain text boxes
var oCell = newRow.insertCell();
oCell.innerHTML = "<input type='text' name='t1'>";
oCell = newRow.insertCell();
oCell.innerHTML = "<input type='text' name='t2'>";
oCell = newRow.insertCell();
oCell.innerHTML = "<input type='text' name='t3'> <input type='button' value='Delete' onclick='removeRow(this);'/>";
}
//deletes the specified row from the table
function removeRow(src)
{
/* src refers to the input button that was clicked.
to get a reference to the containing <tr> element,
get the parent of the parent (in this case <tr>)
*/
var oRow = src.parentElement.parentElement;
//once the row reference is obtained, delete it passing in its rowIndex
document.all("tblGrid").deleteRow(oRow.rowIndex);
}原文: http://www.codeproject.com/KB/scripting/DHTMLGrid.aspx EventLogEventLog.CreateEventSource(source, logName); 默认情况下,服务器上存在三个日志文件: Application、System 和 Security。应用程序和服务使用 Application 日志文件。设备驱动程序使用 System 日志文件。打开审核时,系统在 Security 日志中生成成功审核事件和失败审核事件。如果安装了其他应用程序(如 Windows Server 上的 Active Directory),则可能会有其他默认日志文件。另外,还可以在本地计算机或远程计算机上创建自定义日志文件。与组件向默认的 Application 日志写入事件相比,自定义日志可以更详细地组织日志项。 如果写入事件日志,则仅指定 Log (即LogName)属性是不够的。必须将 Source 属性与事件日志资源关联,才能将其连接到特定的日志。若仅从日志中读取,则不需要指定 Source,但必须使某个事件源与服务器注册表中的事件日志资源关联。只能指定 Log 名称和从中读取的 MachineName(服务器计算机名称)。 Code: public static void Main(){ March 19 M$ ASP.NET AJAX注册脚本用户自定义控件中的UpdatePanel里放入了一个GridView, 然后GridView里有一个ImageButton. 点击ImageButton后希望能返回成功的MessageBox. 本来在GridView里的Command事件回调函数中使用: ScriptManager.RegisterStartupScript(this, this.GetType(), "gvPending_Command_ShowMessage", "alert('加入成功!');", true); 不行, 后来改用 ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "gvPending_Command_ShowMessage", "alert('加入成功!');", true); 就成功了. 现在还不清楚RegisterStartupScript第一个参数的用处, 该参数的类型是Page或者Control. February 05 对《Understanding Single Sign-On in ASP.NET 2.0》一文的补充 --- 引用自http://blog.joycode.com/dotey/今日偶然阅读了Understanding Single Sign-On in ASP.NET 2.0 这篇关于单点登录的文章,仔细阅读,发现还是有些不尽完整之处。文中对于单点登录的介绍,忽略了一个重要问题——就是站点的域的问题。在深入讨论这个问题之前,先简单介绍一下网站域的概念,举个例子,假如我们有三个站点: 回过头来看这篇单点登录文章,按照这种方案,仅能实现同一域下各虚拟目录的单点登录,离真正的单点登录还差得远,当然,文章的思路,对于同一域下的虚拟目录,或者同一主域的不同站点,还有有意义的。 前面说到了文章中的方案还只能实现同一域下的不同虚拟目录的单点登录,还不能实现同一主域的单点登录,那么怎么样才能在这个方案基础上实现同一主域的不同站点的单点登录呢? 文章的核心部分在于让每个站点的MachineKey保持一致,采用Form验证,这样可以保证每台服务器Cookie加密解密的结果是一致的。Form验证将登录后的授权凭证加密后保存在Cookie中,由于同一域下面的虚拟目录,Cookie是可以共享的,因此可以同一域内直接实现单点登录,而对于不同域,Cookie是不能直接共享的,所以对于不同域而同一主域的情况,我们还需要将Cookie的domain设为主域。那么还以前文的A、B站点为例,要实现单点,我们只要在web.config中,配置authentication \forms节点下domain值为主域,如下: 而对于不同主域的站点,实现方案相对就复杂多了。 December 19 使用 Request.QueryString 接受参数时,跟编码有关的一些问题摘自蝈蝈俊.net2007年12月7日 15:22 - (阅读:2080;评论:15)
我们先来看以下几个请求,看a.aspx 页面用Request.QueryString接受到的是啥信息?
情况分析: 案例一 a.aspx?info=%25 为何 Request.QueryString["info"]接受到的值是 % ,而不是 %25,是因为Request.QueryString 替我们在接受到值后,做了一次URL解码。 HttpUtility.UrlDecode("%25") 的计算结果就是 % 上面的这个案例一虽然看起来很简单。但是我们在一些特殊场景时候,就会因为这个而极度郁闷。 比如以下几种情况: 你有一个自己的加密算法,而这个加密算法,某些情况下会计算出带百分号的结果,而这个结果你是要通过URL参数的方式传递给其它页面的。 如果解决案例一碰到的情况呢? 解决方案一: 把需要传递的参数传递前作一次 HttpUtility.UrlEncode , 切记,不可在接受方每次接受后,自作聪明的都做一次 UrlEncode 。而是在发送方做 UrlEncode 。 另:这套方案中切记, UrlEncode 和 UrlDecode 的次数应该一一对应。不能多一次,也不能少一次。 a.aspx 页面中,根据传入的 from 参数,自动跳转到 from 参数(用Request.QueryString["from"]来接受这个参数)设置的页面。 下面再复杂一点,我给下面几个链接,其中都有 a 这个参数,请告诉我 a 这个参数是被那个页面接受到了?
如果想不明白,就想想下面这句话 解决方案二: 不用 Request.QueryString ,而是自己实现一个获取查询参数的方法。细节我在案例二讲完后再告诉大家,因为这个解决方案也处理了案例二的一些情况。 案例二 a.aspx?info=%bc%bc%ca%f5 传给我们的信息其实是使用 GB2312 编码后的“技术” 这两个汉字。 ASP.net 系统内部,在处理 Request.QueryString 等情况时候,都是使用的 UTF-8 的编码,我们如果不存在多系统并存的问题时候,这个问题一点都不存在。 比如下面这两个地址提到的问题: ASP.net中的Server.UrlEncode函数和ASP中的Server.URLEncode函数返回的值竟然不一样 PHP与aspx之间中文通过URL如何传递? 案例二的解决方案 就是采用类似下面代码的方式,来获得指定格式编码的查询文本参数。 System.Collections.Specialized.NameValueCollection nv =
要说我为啥知道上面几种解决方案,是因为我用 Reflector 看了 Request.QueryString 的实现代码。在查看代码时候,我们会看到这样一个 internal 方法: 这个内部方法实现了,按需解密查询参数的功能,但是遗憾的是,在QueryString 的处理函数中,强制指定了解析 QueryString 时,必须作一次 HttpUtility.UrlDecode。参看如下代码: public static NameValueCollection ParseQueryString(string query, Encoding encoding) 如果我们不想采用案例一的解决方案一,我们就需要自己写一个解析查询信息的代码。我们完全可以照抄 System.Web.HttpValueCollection 类的 internal void FillFromString(string s, bool urlencoded, Encoding encoding) 方法来改写。但郁闷的是:如果你用 Reflector 察看这个函数的实现时候,Reflector 出来的代码是错误的。正确的方法如下:是在施凡帮助下完成的。 自己实现从 URL 查询文本 Query 中解析出我们自己需要的文本的方法 /// <summary> // 确保 查询文本首字符不是 ? int num1 = (query != null) ? query.Length : 0; BREAKWHILE: string name = null; queryString.Add(HttpUtility.UrlDecode(name, encoding), HttpUtility.UrlDecode(val, encoding)); return queryString; } 用上面的代码,我们就可以按需解析自己需要的查询参数,而不是受限的使用Request.QueryString 。 小结 Request.QueryString 替我们件事情:每次接受到参数后,都做 UrlEncode ,并且是按照 UTF-8编码做的 UrlEncode 。 这在大多数情况下没有任何问题,但是一些情况下,会给我们带来麻烦,本文就是分析这些可能给我们带来麻烦的场景,以及解决方法。 参考资料: 使用 Reflector ; 查看代码时候,碰到的一个Reflector 的bug 解密不同编码的的参数。 June 05 Architecture Journal Profile: Don FergusonFor this issue, as part of the Architecture Journal Profile series, we had the chance to catch up with Don Ferguson, a Technical Fellow at Microsoft. We asked Don some questions about his career, and we asked what advice he had for people who wanted to become architects or who are interested in architecture today.
AJ: Who are you, and where are you from? DF: I'm Don Ferguson. Before I joined Microsoft earlier this year, I was an IBM Fellow. There are about 200,000 engineers at IBM and about 50 Fellows, so it was quite an honor to be one of them. When I first joined IBM Research, I never thought that someday I would be a Fellow. Maybe one day, I would become a project leader; that would be quite an accomplishment. There are a lot of smart, talented people, and I just hoped that I could be one of them. AJ: How did it feel to become an IBM Fellow? DF: The day I became a Fellow was one of the best days of my life. In truth, I did feel a little bit awkward about the award, however. I felt that there were some people who deserved it more than I did. So, shortly after the announcement, I became an advocate for these people, and over the next few years was able to help get three or four of them to Fellow. In some ways, I was happier on their award days than on mine. When it happens to you, it's a blur; but when it happens to others, you have a lot of satisfaction. AJ: What did a typical day look like? DF: I was the Chief Architect in the Software Group in IBM. There were hundreds of products and projects. Being the Chief Architect means that you can't design every component. There are just too many projects and products for this to be a realistic goal. A large portion of my day would be spent doing a lot of review work. I would review several projects' or products' designs, focusing on some top-level things. I placed special emphasis on new products. Typically, I would focus on cross-product integration, common themes, and so on. For example, does the portal product have the right interface to connect to this security product? Is the product supporting the right standards? I used to jokingly refer to this as "herding the cats." On the title slide of presentations that I gave, I often used the title of "Chief Cat Herder." In the early days, this work was very unsatisfying—too abstract, too shallow, too broad. But then I had an epiphany: Working on pulling the different parts together a little bit more had a significant effect, especially across products. A little bit of improvement in a lot of places makes a difference. An example is also true of the work that I was able to do on the Web services standards. I think I helped make them a little more coherent, composable, easier to understand, and so on. AJ: With such responsibilities, how do you stay technically savvy? DF: Good question! The first thing I do is work really hard. When I'm not with the kids, it's often eat, sleep, work, karate; and sometimes sleep is optional. I definitely put in a lot of hours. Secondly, I do a lot of work on airplanes, where there are no conference calls or disruptions. Whenever possible, I consciously stay away from e-mail. I also try not to learn new technical information by reading a paper or presentation. The best way is to download, install, use, and code. Over the years, one of the things I've learned to do well is to synthesize how things should work with only a little bit of information. By and large, people are smart. With a little bit of information, I can often figure out what smart people must have done. How would smart people have designed this? With this process, although I may not know the topic in-depth, I can often work out how things must work and contribute to the discussion. In IBM, I tended to have around 10 to 12 initiatives that I was working on at any time. I would spend a few months on each project, multiplexing between the initiatives. Eventually, each initiative would either take on a life of its own or not pan out. You'll see a lot of this in the standards work I participated in. I was listed as contributor for many of the early papers, but over time I disappeared. A lot of good people started driving and doing deep technical work, and I moved on to something else. AJ: What advice would you give someone who wants to become an architect today? DF: I think there are four pieces to this answer: Firstly, at IBM we had an architect board in the Software Group, which helped me form a network. It took me a while to understand the importance of a network. Being a New Englander, I tend to be a little taciturn and by myself. You should never underestimate the importance of a social network. You don't know what you don't know. You don't know what someone may say to you that can push the reset button in your brain and make you think differently. Secondly, as a software architect, never stop coding. I write code. It's not good or particularly deep code, but I do code. A lot of it is educational and related to my spare-time activities. For example, recently, I've been working on a portal that connects my family using TikiWiki and PHP. I installed the products, but they didn't work for me right out of the box. So, I had to go in and hack them. It was cool. Another example is the nursery school that my daughter attends. They asked me to set up a Web site using [Microsoft] FrontPage, which was another learning experience. Thirdly, communication skills matter. They really do. It's really important to understand how to write well and how to present well. Finally, the most important thing is to connect with customers. Spend as much time as possible with them. Learn what they are trying to do, and look at what works and what doesn't. Help them use your products. There's no substitute for spending time with customers and helping them solve problems. Doing this, we often learned that customers used things in ways that we never dreamed they would. We also came up with amazing new ideas. AJ: Who is the most important person you've ever met, and what made that person so significant? DF: When I started out in academia and the Research Division, my thesis adviser (Yechiam Yemini) was really important. He taught me two things: People who are driven tend to underestimate the quality of what we do. We are too hard on ourselves. We think our papers aren't very good or our research isn't novel. My adviser helped with perspective. Secondly, he taught me that this stuff can be fun. Just have a good time, and enjoy what you are doing. He had a very contagious, childlike enthusiasm. In addition to my adviser, there are many more people at IBM who became great friends and role models. Tony Storey was the most important one. I would look at the ones that I respected, and often try to "reverse-engineer" how they do their job. I would consciously try to be like them. AJ: What is the one thing in your career that you regret? What did you learn from it? DF: Wow! I don't even know where to begin! I'll give you two: My old group gave me a "Darth Vader" helmet, because of the way I was operating in the early days. "Do it my way or I will blow your planet up." The "Darth Vader" approach doesn't work. You can't make smart people do things that they don't want to do. People do well what they want to do. For me, that was an epiphany. Why was I so curt and domineering? I was busy, and all I could think about was, "I have these 20 things to do. Why won't this person just do what I want?" I came to realize that this approach never works, no matter how hard you try. People deserved my time, and I owed them the time. Secondly, many people who work in technology suffer from the "endgame fallacy." We are all pretty bright. We see a lot of customers. We see what they are doing and then plot a trajectory for where they will be in a few years. Once you do this, however, it's too tempting to build what they will need in five years, and not what they need next or are ready for. Sometimes, I say there is no point in building the Emerald City without building the Yellow Brick Road; and you have to build the road first. Often, I would make things too complicated, anticipating their future needs. One of the senior executives used to say that "vision without execution is hallucination," and it's true. AJ: What does Don's future look like? DF: To answer this, I have another piece of advice. When I ask myself that question, I always put personal fulfillment first and then job fulfillment second. If you are not fulfilled personally, you will never be fulfilled in your job. I have a black belt in karate (Kenpo) and want to get better at that. I want to take another discipline: Jiu-Jitsu. I would like to teach Kenpo. Personal fulfillment has to come first. For job fulfillment and what excites me, I imagine a point in the future where everyone can program. This isn't so much about using Fortran and C#, but instead another definition of "program." It sounds strange, but let me explain: Everyone who graduates from high school has done some programming—even if it's something simple like a PHP Web site. These are basic skills now—just like I learned how to do long division by hand (although I would argue that students of today can't do long division anymore). These casual programmers will enter the workforce. Maybe we need to broaden our definition of "program." What's the number one "programming tool" for business professionals? [Microsoft Office] PowerPoint. If business professionals can use [Office] PowerPoint, I wonder whether we can nudge them into another tool to do business modeling. They already do business modeling, but they do it by using documents that get handed to programmers. Programmers guess what the documents mean, and bad things happen when programmers guess. I wonder whether we can do something cleverer. In business schools, they teach a discipline called structured English and various diagramming techniques. Maybe these could form the basis for programming business services. Job fulfillment for me would be thinking about how we change the fundamental nature of the Web. Web 2.0, mash-ups, and feeds are interesting, but they are step one of a two-step process. The Web today is a push model. People write content that is pushed out to people who read it. Programmers write Web applications that end users "use." People write mash-ups or scripts to access the "pushed" content. These applications run on the PC today, but I believe that they could migrate into the Internet "cloud." The Internet now becomes the programmable Internet and can run my applications for me. The tag line is, "The Internet is the computer." We see this in nascent places already—with Google, Amazon.com, MSN, and so on all now having callable services. Together with a broad range of programming skills for everyone, I see a blurring between the personal and business environment. That's what I really care about.
More on Donald Ferguson's CareerDr. Donald Ferguson is a Microsoft Technical Fellow in Platforms and Strategy in the Office of the CTO. Don focuses on both the evolutionary and revolutionary roles of information technology in business. Microsoft expects that he will be involved in a variety of forward-looking projects. Prior to Joining Microsoft, Don was an IBM Fellow and Chief Architect for IBM's Software Group (SWG). Don provided overall technical leadership for WebSphere, Tivoli, DB2, Rational, and Lotus products. He also chaired the SWG Architecture Board (SWG AB). The SWG AB focused on product integration, cross-product initiatives, and emerging technology. Some of the public focus areas were Web services, patterns, Web 2.0, and business-driven development. Don guided IBM's strategy and architecture for SOA and Web services, and coauthored many of the initial Web service specifications. This article was published in the Architecture Journal, a print and online publication produced by Microsoft. For more articles from this publication, please visit the Architecture Journal Web site. March 21 Talking about 服务站: WCF 消息传递基础
Quote 服务站: WCF 消息传递基础 March 09 谈论 WCF Essentials: What You Need To Know About One-Way Calls, Callbacks, And Events
引用 Object and component-oriented programming have only one way for clients to call a method, but Windows October 18 广告...感兴趣的联系我首先感谢您一直以来对Windows Live Expo的关注与兴趣!现在,我们诚邀您试用Windows Live Expo China Beta版(http://cn.expo.live.com)! “Beta”就是还没有最终完成的意思,这个阶段主要进行测试,为产品向公众发布作准备。 立刻点击下面的Join Now 链接,赶快加入我们(当然,你必须首先有一个.Net Passport账户)。如果您想更详细的了解Expo,请仔细阅读以下信息。
Expo是Microsoft为满足日益发展的社交网络市场需求而推出的一款全新产品。通过将社交网络整合到分类广告的概念中,Windows Live Expo将传统的分类广告服务提升到一个新的水平。 Expo不仅仅限于出售产品。它是一个动态的社会信息服务系统。用户可在这里买卖商品,获得信息,寻求合作。而这一切服务都是完全免费的。
Expo在美国已经对公众正式发布了。现在Expo项目组需要您测试我们在中国的服务。在Expo中国站点正式向公众发布之前,我们需要您,作为Beta版的测试者,在Expo上发布分类信息,并给予我们使用反馈。
2.提交反馈
亲爱的朋友, 马上行动起来,点击上面的“立即加入”按钮,开始你的Expo之旅。
|
|
|