??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品自拍视频,欧美一区二三区,视频一区在线免费观看http://www.aygfsteel.com/Titan/category/5381.html用文字来整理生命zh-cnTue, 27 Feb 2007 12:35:23 GMTTue, 27 Feb 2007 12:35:23 GMT60B+?wi)的研?/title><link>http://www.aygfsteel.com/Titan/articles/30387.html</link><dc:creator>Titan</dc:creator><author>Titan</author><pubDate>Sun, 12 Feb 2006 15:12:00 GMT</pubDate><guid>http://www.aygfsteel.com/Titan/articles/30387.html</guid><wfw:comment>http://www.aygfsteel.com/Titan/comments/30387.html</wfw:comment><comments>http://www.aygfsteel.com/Titan/articles/30387.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/Titan/comments/commentRss/30387.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/Titan/services/trackbacks/30387.html</trackback:ping><description><![CDATA[<TABLE height="100%" cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD vAlign=top align=middle> <TABLE cellSpacing=0 cellPadding=0 width="92%" border=0> <TBODY> <TR> <TD class=text align=left> <P><B></B>1、B+?wi)烦引的Ml构<BR>①B<SUP>+</SUP>?wi)烦引是一个多U烦引,但是其结构不同于多序索引Q?BR>②B<SUP>+</SUP>?wi)烦引采用^衡树(wi)l构Q即每个叶结点到根的路径长度都相同;<BR>③每个非叶l点?IMG height=14 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/title/08/02.gif" width=29>到n个子奻In对特定的?wi)是固定的?BR>④B<SUP>+</SUP>?wi)的所有结点结构都相同Q它最多包含n-1个搜索码值K<FONT size=-5>1</FONT>、K<FONT size=-5>2</FONT>、…、K<FONT size=-5>n-1</FONT>Q以?qing)n个指针P<FONT size=-5>1</FONT>、P<FONT size=-5>2</FONT>、…、P<FONT size=-5>n</FONT>Q每个结点中的搜索码值按ơ序存放Q即如果i<jQ那么Ki<KjQ如<span id="wmqeeuq" class=part>?-3-1</SPAN>所C?BR></P></TD></TR> <TR> <TD class=text align=left> <DIV align=center><span id="wmqeeuq" class=part>?-3-1QB<SUP>+</SUP>?wi)的l点l构 </SPAN><BR><IMG height=34 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/chapter/08/8-3-1.gif" width=420> </DIV></TD></TR> <TR> <TD class=text align=left><span id="wmqeeuq" class=part>2、B<SUP>+</SUP>?wi)烦引的叶结?/SPAN><BR>①指针Pi(i=1,2,?n-1)指向h搜烦码值Ki的一个文件记录或一个指针(存储Q桶Q桶中的每个指针指向h搜烦码值Ki的一个文件记录。指针桶只在文g不按搜烦码顺序物理存储时才用。指针PnhҎ(gu)的作用;<BR>②每个叶结Ҏ(gu)多可有n-1个搜索码|最也要有<IMG height=20 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/title/08/04.gif" width=60 align=absMiddle>个搜索码倹{各个叶l点中搜索码值的范围互不怺。要使B+?wi)烦引成为稠密烦引,数据文g中的各搜索码值都必须出现在某个叶l点中且只能出现一ơ;<BR>③׃各叶l点按照所含的搜烦码值有一个线性顺序,所以就可以利用各个叶结点的指针Pn叶l点按搜索码序链接在一赗这U排序能够高效地Ҏ(gu)件进行顺序处理,而B<SUP>+</SUP>?wi)烦引的其他l构能够高效地对文gq行随机处理Q如<span id="wmqeeuq" class=part>?-3-2</SPAN>所C?BR></TD></TR> <TR> <TD class=text align=left> <DIV align=center><span id="wmqeeuq" class=part>?-3-2QB+?wi)烦引的叶结点结构示?/SPAN> <BR><IMG height=160 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/chapter/08/8-3-2.gif" width=420> </DIV></TD></TR> <TR> <TD class=text align=left><span id="wmqeeuq" class=part>3、B<SUP>+</SUP>?wi)烦引的非叶l点</SPAN><BR>①B<SUP>+</SUP>?wi)烦引的非叶l点形成叶结点上的一个多U(E疏)索引Q?BR>②非叶l点的结构和叶结点的l构相同Q即含有能够存储n-1个搜索码值和n个指针的存储单元的数据结构。只不过非叶l点中的所有指针都指向?wi)中的结点?BR>③如果一个非叶结Ҏ(gu)m个指针,?IMG height=14 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/title/08/02.gif" width=29>≤m≤n。若m<nQ则非叶l点中指针Pm之后的所有空闲空间作为预留空_(d)与叶l点的区别在于结点的最后一个指针Pm和Pn的位|与指向不同Q如<span id="wmqeeuq" class=part>?-3-3</SPAN>所C;<BR></TD></TR> <TR> <TD class=text align=left> <DIV align=center><span id="wmqeeuq" class=part>?-3-3QB+?wi)烦引的非叶l点l构 </SPAN><BR><IMG height=80 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/chapter/08/8-3-3.gif" width=420> </DIV></TD></TR> <TR> <TD class=text align=left>④在一个含有m个指针的非叶l点中,指针P<FONT size=-5>i</FONT>(i=2,?m-1)指向一子?wi),该子树(wi)的所有结点的搜烦码值大于等于K<FONT size=-5>i-1</FONT>而小于K<FONT size=-5>i</FONT>。指针Pm指向子树(wi)中所含搜索码值大于等于K<FONT size=-5>m-1</FONT>的那一部分Q而指针P<FONT size=-5>1</FONT>指向子树(wi)中所含搜索码值小于K<FONT size=-5>1</FONT>的那一部分Q如<span id="wmqeeuq" class=part>?-3-4</SPAN>所C?BR></TD></TR> <TR> <TD class=text align=left> <div id="wmqeeuq" class=part align=center>?-3-4QB<SUP>+</SUP>?wi)烦引的非叶l点中指针Pi的指?BR><IMG height=106 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/chapter/08/8-3-4.gif" width=420> </DIV></TD></TR> <TR> <TD class=text align=left><span id="wmqeeuq" class=part>4、B<SUP>+</SUP>?wi)烦引的根结?/SPAN><BR>①根结点的l构也与叶结点相同;<BR>②根结点包含的指针数可以小?IMG height=14 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/title/08/02.gif" width=29>。但是,除非整棵?wi)只有一个结点,否则根结点必至包含两个指针?SPAN class=part>?-3-5</SPAN>l出一个B<SUP>+</SUP>?wi)结构的C意图。?BR></TD></TR> <TR> <TD class=text align=left> <DIV align=center><span id="wmqeeuq" class=part>?-3-5Qaccount关系的B<SUP>+</SUP>?wi)烦引结?</SPAN><BR><IMG height=134 src="http://www.nuist.edu.cn/courses/jsj/GD_jsj_013b/image/chapter/08/8-3-5.gif" width=420><BR></DIV></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><img src ="http://www.aygfsteel.com/Titan/aggbug/30387.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/Titan/" target="_blank">Titan</a> 2006-02-12 23:12 <a href="http://www.aygfsteel.com/Titan/articles/30387.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Z索引的SQL语句优化之降龙十八掌http://www.aygfsteel.com/Titan/articles/26467.htmlTitanTitanTue, 03 Jan 2006 12:26:00 GMThttp://www.aygfsteel.com/Titan/articles/26467.htmlhttp://www.aygfsteel.com/Titan/comments/26467.htmlhttp://www.aygfsteel.com/Titan/articles/26467.html#Feedback0http://www.aygfsteel.com/Titan/comments/commentRss/26467.htmlhttp://www.aygfsteel.com/Titan/services/trackbacks/26467.html阅读全文

Titan 2006-01-03 20:26 发表评论
]]>
[转]B-tree algorithmshttp://www.aygfsteel.com/Titan/articles/26466.htmlTitanTitanTue, 03 Jan 2006 12:24:00 GMThttp://www.aygfsteel.com/Titan/articles/26466.htmlhttp://www.aygfsteel.com/Titan/comments/26466.htmlhttp://www.aygfsteel.com/Titan/articles/26466.html#Feedback1http://www.aygfsteel.com/Titan/comments/commentRss/26466.htmlhttp://www.aygfsteel.com/Titan/services/trackbacks/26466.htmlB-tree algorithms

A B-tree is a data structure that maintains an ordered set of data and allows efficient operations to find, delete, insert, and browse the data. In this discussion, each piece of data stored in a B-tree will be called a "key", because each key is unique and can occur in the B-tree in only one location.

A B-tree consists of "node" records containing the keys, and pointers that link the nodes of the B-tree together.

Every B-tree is of some "order n", meaning nodes contain from n to 2n keys, and nodes are thereby always at least half full of keys. Keys are kept in sorted order within each node. A corresponding list of pointers are effectively interspersed between keys to indicate where to search for a key if it isn't in the current node. A node containing k keys always also contains k+1 pointers.

For example, here is a portion of a B-tree with order 2 (nodes have at least 2 keys and 3 pointers). Nodes are delimited with [square brackets]. The keys are city names, and are kept sorted in each node. On either side of every key are pointers linking the key to subsequent nodes:

           Start here
           | 
           v 
           [ Chicago Hoboken ]  
            |       |       | 
+-----------+       |       +------------+
|                   |                    |
v                   v                    v
[ Aptos Boston ]    [ Denver Detroit ]   [ San-Jose Seattle ]
 |     |      |      |      |       |     |        |       |
 v     v      v      v      v       v     v        v       v
                     X

To find the key "Dallas", we begin searching at the top "root" node. "Dallas" is not in the node but sorts between "Chicago" and "Hoboken", so we follow the middle pointer to the next node. Again, "Dallas" is not in the node but sorts before "Denver", so we follow that node's first pointer down to the next node (marked with an "X"). Eventually, we will either locate the key, or encounter a "leaf" node at the bottom level of the B-tree with no pointers to any lower nodes and without the key we want, indicating the key is nowhere in the B-tree.

Below is another fragment of an order 1 B-tree (nodes have at least 1 key and 2 pointers). Searching for the key "Chicago" begins at "Marin", follows the first pointer to "Aptos" (since Chicago sorts before Marin), then follows that node's second pointer down to the next level (since Chicago sorts after Aptos), as marked with an "X".

          | 
          v 
      [ Marin ]  
       |     |
    +--+     +---+
    |            |
    v            v
[ Aptos ]   [ Seattle ]
 |     |     |       |
 v     v     v       v 
       X

Searching a B-tree for a key always begins at the root node and follows pointers from node to node until either the key is located or the search fails because a leaf node is reached and there are no more pointers to follow.

B-trees grow when new keys are inserted. Since the root node initially begins with just one key, the root node is a special exception and the only node allowed to have less than n keys in an order n B-tree.

Here is an order 2 B-tree with integer keys. Except for the special root node, order 2 requires every node to have from 2 to 4 keys and 3 to 5 pointers. Empty slots are marked with ".", showing where future keys have not yet been stored in the nodes:

                       [ 57 . . .]
                        |  |
        +---------------+  +---------------------+
        |                                        |
        v                                        v
        [ 14 40 . .]                             [ 72 84 . .]
         |  |  |                                  |  |  |
+--------+  |  +----------+            +----------+  |  +-----------+
|           |             |            |             |              |
v           v             v            v             v              v
[01 12 . .] [15 16 17 .]  [47 56 . .]  [58 60 61 .]  [74 75 76 78]  [85 86 99 .]

To insert the key "59", we first simply search for that key. If 59 is found, the key is already in the tree and the insertion is superfluous. Otherwise, we must end up at a leaf node at the bottom level of the tree where 59 would be stored. In the above case, the leaf node contains 58, 60, 61, and room for a fourth key, so 59 is simply inserted in the leaf node in sorted order:
[58 59 60 61]

Now we'll insert the key "77". The initial search leads us to the leaf node where 77 would be inserted, but the node is already full with 4 keys: 74, 75, 76, and 78. Adding another key would violate the rule that order 2 B-trees can't have more than 4 keys. Because of this "overflow" condition, the leaf node is split into two leaf nodes. The leftmost 2 keys are put in the left node, the rightmost 2 keys are put in the right node, and the middle key is "promoted" by inserting it into the parent node above the leaf. Here, inserting 77 causes the 74-75-76-78 node to be split into two nodes, and 76 is moved up to the parent node that contained 72 and 84:
Before inserting 77           After inserting 77

[ 72 84 . .]                    [ 72 76 84 .]
 |  |  |                         |  |  |  |
-+  |  +-                      --+  |  |  +--
    |                               |  |
    |                          +----+  +------+
    |                          |              |
    v                          v              v
    [74 75 76 78]              [74 75 . .]    [77 78 . .]

In this case, the parent node contained only 2 keys (72 and 84), leaving room for 76 to be promoted and inserted. But if the parent node was also already full with 4 keys, then it too would have to split. Indeed, splitting may propagate all the way up to the root node. When the root splits, the B-tree grows in height by one level, and a new root with a single promoted key is formed. (A situation when an order n root node sometimes has fewer than n keys, just like the situation described earlier when the root node stores the very first key placed in the B-tree.)

B-trees shrink when keys are deleted. To delete a key, first perform the usual search operation to locate the node containing the key. (If the key isn't found, it isn't in the tree and can't be deleted.)

If the found key is not in a leaf, move it to a leaf by swapping the key with the logical "next" key. In a B-tree, the "next" key is always the first key in the leftmost leaf of the right subtree.

For example, in this B-tree we want to delete "37", which is not in a leaf. "xx" indicates key values that don't matter:

[ xx 37 xx xx ]
       |
       |
       +->[ xx xx xx xx ]
           |
           |
           +->[ xx xx xx xx ]
               |
               |
               +->[41 43 . .]

We follow the pointer immediately to the right of 37 to find 37's right subtree, then follow the leftmost pointers in each subnode until we reach a leaf. The first key in the leaf is "41", the logical "next" key after 37 in the list of all keys in the tree. By swapping 37 and 41, we can move 37 to a leaf node to set up a deletion without violating the key order or pointer order of the overall B-tree.

Once the key we want is in a leaf, we can delete it. If at least n keys remain in the node, we're done, otherwise it is an "underflow", since every node (except the root) must have at least n keys.

If a node underflows, we may be able to "redistribute" keys by borrowing some from a neighboring node. For example, in the order 3 B-tree below, the key 67 is being deleted, which causes a node to underflow since it only has keys 66 and 88 left. So keys from the neighbor on the left are "shifted through" the parent node and redistributed so both leaf nodes end up with 4 keys:

   Before deleting 67                         After deleting 67

     [ xx 55 xx ]                               [ xx 33 xx ]
         |  |                                       |  |
+--------+  +--------+                     +--------+  +------+
|                    |                     |                  |
v                    v                     v                  v
[22 24 26 28 33 44]  [66 67 88 . . .]      [22 24 26 28 . .]  [44 55 66 88 . .]

But if the underflow node and the neighbor node have less than 2n keys to redistribute, the two nodes will have to be combined. For example, here key 52 is being deleted from the B-tree below, causing an underflow, and the neighbor node can't afford to give up any keys for redistribution. So one node is discarded, and the parent key moves down with the other keys to fill up a single node:
Before deleting 52          After deleting 52

  [ 35 45 55 . ]              [ 35 55 . . ]
   |  |  |  |                  |  |  |
  -+  |  |  +-                -+  |  +-
      |  |                        |
+-----+  +---+                    |
|            |                    |
v            v                    v
[40 42 . .]  [50 52 . .]          [40 42 45 50]

In the above case, moving the key 45 out of the parent node left two keys (35 and 55) remaining. But if the parent node only had n keys to begin with, then the parent node also would underflow when the parent key was moved down to combine with the leaf key. Indeed, underflow and the combining of nodes may propagate all the way up to the root node. When the root underflows, the B-tree shrinks in height by one level, and the nodes under the old root combine to form a new root.

The payoff of the B-tree insert and delete rules are that B-trees are always "balanced". Searching an unbalanced tree may require traversing an arbitrary and unpredictable number of nodes and pointers.

An unbalanced tree of 4 nodes              A balanced tree of 4 nodes

[ x x ]                                             [ x x ]
    |                                                | | |
    [ x x ]                                   +------+ | +------+
        |                                     |        |        |
        [ x x ]                               [ x x ]  [ x x ]  [ x x ]
            |
            [ x x ]

Searching a balanced tree means that all leaves are at the same depth. There is no runaway pointer overhead. Indeed, even very large B-trees can guarantee only a small number of nodes must be retrieved to find a given key. For example, a B-tree of 10,000,000 keys with 50 keys per node never needs to retrieve more than 4 nodes to find any key.
B-TREE-P copyright © 1987-2000 by Semaphore Corporation

Titan 2006-01-03 20:24 发表评论
]]>
ORACLE索引与高性能SQL介绍http://www.aygfsteel.com/Titan/articles/24433.htmlTitanTitanSat, 17 Dec 2005 16:09:00 GMThttp://www.aygfsteel.com/Titan/articles/24433.htmlhttp://www.aygfsteel.com/Titan/comments/24433.htmlhttp://www.aygfsteel.com/Titan/articles/24433.html#Feedback0http://www.aygfsteel.com/Titan/comments/commentRss/24433.htmlhttp://www.aygfsteel.com/Titan/services/trackbacks/24433.html  什么是索引
  
  索引是徏立在表的一列或多个列上的辅助对象,目的是加快访问表中的数据Q?BR>  
  Oracle存储索引的数据结构是B*?wi),位图索引也是如此Q只不过是叶子节点不同B*数烦引;
  
  索引由根节点、分支节点和叶子节点l成Q上U烦引块包含下索引块的索引数据Q叶节点包含索引数据和确定行实际位置的rowid?BR>  
  使用索引的目?BR>  加快查询速度
  减少I/O操作
  消除盘排序
  
  何时使用索引
  查询q回的记录数
  排序?lt;40%
  非排序表 <7%
  表的片较多Q频J增加、删除)
  
  索引的种c?BR>  非唯一索引Q最常用Q?BR>  唯一索引
  位图索引
  局部有前缀分区索引
  局部无前缀分区索引
  全局有前~分区索引
  散列分区索引
  Z函数的烦?BR>  
  理索引的准?BR>  
  在表中插入数据后创徏索引
  

  。在用SQL*Loader或import工具插入或装载数据后Q徏立烦引比较有效;
  
  索引正确的表和列
  
  。经常检索排序大表中40%或非排序?%的行Q徏议徏索引Q?BR>  。ؓ(f)了改善多表关联,索引列用于联l;
  。列中的值相Ҏ(gu)较唯一Q?BR>  。取D_(d)大:(x)B*?wi)烦引,?x)位图索引Q;
  。Date型列一般适合Z函数的烦引;
  。列中有许多I|不适合建立索引
  
  为性能而安排烦引列
  
  。经怸起用多个字D|索记录,l合索引比单索引更有效;
  。把最常用的列攑֜最前面Q例Qdx_groupid_serv_id(groupid,serv_id)Q在where条g中用groupid或groupid,serv_idQ查询将使用索引Q若仅用到serv_id字段Q则索引无效Q?BR>  。合q?拆分不必要的索引?BR>  
  限制每个表烦引的数量
  
  。一个表可以有几百个索引Q你?x)这样做吗?Q,但是对于频繁插入和更新表Q烦引越多系lCPUQI/O负担p重;
  。徏议每张表不超q?个烦引?BR>  
  删除不再需要的索引
  
  。烦引无效,集中表现在该使用Z函数的烦引或位图索引Q而用了B*?wi)烦引?BR>  。应用中的查询不使用索引Q?BR>  。重建烦引之前必d删除索引Q若用alter index ?rebuild重徏索引Q则不必删除索引?BR>  
  索引数据块空间?/B>
  
  。创建烦引时指定表空_(d)特别是在建立主键Ӟ应明指定表I间Q?BR>  。合理设定pctfressQ注意:(x)不能l烦引指定pctusedQ?BR>  。估计烦引的大小和合理地讄存储参数Q默认ؓ(f)表空间大,或initial与next讄成一样大?BR>  
  考虑q行创徏索引
  
  。对大表可以采用q行创徏索引Q在q行创徏索引Ӟ存储参数被每个查询服务器q程分别使用Q例如:(x)initial?MQƈ行度?Q则创徏索引期间臛_要消?MI间Q?BR>  
  考虑用nologging创徏索引
  
  。对大表创徏索引可以使用nologging来减重做日志;
  。节省重做日志文件的I间Q?BR>  。羃短创建烦引的旉Q?BR>  。改善了q行创徏大烦引时的性能?BR>  
  怎样建立最佳烦?/B>
  
  明确地创建烦?BR>  create index index_name on table_name(field_name)
  tablespace tablespace_name
  pctfree 5
  initrans 2
  maxtrans 255
  storage
  (
  minextents 1
  maxextents 16382
  pctincrease 0
  );
  
  创徏Z函数的烦?/B>
  
  。常用与UPPER、LOWER、TO_CHAR(date){函数分cMQ例Q?BR>  create index idx_func on emp (UPPER(ename)) tablespace tablespace_name;
  
  创徏位图索引
  
  。对基数较小Q且基数相对E_的列建立索引Ӟ首先应该考虑位图索引Q例Q?BR>  create bitmap index idx_bitm on class (classno) tablespace tablespace_name;
  
  明确地创建唯一索引
  
  。可以用create unique index语句来创建唯一索引Q例Q?BR>  create unique index dept_unique_idx on dept(dept_no) tablespace idx_1;
  
  创徏与约束相关的索引
  
  。可以用using index字句Qؓ(f)与unique和primary keyU束相关的烦引,例如Q?BR>  alter table table_name
  add constraint PK_primary_keyname primary key (field_name)
  using index tablespace tablespace_nameQ?BR>  
  如何创徏局部分区烦?/B>
  
  。基表必L分区表;
  。分区数量与基础表相同;
  。每个烦引分区的子分区数量与相应的基表分区相同;
  。基表的子分Z的行的烦引项Q被存储在该索引的相应的子分Z,例如:
  Create Index TG_CDR04_SERV_ID_IDX On TG_CDR04(SERV_ID)
  Pctfree 5
  Tablespace TBS_AK01_IDX
  Storage (
  MaxExtents 32768
  PctIncrease 0
  FreeLists 1
  FreeList Groups 1
  )
  local
  /
  
  如何创徏范围分区的全局索引
  
  。基表可以是全局表和分区表?BR>  create index idx_start_date on tg_cdr01(start_date)
  global partition by range(start_date)
  (partition p01_idx vlaues less than (?106?
  partition p01_idx vlaues less than (?111?
  ?BR>  partition p01_idx vlaues less than (?401?))
  /
  
  重徏现存的烦?/B>
  
  重徏现存的烦引的当前时刻不会(x)影响查询Q?BR>  
  重徏索引可以删除额外的数据块Q?BR>  
  提高索引查询效率Q?BR>  alter index idx_name rebuild nologging;
  
  对于分区索引Q?BR>  alter index idx_name rebuild partition partiton_name nologging;
  
  要删除烦引的原因
  
  。不再需要的索引Q?BR>  。烦引没有针对其相关的表所发布的查询提供所期望的性能改善Q?BR>  。应用没有用该烦引来查询数据Q?BR>  。该索引无效Q必d重徏之前删除该烦引;
  。该索引已经变的太碎了,必须在重Z前删除该索引Q?BR>  。语句:(x)drop index idx_name;drop index idx_name drop partition partition_name;
  
  建立索引的代?/B>
  
  基础表维护时Q系l要同时l护索引Q不合理的烦引将严重影响pȝ资源Q主要表现在CPU和I/O上;
  
  插入、更新、删除数据生大量db file sequential read锁等待;
  
  SQL优化器简?BR>  
  Z规则的优化器

  
  。L使用索引
  。L从驱动表开始(from子句最双的表Q?BR>  。只有在不可避免的情况下Q才使用全表扫描
  。Q何烦引都可以
  
  Z成本的优化器
  
  。需要表、烦引的l计资料
  Analyze table customer compute statistics;
  Analyze table customer estimate statistics sample 5000 rows;
  。表中设|ƈ行度、表分区
  
  优化器模?BR>  
  rule模式
  
  。d略CBO和统计信息而基于规?BR>  choose模式
  
  。OracleҎ(gu)情况选择rule or first_rows or all_rows
  first_rows 模式
  
  。基于成本,以最快的速度q回记录Q会(x)造成M查询速度的下降或消耗更多的资源Q們֐索引扫描Q适合OLTPpȝ
  all_rows模式
  
  。基于成本,保M查询旉最短,們֐q行全表扫描
  
  例如Q?BR>  Select last_name from customer order by last_name;用first_rowsӞq速返回记录,但I/O量大Q用all_rowsӞq回记录慢,但用资源少?BR>  
  调整SQL表访?/B>
  
  全表扫描
  
  。返回记录:(x)未排序表>40%Q排序表>7%Q徏议采用ƈ行机制来提高讉K速度QDDSQ?BR>  
  索引讉K
  
  。最常用的方法,包括索引唯一扫描和烦引范围扫描,OLTPQ?BR>  
  快速完全烦引扫?BR>  
  。访问烦引中所有数据块Q结果相当于全表扫描Q可以用索引扫描代替全表扫描Q例如:(x)
  
  Select serv_id,count(* ) from tg_cdr01 group by serv_id;
  
  评估全表扫描的合法?BR>  
  如何实现q行扫描
  
  。永久ƈ行化Q不推荐Q?BR>  alter table customer parallel degree 8;
  
  。单个查询ƈ行化
  select /*+ full(emp) parallel(emp,8)*/ * from emp;
  
  分区表效果明?BR>  
  优化SQL语句排序
  
  排序的操作:(x)
  
  。order by 子句
  。group by 子句
  。select distinct子句
  。创建烦引时
  。union或minus
  。排序合q连?BR>  
  如何避免排序
  
  。添加烦?BR>  。在索引中用distinct子句
  。避免排序合q连?BR>  
  使用提示q行调整
  
  使用提示的原?BR>  
  。语法:(x)/*+ hint */
  。用表别名:select /*+ index(e dept_idx)*/ * from emp e
  。检验提C?BR>  
  常用的提C?BR>  
  。rule
  。all_rows
  。first_rows
  。use_nl
  。use_hash
  。use_merge
  。index
  。index_asc
  。no_index
  。index_descQ常用于使用max内置函数Q?BR>  。index_combine(强制使用位图索引)
  。index_ffsQ烦引快速完全扫描)
  。use_concat(查询中所有or条g使用union all)
  。parallel
  。noparallel
  。full
  。orderedQ基于成本)
  
  调整表连?/B>
  
  表连接的cd
  
  。等q接
  where 条g中用{式q接Q?BR>  。外部连接(左、右q接Q?BR>  
  在where条g子句的等式谓词放|一?+)来实玎ͼ例如Q?BR>  select a.ename,b.comm from emp a,bonus b where a.ename=b.ename(+);
  
  该语句返回所有emp表的记录Q?BR>  。自q接
   Select a.value total, B.value hard, (A.value - b.value) soft ,
  Round((b.value/a.value)*100,1) perc
  From v$sysstat a,v$sysstat b
  Where a.statistic# = 179
  and B.statistic# = 180;
  
  反连?BR>  
  反连接常用于not in or not exists中,是指在查询中扑ֈ的Q何记录都不包含在l果集中的子查询Q不使用not in or not exists;
  
  。半q接
  
  查询中用existsQ含义:(x)即在子查询中返回多条重复的记录Q外部查询也只返回一条记录?BR>  
  嵌套循环q接
  
  。被q接表中存在索引的情况下使用Q?BR>  。用use_nl?BR>  
  hashq接
  
  。Hashq接驱动表加蝲在内存中Qƈ使用hash技术连接第二个表,提高{连接速度?BR>  。适合于大表和表q接Q?BR>  。用use_hash?BR>  
  排序合ƈq接
  
  。排序合q连接不使用索引
  。用原则:(x)
  
  q接表子D中不存在可用烦引;
  
  查询q回两个表中大部分的数据快;
  
  CBO认ؓ(f)全表扫描比烦引扫描执行的更快?BR>  
  。用use_merge
  
  使用临时/中间?/B>
  
  多个大表兌Ӟ可以分别把满x件的l果集存攑ֈ中间表,然后用中间表兌Q?BR>  
  SQL子查询的调整
  
  兌与非兌子查?BR>  
  。关联:(x)子查询的内部引用的是外部表,每行执行一ơ;
  。非兌Q子查询只执行一ơ,存放在内存中?BR>  
  调整not in 和not exists语句
  
  。可以用外部连接优化not in子句Q例如:(x)
  select ename from emp where dept_no not in
  (select dept_no from dept where dept_name =‘Math?;
  
  改ؓ(f)Q?BR>  select ename from emp,dept
  where emp.dept_no=dept.dept_no
  and dept.dept_name is null;
  
  使用索引调整SQL
  
  Oracle Z么不使用索引
  
  。检查被索引的列或组合烦引的首列是否出现在PL/SQL语句的WHERE子句中,q是“执行计划”能用到相关索引的必要条件?BR>  
  。看采用了哪U类型的q接方式。ORACLE的共有Sort Merge JoinQSMJQ、Hash JoinQHJQ和Nested Loop JoinQNLQ。在两张表连接,且内表的目标列上建有索引Ӟ只有Nested Loop才能有效地利用到该烦引。SMJ即相关列上建有索引Q最多只能因索引的存在,避免数据排序q程。HJ׃dHASHq算Q烦引的存在Ҏ(gu)据查询速度几乎没有影响?BR>  
  。看q接序是否允许使用相关索引。假设表emp的deptno列上有烦引,表dept的列deptno上无索引QW(xu)HERE语句有emp.deptno=dept.deptno条g。在做NLq接Ӟemp做ؓ(f)外表Q先被访问,׃q接机制原因Q外表的数据讉K方式是全表扫描,emp.deptno上的索引昄是用不上Q最多在其上做烦引全扫描或烦引快速全扫描?BR>  
  。是否用到系l数据字典表或视图。由于系l数据字典表都未被分析过Q可能导致极差的“执行计划”。但是不要擅自对数据字典表做分析Q否则可能导致死锁,或系l性能下降?BR>  
  。烦引列是否函数的参数。如是,索引在查询时用不上?BR>  
  。是否存在潜在的数据cd转换。如字W型数据与数值型数据比较QORACLE?x)自动将字符型用to_number()函数q行转换Q从而导致上一U现象的发生?BR>  
  。是否ؓ(f)表和相关的烦引搜集够的l计数据。对数据l常有增、删、改的表最好定期对表和索引q行分析Q可用SQL语句“analyze table xxxx compute statistics for all indexes;”。ORACLE掌握了充分反映实际的l计数据Q才有可能做出正的选择?BR>  
  。烦引列的选择性不高?  我们假设典型情况Q有表empQ共有一百万行数据,但其中的emp.deptno列,数据只有4U不同的|?0?0?0?0。虽然emp数据行有很多QORACLE~省认定表中列的值是在所有数据行均匀分布的,也就是说每种deptno值各?5万数据行与之对应。假设SQL搜烦条gDEPTNO=10Q利用deptno列上的烦引进行数据搜索效率,往往不比全表扫描的高?BR>  
  。烦引列值是否可为空QNULLQ。如果烦引列值可以是I|在SQL语句中那些要q回NULL值的操作Q将不会(x)用到索引Q如COUNTQ?Q,而是用全表扫描。这是因为烦引中存储g能ؓ(f)全空?BR>  
  。看是否有用到ƈ行查询(PQOQ。ƈ行查询将不会(x)用到索引?BR>  
  。如果从以上几个斚w都查不出原因的话Q我们只好用采用在语句中加hint的方式强制ORACLE使用最优的“执行计划”? hint采用注释的方式,有行注释和段注释两种方式? 如我们想要用到A表的IND_COL1索引的话Q可采用以下方式Q? “SELECT /*+ INDEXQA IND_COL1Q?/ * FROM A WHERE COL1 = XXX;"
  
  如何屏蔽索引
  
  语句的执行计划中有不良烦引时Q可以h为地屏蔽该烦引,Ҏ(gu)Q?BR>  
  。数值型Q在索引字段上加0Q例?BR>  select * from emp where emp_no+0 = v_emp_no;
  
  。字W型Q在索引字段上加‘’,例如
  select * from tg_cdr01 where msisdn||’?v_msisdn;

Titan 2005-12-18 00:09 发表评论
]]>
关于三种JOIN的理?http://www.aygfsteel.com/Titan/articles/24432.htmlTitanTitanSat, 17 Dec 2005 16:06:00 GMThttp://www.aygfsteel.com/Titan/articles/24432.htmlhttp://www.aygfsteel.com/Titan/comments/24432.htmlhttp://www.aygfsteel.com/Titan/articles/24432.html#Feedback0http://www.aygfsteel.com/Titan/comments/commentRss/24432.htmlhttp://www.aygfsteel.com/Titan/services/trackbacks/24432.html  
  步骤Q确定一个驱动表(outer table)Q另一个表为inner tableQ驱动表中的每一行与inner表中的相应记录JOIN。类g个嵌套的循环。适用于驱动表的记录集比较?yu)?lt;10000Q而且inner表需要有有效的访问方法(IndexQ。需要注意的是:(x)JOIN的顺序很重要Q驱动表的记录集一定要,q回l果集的响应旉是最快的?BR>  
  cost = outer access cost + (inner access cost * outer cardinality)
  
  |  2 |  NESTED LOOPS        |       |   3 |  141 |   7 (15)|
  |  3 |  TABLE ACCESS FULL     | EMPLOYEES  |   3 |  60 |   4 (25)|
  |  4 |  TABLE ACCESS BY INDEX ROWID| JOBS     |  19 |  513 |   2 (50)|
  |  5 |   INDEX UNIQUE SCAN     | JOB_ID_PK  |   1 |    |      |
  
  EMPLOYEES为outer table, JOBS为inner table.
  
  Hash join
  
  步骤Q将两个表中较小的一个在内存中构造一个HASH表(对JOIN KEYQ,扫描另一个表Q同样对JOIN KEYq行HASH后探是否可以JOIN。适用于记录集比较大的情况。需要注意的是:(x)如果HASH表太大,无法一ơ构造在内存中,则分成若q个partitionQ写入磁盘的temporary segmentQ则?x)多一个写的代P?x)降低效率?BR>  
  cost = (outer access cost * # of hash partitions) + inner access cost
  --------------------------------------------------------------------------
  | Id | Operation      | Name    | Rows | Bytes | Cost (%CPU)|
  --------------------------------------------------------------------------
  |  0 | SELECT STATEMENT   |       |  665 | 13300 |   8 (25)|
  |  1 | HASH JOIN      |       |  665 | 13300 |   8 (25)|
  |  2 |  TABLE ACCESS FULL | ORDERS    |  105 |  840 |   4 (25)|
  |  3 |  TABLE ACCESS FULL | ORDER_ITEMS |  665 | 7980 |   4 (25)|
  --------------------------------------------------------------------------
  
  ORDERS为HASH TABLEQORDER_ITEMS扫描
  
  Sort merge join
  
  步骤Q将两个表排序,然后两个表合ƈ。通常情况下,只有在以下情况发生时Q才?x)用此UJOIN方式Q?BR>  
  1.RBO模式
  
  2.不等价关?>,<,>=,<=,<>)
  
  3.HASH_JOIN_ENABLED=false
  
  4.数据源已排序
  
  cost = (outer access cost * # of hash partitions) + inner access cost

Titan 2005-12-18 00:06 发表评论
]]>
SQL语句主要的连接方?/title><link>http://www.aygfsteel.com/Titan/articles/24430.html</link><dc:creator>Titan</dc:creator><author>Titan</author><pubDate>Sat, 17 Dec 2005 15:56:00 GMT</pubDate><guid>http://www.aygfsteel.com/Titan/articles/24430.html</guid><wfw:comment>http://www.aygfsteel.com/Titan/comments/24430.html</wfw:comment><comments>http://www.aygfsteel.com/Titan/articles/24430.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/Titan/comments/commentRss/24430.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/Titan/services/trackbacks/24430.html</trackback:ping><description><![CDATA[SQL语句主要的连接方?BR><BR>a) Nested-loop join<BR>适合于小?几千条,几万条记?与大表做联接<BR>在联接列上有索引?BR><BR>分内表和外表(驱动?Q靠qfrom子句的是内表。从效率上讲Q小表应该作外表Q大表应该作内表Q即大表查询时走索引?BR><BR>COST= Access cost of A(驱动? + (access cost of B * number of rows from A)<BR><BR>成本计算Ҏ(gu)Q?BR>讑ְ?00行,大表100000行?BR><BR>两表均有索引Q?BR>如果表在内Q大表在?驱动?的话Q则扫描ơ数为:(x)<BR>100000+100000*2 (其中2表示IOơ数Q一ơ烦引,一ơ数?<BR>如果大表在内Q小表在?驱动?的话Q则扫描ơ数为:(x)<BR>100+100*2.<BR><BR>两表均无索引Q?BR>如果表在内Q大表在外的话,则扫描次Cؓ(f)Q?BR>100000+100*100000<BR>如果大表在内Q小表在外的话,则扫描次Cؓ(f)Q?BR>100+100000*100<BR><BR>注意Q如果一个表有烦引,一个表没有索引QORACLE?x)将没有索引的表作驱动表。如果两个表都有索引Q则外表作驱动表。如果两个都没烦引的话,则也是外表作驱动表?BR><BR>基本的执行计划如下所C:(x)<BR>NESTED LOOPS<BR>           TABLE ACCESS (BY ROWID)  OF  our_outer_table<BR>                   INDEX (..SCAN) OF outer_table_index(?)<BR>           TABLE ACCESS (BY ROWID)  OF  our_inner_table<BR>             INDEX (..SCAN) OF inner_table_index(?)<BR><BR>b) Hash join <BR><BR>适合于大表与大表Q小?几十万,几百?与大表之间的联连?BR>联接列上不需要烦引?BR><BR>基本执行计划如下Q?BR>HASH JOIN<BR>              TABLE ACCESS (?)  OF  tableA<BR>              TABLE ACCESS (?)  OF  tableB<BR><BR>cost= (access cost of A * number of hash partitions of B) + access cost of B<BR><BR>可以看出主要成本在于A表是否可以被Cache。Hash_area_size的大将军_Hash Join的主要成本。可以看出Hash Join的成本和q回集合q没有直接的关系Q所以当q回l果集比较大的时候一般具有较好的性能?BR><BR>Z加快hash join的速度Q可以调大hash_area_size和pga_aggregate_targetQ默认ؓ(f)25MQ的倹{?BR><BR><BR>c) Sort Merge join<BR><BR>每一个Row Source在Join列上均排序?BR>然后两个排序后的Row Source合ƈ后,作一个结果集q回?BR>Sort/Merge Join仅仅对equal Join有效?BR><BR>基本执行计划<BR>MERGE (JOIN)<BR>        SORT (JOIN) <BR>                 TABLE ACCESS (?)  OF  tableA<BR>        SORT (JOIN) <BR>                 TABLE ACCESS (?)  OF  tableB<BR><BR>cost= access cost of A + access cost of B +(sort cost of A + sort cost of B)<BR><BR>可以看出Sort的成本是Merge Join的主要构成部分。这样sort_area_size的大将很大E度军_Merge Join的大。同样如果A表或者B表已l经q排序的Q那么Merge Join往往h很好的性能。其不会(x)走烦引?BR><BR>没有驱动表的概念Q即时响应能力较差?BR><img src ="http://www.aygfsteel.com/Titan/aggbug/24430.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/Titan/" target="_blank">Titan</a> 2005-12-17 23:56 <a href="http://www.aygfsteel.com/Titan/articles/24430.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转蝲]Effective SQL http://www.aygfsteel.com/Titan/articles/21744.htmlTitanTitanMon, 28 Nov 2005 15:06:00 GMThttp://www.aygfsteel.com/Titan/articles/21744.htmlhttp://www.aygfsteel.com/Titan/comments/21744.htmlhttp://www.aygfsteel.com/Titan/articles/21744.html#Feedback0http://www.aygfsteel.com/Titan/comments/commentRss/21744.htmlhttp://www.aygfsteel.com/Titan/services/trackbacks/21744.html前言Q?
Effective SQL
览了一遍EFFECTIVEpd书名Q似乎缺Effective SQL,所以有了一U莫名的冲动吧?
参考CSDN和博客堂的文档,加上以自q切n体会(x)ȝ出的一些EffectiveQ希望能够给大家带来一些帮助?
׃转蝲,整理的文章比较多,所以不一一指出出处,请原文作者多多谅?
{于作者水qx限,所以可能于实际中有较大出入Q望见谅?
如有不正之处Q请?qing)时与作者本pR谢谢!


正文Q?

一.名词解释Q?
0。SQL l构化查询语a(Structured Query Language)

1。非关系型数据库pȝ
做ؓ(f)W一代数据库pȝ的ȝQ其包括2U类型:(x)“层ơ”数据库与“网状”数据库

“层ơ”数据库理pȝ eg:IBM&IMS (Information  Management System)
特点:数据按层ơ模型组l?

"|状"数据?
特点Q数据按|状模型l织

2。关pd数据库系l?
关系性数据库理pȝ (RDBMS)
eg:SQL/DS , DB2, Oracle ,Informix ,Unity,dBASE{?
特点Q数据按二维的表格组l?

3。数据库(DataBase)
按一定结构存储在计算Z怺兌的数据的集合?

4。数据库理pȝDBMS(Database Management System)
一个通用的Y件系l。就是让你怎么理你的数据库。其中包括存储,安全Q完整性管理等?

5。数据库应用pȝDBAS QDatabase Application SystemQ?
数据库应用程序系l,建立在DBMS基础之上的。就是一个面向用L(fng)软gpȝ?

6。ANSI标准 QAmerican National Standards InstituteQ美国国家标准委员会(x)
因ؓ(f)1999q第2ơ更新SQLQ所以SQL又称为SQL99或SQL3Q第3版,?个版本分别ؓ(f)1986q的sql ,1992 q的sql2/sql92Q?

7。SQL语句?U类?
数据操作语句(Data Manipulation Language ) DML 关于数据操作命o(h)?nbsp; eg:select,insert,update,delete
数据定义语句(Data Definition Language ) DDL     关于数据对象讉K?nbsp; eg:createQ?drop
数据控制语句(Data Control Language) DCL         关于权限?nbsp; eg:grant Qrevoke

8。PL/SQL Procedural Language/sql
用于oracle的语a

9.T-SQL  transact-sql
用于 microsoft sql server 和sybase adaptive server

10。E.F.Codd关于关系型数据库12条检验原则(MYSQLQ不支持视图和原子事物处理,所以排除)
内容Q暂?

11。数据库设计之新奥尔良方法?
需求分?=》概念设?=》逻辑设计==》物理设?
4个步骤的具体中以需求分析最重要.
需求分析的内容:暂略
概念设计的内?暂略
逻辑设计的内?暂略
物理设计的内?暂略


?数据库优化方?
1.索引
一 概述

   可以利用索引快速访问数据库表中的特定信息。烦引是Ҏ(gu)据库表中一个或多个列的D行排序的l构?
   索引提供指针以指向存储在表中指定列的数据|然后Ҏ(gu)指定的排序次序排列这些指针?
   数据库用烦引的方式与用书的目录很怼Q通过搜烦索引扑ֈ特定的|
   然后跟随指针到达包含该值的?

索引是一个单独的、物理的数据库结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识q些值的数据늚逻辑指针清单?

一个表的存储是׃部分l成的,一部分用来存放表的数据面Q另一部分存放索引面。烦引就存放在烦引页面上

?索引的两U类型:(x)

聚集索引=集索引

聚集索引Z数据行的键值在表内排序和存储这些数据行。由于数据行按基于聚集烦引键的排序次序存储,
因此聚集索引Ҏ(gu)找行很有效。每个表只能有一个聚集烦引,因ؓ(f)数据行本w只能按一个顺序存储?
数据行本w构成聚集烦引的最低别?

只有当表包含聚集索引Ӟ表内的数据行才按排序ơ序存储。如果表没有聚集索引Q?
则其数据行按堆集方式存储?

聚集索引对于那些l常要搜索范围值的列特别有效。用聚集烦引找到包含第一个值的行后Q?
便可以确保包含后l烦引值的行在物理盔R。例如,如果应用E序执行的一个查询经常检索某一日期范围
内的记录Q则使用聚集索引可以q速找到包含开始日期的行,然后(g)索表中所有相?c)行?
直到到达l束日期。这h助于提高此类查询的性能。同P如果对从表中(g)索的数据q行排序?
l常要用到某一列,则可以将该表在该列上聚集Q物理排序)Q避免每ơ查询该列时都进行排序,
从而节省成?

非聚集烦?

非聚集烦引具有完全独立于数据行的l构。非聚集索引的最低行包含非聚集烦引的键|
q且每个键值项都有指针指向包含该键值的数据行。数据行不按Z非聚集键的次序存储?

在非聚集索引内,从烦引行指向数据行的指针UCؓ(f)行定位器?
行定位器的结构取决于数据늚存储方式是堆集还是聚集。对于堆集,行定位器是指向行的指针?
对于有聚集烦引的表,行定位器是聚集烦引键?
只有在表上创Z聚集索引Ӟ表内的行才按特定的顺序存储。这些行基于聚集烦引键按顺序存储?
如果一个表只有非聚集烦引,它的数据行将按无序的堆集方式存储
非聚集烦引可以徏多个,两者都能改善查询性能

非聚集烦引与聚集索引一h B ?wi)结构,但是有两个重大差别?x)
数据行不按非聚集索引键的序排序和存储?
非聚集烦引的叶层不包含数据页?
相反Q叶节点包含索引行。每个烦引行包含非聚集键g?qing)一个或多个行定位器Q?
q些行定位器指向有该键值的数据行(如果索引不唯一Q则可能是多行)?
非聚集烦引可以在有聚集烦引的表、堆集或索引视图上定?


聚集索引-->序表结?其物理数据和逻辑排序紧邻.
非聚集烦?->单链表结?L(fng)理和逻辑排序不按序排列.

打个比方.
一本字?你现在查一个陈?你有2U方?首先,你在知道他念chen的情况下L照拼韛_母去查找.他是排在字母A,B
于是你很Ҏ(gu)的就扑ֈ"??W?U方法则是按~旁查找,先找到x?LC个(f)时的~旁表在L"?q个?然后按照l出?
|扑ֈ相应的位|?
昄,W一U方法就是聚集烦?按照物理位置Ҏ(gu)排序来查?
W?U方法则是非聚集索引,按照一个(f)时烦引来查找.

另外
唯一索引

唯一索引可以保索引列不包含重复的倹{在多列唯一索引的情况下Q该索引可以保索引列中每个值组
合都是唯一的。唯一索引既是索引也是U束?

复合索引
索引Ҏ(gu)多个的就叫组合烦引,也叫复合索引。复合烦引用时需要注意烦引项的次序?

?索引的创?/P>

有两U方法可以在 SQL Server 内定义烦? CREATE INDEX 语句和CREATE TABLE 语句

CREATE TABLE支持在创建烦引时使用下列U束Q?/P>

PRIMARY KEY 创徏唯一索引来强制执行主?
UNIQUE 创徏唯一索引
CLUSTERED 创徏聚集索引
NONCLUSTERED 创徏非聚集烦?

? 1 定义索引Ӟ可以指定每列的数据是按升序还是降序存储。如果不指定Q则默认为升?
    2 支持在计列上创建烦?
    3 为烦引指定填充因?
      可标识填充因子来指定每个索引늚填满E度。烦引页上的IZI间量很重要Q?
      因ؓ(f)当烦引页填满Ӟpȝ必须花时间拆分它以便为新行腾出空间?


?索引的维护语?

DBCC DBREINDEX    重徏指定数据库中表的一个或多个索引
DBCC INDEXFRAG  整理指定的表或视囄聚集索引和辅助烦引碎?

比较

             速度    兼容?nbsp;    日志影响      数据讉K影响       额外盘I间
DBCC        最?nbsp;     最?nbsp;    ?但能通过?nbsp;  操作q程中数据不   需要大
DBREINDEX             可以?nbsp;  故障q原模型?nbsp; 能访问,影响?
                      建所?nbsp;  为简单减日?nbsp;  
                      有烦?

DBCC        ?nbsp;      但可   必须?nbsp;  ?nbsp;             数据未被锁定        需要小
INDEXDEFRAG          随时l?别指?
                     止执?nbsp; 
                               

drop index    中等  必须?nbsp;  ?但能通过?nbsp;   仅在操作执行?nbsp;   中等Q操作在   
create index        别指?nbsp;  故障q原模型?nbsp;  锁定数据          tempdb中进?
                             为简单减日?


?查看索引的方?

sp_indexes        q回指定q程表的索引信息
INDEXKEY_PROPERTY q回有关索引键的信息
sysindexespȝ?nbsp; 数据库中的每个烦引和表在表中各占一行,该表存储在每个数据库?


?可以通过执行计划
   查看sql语句执行时是否徏立在索引之上

比如
CREATE TABLE Test
(Field_1 int NOT NULL,
 Field_2 int CONSTRAINT PK_Test
 PRIMARY KEY CLUSTERED (Field_1))

CREATE index IX_Test ON Test (Field_2)

1 SELECT * FROM Test WHERE Field_2 =408
  执行计划可以看出使用了IX_Test索引
2 SELECT * FROM Test WHERE Field_1 =1
  执行计划可以看出使用了PK_Test
3 但如果是SELECT * FROM Test with (index(IX_Test)) WHERE Field_1 =1
  则指定用烦?


?索引的具体?

1Q?索引的设?
A:量避免表扫?
(g)查你的查询语句的where子句Q因是优化器重要x的地斏V包含在where里面的每一列(column)都是可能的侯选烦引,辑ֈ最优的性能Q考虑在下面给出的例子Q对于在where子句中给Zcolumn1q个列?
下面的两个条件可以提高烦引的优化查询性能Q?
W一Q在表中的column1列上有一个单索引
W二Q在表中有多索引Q但是column1是第一个烦引的?
避免定义多烦引而column1是第二个或后面的索引Q这L(fng)索引不能优化服务器性能
例如Q下面的例子用了pubs数据库?
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = ’White?
按下面几个列上徏立的索引会(x)是对优化器有用的索引
?au_lname
?au_lname, au_fname
而在下面几个列上建立的烦引将不会(x)对优化器起到好的作用
?au_address
?au_fname, au_lname
考虑使用H的索引在一个或两个列上Q窄索引比多索引和复合烦引更能有效。用H的索引Q在每一上
会(x)有更多的行和更少的烦引别(相对与多索引和复合烦引而言Q,q将推进pȝ性能?
对于多列索引QSQL Serverl持一个在所有列的烦引上的密度统计(用于联合Q和在第一个烦引上?
histogramQ柱状图Q统计。根据统计结果,如果在复合烦引上的第一个烦引很被选择使用Q那么优化器对很多查询请求将不会(x)使用索引?
有用的烦引会(x)提高select语句的性能Q包括insert,uodate,delete?
但是Q由于改变一个表的内容,会(x)影响索引。每一个insert,update,delete语句会(x)使性能下降一些。实验表明,不要在一个单表上用大量的索引Q不要在׃n的列上(指在多表中用了参考约束)使用重叠的烦引?
在某一列上(g)查唯一的数据的个数Q比较它与表中数据的行数做一个比较。这是数据的选择性,q比较结果将?x)帮助你军_是否某一列作Z选的索引列,如果需要,建哪一U烦引。你可以用下面的查询语句q回某一列的不同值的数目?
select count(distinct cloumn_name) from table_name
假设column_name是一?0000行的表,则看column_nameq回值来军_是否应该使用Q及(qing)应该使用什么烦引?
Unique values Index

5000 Nonclustered index
20 Clustered index
3 No index


2) 镞烦引和非镞索引的选择

<1:>镞烦引是行的物理序和烦引的序是一致的。页U,低层{烦引的各个U别上都包含实际的数据页。一个表只能是有一个镞索引。由于update,delete语句要求相对多一些的L作,因此镞烦引常常能加速这L(fng)操作。在臛_有一个烦引的表中Q你应该有一个镞索引?
在下面的几个情况下,你可以考虑用镞索引Q?
例如Q?某列包括的不同值的个数是有限的Q但是不是极的Q?
֮表的州名列有50个左右的不同州名的羃写|可以使用镞烦引?
例如Q?对返回一定范围内值的列可以用镞索引Q比如用between,>,>=,<,<={等来对列进行操作的列上?
select * from sales where ord_date between ?/1/93?and ?/1/93?
例如Q?Ҏ(gu)询时q回大量l果的列可以使用镞烦引?
SELECT * FROM phonebook WHERE last_name = ’Smith?

当有大量的行正在被插入表中时Q要避免在本表一个自然增长(例如Qidentity列)的列上徏立镞索引。如果你建立了镞的烦引,那么insert的性能׃(x)大大降低。因为每一个插入的行必d表的最后,表的最后一个数据页?
当一个数据正在被插入Q这时这个数据页是被锁定的)Q所有的其他插入行必ȝ待直到当前的插入已经l束?
一个烦引的叶中包括实际的数据页Qƈ且在盘上的数据늚ơ序是跟镞烦引的逻辑ơ序一L(fng)?

<2:>一个非镞的索引是行的物理ơ序与烦引的ơ序是不同的。一个非镞烦引的叶包含了指向行数据늚指针?
在一个表中可以有多个非镞索引Q你可以在以下几个情况下考虑使用非镞索引?
在有很多不同值的列上可以考虑使用非镞索引
例如Q一个part_id列在一个part表中
select * from employee where emp_id = ’pcm9809f?
查询语句中用order by 子句的列上可以考虑使用镞烦?

 

3) 一个表列如果设Z?primary key),它会(x)自动生成一个聚烦?
q时不能直接使用Drop index Table1.Tableindex1语句
必须删除主键U束Q用语句:alter table table1 drop constraint U束?如pk_xxx)


?全文索引
use pubs
  go

  --打开数据库全文烦引的支持

 execute sp_fulltext_database 'enable'
 go

  --建立全文目录ft_titles

  execute sp_fulltext_catalog 'ft_titles', 'create'
  go

  --为titles表徏立全文烦引数据元QUPKCL_titleidind是主键所建立的唯一索引Q可由sp_help titles得知

  execute sp_fulltext_table 'titles','create', 'ft_titles', 'UPKCL_titleidind'
  go

  --讄全文索引列名

  exec sp_fulltext_column 'titles', 'title', 'add'
  go
  exec sp_fulltext_column 'titles', 'notes', 'add'
  go

  --建立全文索引

  exec sp_fulltext_table 'titles', 'activate'
  go

  --填充全文索引目录

  exec sp_fulltext_catalog 'ft_titles', 'start_full'
  go

  --使用contains和freetext

  select title, notes from titles
  where contains(title, '"computer Cooking"')
  go
  select title, notes from titles
  where freetext(title, 'computer Cooking')
  go
  select title, notes from titles
  where freetext(title, '"computer Cooking"')
  go
  select title, notes from titles
  where contains(title, 'computer')
  go
  select title, notes from titles
  where freetext (*, 'computer')
  go

q里提一下google的搜索引擎的原理.
他把每个字词都做为单元去查询.
打个比方:我在字典里查?现在我要搜烦"?wi)?q个?他会(x)把这个树(wi)型这个词全文扫描一?生成一个二叉树(wi).q记下他的页?
然后当我W?ơ查扄时候显然这?记忆"提示,然后"提取".如果你对某一个字D做了全文烦引的话,他会(x)全文扫描表一?然后U录?
相应的纪?生成二叉?
如果我要查找"?wi)?,同理也可以得出页?但当我们L找一??wi)型l构"他则?x)??wi)???wi)型l构"?U录"下来.

?巧妙的用烦?
SELECT SUM(quantity) AS quantity FROM test WHERE...
1.若WHERE 里用的是字段与常量比较,MSSQL?x)自动引用该字段上的索引Q若用的是变量,MSSQL不会(x)自动引用该字D上的烦引而是Ҏ(gu)聚集索引q行扫描
2.加上with(index(索引?)指定索引Q即Q?
SELECT SUM(quantity) AS quantity FROM with(index(索引?) test WHERE...
指定索引后,W(xu)HERE 里不论是帔Rq是变量QMSSQL都根据指定的索引q行扫描
3.DBCC DBREINDEX执行q不一定能优化MSSQL性能Q慎?
4.如果在pub_id上徏立烦引的?
select * from titles where pub_id-500 >1000   ---------(a)
select * from titles where pub_id >1000+500  -----------(b)
请选用(b)语句,q样的话Q他?x)利用烦??a)的话׃对字D|作了,所以不?x)利用烦?
5.量避免用like语句,
如果L找baa%,caa%的话
如果是like '%aa%','_aa%','[m-z]o%'  则根本不?x)用到烦?
替换Ҏ(gu).columns like 'baa%' or  columns like 'caa %'
6什么情况下应不建或徏索引
a.表记录太?.因ؓ(f)索引的话Q要Ҏ(gu)据库往q?ơ操?如果1个表只有几行字段的话Q数据库?x)对他的U录一ơ性全部取出来,q样的效率要q远高于索引.
b.l常insert,delete,update的表  对一些经常处理的业务表应在查询允许的情况下尽量减烦?
c.数据重复且分布^均的表字D??性别字段,各占50%的话Q你即Z,也v不到明显的作?
d.l常和主字段一块查询但dD늃引值比较多的表字段
表经常按收费序号、户标识~号、抄表日期、电(sh)费发生年月、操作标志来具体查询某一W收Ƅ情况Q如果将所有的字段都徏在一个烦引里那将?x)增加数据的修改、插入、删除时_(d)从实际上分析一W收Ƒ֦果按收费序号索引已l将记录减少到只有几条,如果再按后面的几个字D늃引查询将Ҏ(gu)能不生太大的影响?
e.如果一个表的记录达?00万以上的话,要对其中一个字D徏索引可能要花很长的时_(d)甚至D服务器数据库LQ因为在建烦引的时候ORACLE要将索引字段所有的内容取出q进行全面排序,数据量大的话可能D服务器排序内存不引用磁盘交换空间进行,q将严重影响服务器数据库的工作。解x法是增大数据库启动初始化中的排序内存参数Q如果要q行大量的烦引修改可以设|?0M以上的排序内存(ORACLE~省大小?4KQ,在烦引徏立完成后应将参数修改回来Q因为在实际OLTP数据库应用中一般不?x)用到这么大的排序内存?


以下转蝲
 great_domino ?Blog

探讨如何在有着1000万条数据的MS SQL SERVER数据库中实现快速的数据提取和数据分c(din)以下代码说明了我们实例中数据库的“红头文件”一表的部分数据l构Q?/P>

CREATE TABLE [dbo].[TGongwen] (    --TGongwen是红头文件表?/P>

   [Gid] [int] IDENTITY (1, 1) NOT NULL ,
--本表的idP也是主键

   [title] [varchar] (80) COLLATE Chinese_PRC_CI_AS NULL , 
--U头文g的标?

   [fariqi] [datetime] NULL ,
--发布日期

   [neibuYonghu] [varchar] (70) COLLATE Chinese_PRC_CI_AS NULL ,
--发布用户

   [reader] [varchar] (900) COLLATE Chinese_PRC_CI_AS NULL ,

--需要浏览的用户。每个用户中间用分隔W?”分开

) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO


  下面Q我们来往数据库中d1000万条数据Q?

declare @i int

set @i=1

while @i<=250000

begin

    insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-2-5','通信U?,'通信U?办公?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦支队,hU?d支队,外事U?,'q是最先的25万条记录')

    set @i=@i+1

end

GO

 

declare @i int

set @i=1

while @i<=250000

begin

    insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-9-16','办公?,'办公?通信U?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦支队,hU?外事U?,'q是中间?5万条记录')

    set @i=@i+1

end

GO

 

declare @h int

set @h=1

while @h<=100

begin

declare @i int

set @i=2002

while @i<=2003

begin

declare @j int

        set @j=0

        while @j<50

            begin

declare @k int

            set @k=0

            while @k<50

            begin

    insert into Tgongwen(fariqi,neibuyonghu,reader,title) values(cast(@i as varchar(4))+'-8-15 3:'+cast(@j as varchar(2))+':'+cast(@j as varchar(2)),'通信U?,'办公?通信U?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦支队,hU?外事U?,'q是最后的50万条记录')

            set @k=@k+1

            end

set @j=@j+1

        end

set @i=@i+1

end

set @h=@h+1

end

GO

 

declare @i int

set @i=1

while @i<=9000000

begin

    insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-5-5','通信U?,'通信U?办公?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦支队,hU?d支队,外事U?,'q是最后添加的900万条记录')

    set @i=@i+1000000

end

GO

通过以上语句Q我们创Z25万条׃2004q??日发布的记录Q?5万条由办公室?004q??日发布的记录Q?002q和2003q各100?500条相同日期、不同分U的记录Q共50万条Q,q有由通信U于2004q??日发布的900万条记录Q合?000万条?/P>

何时使用聚集索引或非聚集索引

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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如果?zhn)的数据库真的?000万容量的话,把主键徏立在ID列上Q就像以上的W??U情况,在网上的表现就是超ӞҎ(gu)无法显C。这也是我摒弃ID列作集烦引的一个最重要的因素?/P>

  得出以上速度的方法是Q在各个select语句前加Qdeclare @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上建立聚合索引是再合适不q了。在现实中,我们每天都会(x)发几个文Ӟq几个文件的发文日期q同,q完全符合徏立聚集烦引要求的Q“既不能l大多数都相同,又不能只有极数相同”的规则。由此看来,我们建立“适当”的聚合索引对于我们提高查询速度是非帔R要的?/P>

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

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

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

  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我们可以看到如果仅用聚集烦引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一L(fng)Q甚x用上全部的复合烦引列q要略快Q在查询l果集数目一L(fng)情况下)Q而如果仅用复合聚集烦引的非v始列作ؓ(f)查询条g的话Q这个烦引是不vM作用的。当Ӟ语句1?的查询速度一h因ؓ(f)查询的条目数一P如果复合索引的所有列都用上,而且查询l果的话,q样׃(x)形成“烦引覆盖”,因而性能可以辑ֈ最优。同Ӟ误住:(x)无论(zhn)是否经怋用聚合烦引的其他列,但其前导列一定要是用最频繁的列?/P>

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

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

  下面是实例语句:(x)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用聚集索引作ؓ(f)排序列要比用非聚集索引速度快得明显的多Q而数据量如果很大的话Q如10万以上,则二者的速度差别不明显?/P>

  3、用聚合烦引内的时间段Q搜索时间会(x)按数据占整个数据表的癑ֈ比成比例减少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那么用大于号和等于号是一L(fng)Q?/P>

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1' and fariqi<'2004-6-6'

  用时Q?280毫秒

  4 、日期列不会(x)因ؓ(f)有分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毫秒

  Q五Q其他注意事?/P>

  “水可蝲舟,亦可覆舟”,索引也一栗烦引有助于提高?gu)(g)索性能Q但q多或不当的索引也会(x)Dpȝ低效。因为用户在表中每加q一个烦引,数据库就要做更多的工作。过多的索引甚至?x)导致烦引碎片?/P>

  所以说Q我们要建立一个“适当”的索引体系Q特别是对聚合烦引的创徏Q更应精益求_,以(zhn)的数据库能得到高性能的发挥?/P>

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

二、改善SQL语句

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

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

  和执?

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

  一些h不知道以上两条语句的执行效率是否一P因ؓ(f)如果单的从语句先后上看,q两个语句的是不一P如果tID是一个聚合烦引,那么后一句仅仅从表的10000条以后的记录中查扑ְ行了Q而前一句则要先从全表中查找看有几个name='zhangsan'的,而后再根据限制条件条件tID>10000来提出查询结果?/P>

  事实上,q样的担心是不必要的。SQL SERVER中有一个“查询分析优化器”,它可以计出where子句中的搜烦条gq确定哪个烦引能~小表扫描的搜烦I间Q也是_(d)它能实现自动优化?/P>

  虽然查询优化器可以根据where子句自动的进行查询优化,但大家仍然有必要了解一下“查询优化器”的工作原理Q如非这P有时查询优化器就?x)不按照?zhn)的本意q行快速查询?/P>

  在查询分析阶D,查询优化器查看查询的每个阶段q决定限刉要扫描的数据量是否有用。如果一个阶D可以被用作一个扫描参敎ͼSARGQ,那么q之ؓ(f)可优化的Qƈ且可以利用烦引快速获得所需数据?/P>

  SARG的定义:(x)用于限制搜烦的一个操作,因ؓ(f)它通常是指一个特定的匚wQ一个值得范围内的匚w或者两个以上条件的ANDq接。Ş式如下:(x)

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

?/P>

<常数 ?变量> 操作W列?/P>

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

Name=’张三?/P>

h>5000

5000<h

Name=’张三?and h>5000

  如果一个表辑ּ不能满SARG的Ş式,那它?yu)无法限制搜索的范围了,也就是SQL SERVER必须Ҏ(gu)一行都判断它是否满WHERE子句中的所有条件。所以一个烦引对于不满SARG形式的表辑ּ来说是无用的?/P>

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

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

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

  而:(x)name like ?张?,׃属于SARG?/P>

  原因是通配W?在字W串的开通得烦引无法用?/P>

  2、or ?x)引起全表扫?/P>

Name=’张三?and h>5000 W号SARGQ而:(x)Name=’张三?or h>5000 则不W合SARG。用or?x)引起全表扫描?/P>

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

  不满SARG形式的语句最典型的情况就是包括非操作W的语句Q如QNOT?=?lt;>?<?>、NOT EXISTS、NOT IN、NOT LIKE{,另外q有函数。下面就是几个不满SARG形式的例子:(x)

ABS(h)<5000

Name like ?三?/P>

  有些表达式,如:(x)

WHERE h*2>5000

  SQL SERVER也会(x)认ؓ(f)是SARGQSQL SERVER?x)将此式转化为?x)

WHERE h>2500/2

  但我们不推荐q样使用Q因为有时SQL SERVER不能保证q种转化与原始表辑ּ是完全等L(fng)?/P>

  4、IN 的作用相当与OR

  语句Q?/P>

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

  ?/P>

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

  是一L(fng)Q都?x)引起全表扫描,如果tid上有索引Q其索引也会(x)失效?/P>

  5、尽量少用NOT

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

  很多资料上都昄_(d)exists要比in的执行效率要高,同时应尽可能的用not exists来代替not in。但事实上,我试验了一下,发现二者无论是前面带不带notQ二者之间的执行效率都是一L(fng)。因为涉?qing)子查询Q我们试验这ơ用SQL SERVER自带的pubs数据库。运行前我们可以把SQL SERVER的statistics I/O状态打开?/P>

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

  该句的执行结果ؓ(f)Q?/P>

  ?'sales'。扫描计?18Q逻辑?56 ơ,物理?0 ơ,预读 0 ơ?/P>

  ?'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果为:(x)

  ?'sales'。扫描计?18Q逻辑?56 ơ,物理?0 ơ,预读 0 ơ?/P>

  ?'titles'。扫描计?1Q逻辑?2 ơ,物理?0 ơ,预读 0 ơ?/P>

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

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

  前面Q我们谈刎ͼ如果在LIKE前面加上通配W?Q那么将?x)引起全表扫描,所以其执行效率是低下的。但有的资料介绍_(d)用函数charindex()来代替LIKE速度?x)有大的提升Q经我试验,发现q种说明也是错误的:(x)

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

  用时Q?U,另外Q扫描计?4Q逻辑?7155 ơ,物理?0 ơ,预读 0 ơ?/P>

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

  用时Q?U,另外Q扫描计?4Q逻辑?7155 ơ,物理?0 ơ,预读 0 ơ?/P>

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

  我们前面已经谈到了在where子句中用or?x)引起全表扫描,一般的Q我所见过的资料都是推荐这里用union来代替or。事实证明,q种说法对于大部分都是适用的?/P>

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

  用时Q?8U。扫描计?1Q逻辑?404008 ơ,物理?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(fng)话,那么用union则反倒和用or的执行速度差很多,虽然q里union扫描的是索引Q而or扫描的是全表?/P>

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>

  我们来做一个试验:(x)

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,数据的提取速度׃(x)有相应的提升。提升的速度q要看?zhn)舍弃的字D늚大小来判断?/P>

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

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

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除主键以外的字段汇总速度要快Q而且字段长Q汇ȝ速度p慢。我惻I如果用count(*)Q?SQL SERVER可能?x)自动查找最字D|汇ȝ。当Ӟ如果(zhn)直接写count(主键)会(x)来的更直接些?/P>

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

  我们来看Q(gid是主键,fariqi是聚合烦引列Q?/P>

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

  用时Q?96 毫秒?扫描计数 1Q逻辑?289 ơ,物理?1 ơ,预读 1527 ơ?/P>

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

  用时Q?720毫秒?扫描计数 1Q逻辑?41956 ơ,物理?0 ơ,预读 1287 ơ?/P>

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

  用时Q?736毫秒?扫描计数 1Q逻辑?55350 ơ,物理?10 ơ,预读 775 ơ?/P>

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

  用时Q?73毫秒?扫描计数 1Q逻辑?290 ơ,物理?0 ơ,预读 0 ơ?/P>

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

  用时Q?56毫秒?扫描计数 1Q逻辑?289 ơ,物理?0 ơ,预读 0 ơ?/P>

  从以上我们可以看出,不排序的速度以及(qing)逻辑L数都是和“order by 聚集索引列?的速度是相当的Q但q些都比“order by 非聚集烦引列”的查询速度是快得多的?/P>

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

  12、高效的TOP

  事实上,在查询和提取大定w的数据集Ӟ影响数据库响应时间的最大因素不是数据查找,而是物理的I/0操作。如Q?/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整条语句的执行旉应该比子句的执行旉长,但事实相反。因为,子句执行后返回的?0000条记录,而整条语句仅q回10条语句,所以媄响数据库响应旉最大的因素是物理I/O操作。而限制物理I/O操作此处的最有效Ҏ(gu)之一是使用TOP关键词了。TOP关键词是SQL SERVER中经q系l优化过的一个用来提取前几条或前几个癑ֈ比数据的词。经W者在实践中的应用Q发现TOP实很好用,效率也很高。但q个词在另外一个大型数据库ORACLE中却没有Q这不能说不是一个遗憾,虽然在ORACLE中可以用其他Ҏ(gu)Q如QrownumberQ来解决。在以后的关于“实现千万数据的分|C存储过E”的讨论中,我们将用到TOPq个关键词?/P>

  到此为止Q我们上面讨Z如何实现从大定w的数据库中快速地查询出?zhn)所需要的数据Ҏ(gu)。当Ӟ我们介绍的这些方法都是“Y”方法,在实践中Q我们还要考虑各种“硬”因素,如:(x)|络性能、服务器的性能、操作系l的性能Q甚至网卡、交换机{?/P>

三、实现小数据量和量数据的通用分页昄存储q程

  建立一个web 应用Q分|览功能必不可。这个问题是数据库处理中十分常见的问题。经典的数据分页Ҏ(gu)?ADO U录集分|Q也是利用ADO自带的分功能(利用游标Q来实现分页。但q种分页Ҏ(gu)仅适用于较?yu)数据量的情形,因?f)游标本n有缺点:(x)游标是存攑֜内存中,很费内存。游标一建立Q就相关的记录锁住Q直到取消游标。游标提供了对特定集合中逐行扫描的手D,一般用游标来逐行遍历数据Q根据取出数据条件的不同q行不同的操作。而对于多表和大表中定义的游标Q大的数据集合)循环很容易ɽE序q入一个O长的{待甚至L?/P>

  更重要的是,对于非常大的数据模型而言Q分|索时Q如果按照传l的每次都加载整个数据源的方法是非常费资源的。现在流行的分页Ҏ(gu)一般是(g)索页面大的块区的数据,而非(g)索所有的数据Q然后单步执行当前行?/P>

  最早较好地实现q种Ҏ(gu)面大小和页码来提取数据的方法大概就是“俄|斯存储q程”。这个存储过E用了游标,׃游标的局限性,所以这个方法ƈ没有得到大家的普遍认可?/P>

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

CREATE procedure pagination1

(@pagesize int,  --面大小Q如每页存储20条记?/P>

@pageindex int   --当前늠

)

as

set nocount on

begin

declare @indextable table(id int identity(1,1),nid int)  --定义表变?/P>

declare @PageLowerBound int  --定义此页的底?/P>

declare @PageUpperBound int  --定义此页的顶?/P>

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的分存储过E。当Ӟ在这个过E中Q?zhn)也可以把其中的表变量写成临时表?x)CREATE TABLE #Temp。但很明显,在SQL SERVER中,用(f)时表是没有用表变量快的。所以笔者刚开始用这个存储过E时Q感觉非常的不错Q速度也比原来的ADO的好。但后来Q我又发C比此Ҏ(gu)更好的方法?/P>

  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 表的关键?

  我当时看到这文章的时候,真的是精ؓ(f)之一振,觉得思\非常得好。等到后来,我在作办公自动化pȝQASP.NET+ C#QSQL SERVERQ的时候,忽然惌v了这文章,我想如果把这个语句改造一下,q就可能是一个非常好的分存储过E。于是我满|上找这文章,没想刎ͼ文章q没扑ֈQ却扑ֈ了一根据此语句写的一个分存储过E,q个存储q程也是目前较ؓ(f)行的一U分存储过E,我很后?zhn)没有争先把这D|字改造成存储q程Q?/P>

CREATE PROCEDURE pagination2
(
 @SQL nVARCHAR(4000),    --不带排序语句的SQL语句
 @Page int,              --늠
 @RecsPerPage int,       --每页容纳的记录数
 @ID VARCHAR(255),       --需要排序的不重复的ID?
 @Sort VARCHAR(255)      --排序字段?qing)规?
)
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以上语句可以简化ؓ(f)Q?/P>

SELECT TOP 大?*

FROM Table1

WHERE (ID NOT IN

          (SELECT TOP 大?| id

         FROM ?/P>

         ORDER BY id))

ORDER BY ID

  但这个存储过E有一个致命的~点Q就是它含有NOT IN字样。虽然我可以把它攚wؓ(f)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 卛_实现Ҏ(gu)据量的控制?/P>

  在分늮法中Q媄响我们查询速度的关键因素有两点QTOP和NOT IN。TOP可以提高我们的查询速度Q而NOT IN?x)减慢我们的查询速度Q所以要提高我们整个分页法的速度Q就要彻底改造NOT INQ同其他Ҏ(gu)来替代它?/P>

  我们知道Q几乎Q何字D,我们都可以通过max(字段)或min(字段)来提取某个字D中的最大或最|所以如果这个字D不重复Q那么就可以利用q些不重复的字段的max或min作ؓ(f)分水岭,使其成ؓ(f)分页法中分开每页的参照物。在q里Q我们可以用操作W?gt;”或?lt;”号来完成这个命,使查询语句符合SARG形式。如Q?/P>

Select top 10 * from table1 where id>200

  于是有了如下分|案:(x)

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我们通常?x)选择主键。下表列ZW者用有着1000万数据的办公自动化系l中的表Q在以GIDQGID是主键,但ƈ不是聚集索引。)为排序列、提取gid,fariqi,title字段Q分别以W??0?00?00?000?万?0万?5万?0万页ZQ测试以上三U分|案的执行速度Q(单位Q毫U)

?nbsp; ?
 Ҏ(gu)1
 Ҏ(gu)2
 Ҏ(gu)3
 
1
 60
 30
 76
 
10
 46
 16
 63
 
100
 1076
 720
 130
 
500
 540
 12943
 83
 
1000
 17110
 470
 250
 
1?
 24796
 4500
 140
 
10?
 38326
 42283
 1553
 
25?
 28140
 128720
 2330
 
50?
 121686
 127846
 7168
 

  从上表中Q我们可以看出,三种存储q程在执?00以下的分页命o(h)Ӟ都是可以信Q的,速度都很好。但W一U方案在执行分页1000以上后Q速度降了下来。第二种Ҏ(gu)大约是在执行分页1万页以上后速度开始降了下来。而第三种Ҏ(gu)却始l没有大的降势,后劲仍然很?/P>

  在确定了W三U分|案后Q我们可以据此写一个存储过E。大家知道SQL SERVER的存储过E是事先~译好的SQL语句Q它的执行效率要比通过WEB面传来的SQL语句的执行效率要高。下面的存储q程不仅含有分页Ҏ(gu)Q还?x)根据页面传来的参数来确定是否进行数据Ll计?/P>

-- 获取指定늚数据

CREATE PROCEDURE pagination3

@tblName   varchar(255),       -- 表名

@strGetFields varchar(1000) = '*',  -- 需要返回的?

@fldName varchar(255)='',      -- 排序的字D名

@PageSize   int = 10,          -- 尺?/P>

@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)       -- 主语?/P>

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?的情?/P>

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这样会(x)加快执行速度

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>

  在大数据量的情况下,特别是在查询最后几늚时候,查询旉一般不?x)超q?U;而用其他存储q程Q在实践中就?x)导致超Ӟ所以这个存储过E非帔R用于大定w数据库的查询?/P>

  W者希望能够通过对以上存储过E的解析Q能l大家带来一定的启示Qƈl工作带来一定的效率提升Q同时希望同行提出更优秀的实时数据分늮法?/P>

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

  在上一节的标题中,W者写的是Q实现小数据量和量数据的通用分页昄存储q程。这是因为在本存储q程应用于“办公自动化”系l的实践中时Q笔者发现这W三U存储过E在数据量的情况下Q有如下现象Q?/P>

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

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

  虽然在超大容量情况下Q这个分늚实现q程是很快的Q但在分前几|Q这?Q?U的速度比vW一U甚x有经q优化的分页Ҏ(gu)速度q要慢,借用L(fng)话说是“还没有ACCESS数据库速度快”,q个认识以D用户攑ּ使用(zhn)开发的pȝ?/P>

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

  本篇文章的题目是Q“查询优化及(qing)分页法Ҏ(gu)”。笔者只所以把“查询优化”和“分늮法”这两个联系不是很大的论题放在一P是因ؓ(f)二者都需要一个非帔R要的东西――聚集烦引?/P>

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

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

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

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

  而聚集烦引在每个表内又只能徏立一个,q得聚集烦引显得更加的重要。聚集烦引的挑选可以说是实现“查询优化”和“高效分”的最关键因素?/P>

  但要既聚集索引列既W合查询列的需要,又符合排序列的需要,q通常是一个矛盾?/P>

  W者前面“烦引”的讨论中,fariqiQ即用户发文日期作ؓ(f)了聚集烦引的起始列,日期的精度为“日”。这U作法的优点Q前面已l提CQ在q行划时间段的快速查询中Q比用ID主键列有很大的优ѝ?/P>

  但在分页Ӟ׃q个聚集索引列存在着重复记录Q所以无法用max或min来最为分늚参照物,q而无法实现更为高效的排序。而如果将ID主键列作集烦引,那么聚集索引除了用以排序之外Q没有Q何用处,实际上是费了聚集烦引这个宝늚资源?/P>

   册个矛盾,W者后来又d了一个日期列Q其默认gؓ(f)getdate()。用户在写入记录Ӟq个列自动写入当时的旉Q时间精到毫秒。即使这PZ避免可能性很的重合Q还要在此列上创建UNIQUEU束。将此日期列作ؓ(f)聚集索引列?/P>

  有了q个旉型聚集烦引列之后Q用户就既可以用q个列查扄户在插入数据时的某个旉D늚查询Q又可以作ؓ(f)唯一列来实现max或minQ成为分늮法的参照物?/P>

  l过q样的优化,W者发玎ͼ无论是大数据量的情况下还是小数据量的情况下,分页速度一般都是几十毫U,甚至0毫秒。而用日期D늾?yu)范围的查询速度比原来也没有Mq钝?/P>

  聚集索引是如此的重要和珍贵,所以笔者ȝ了一下,一定要聚集烦引徏立在Q?/P>

  1、?zhn)最频繁使用的、用以羃?yu)查询范围的字段上?/P>

  2、?zhn)最频繁使用的、需要排序的字段上?/P>

  l束语:(x)

  希望q篇文章不仅能够l大家的工作带来一定的帮助Q也希望能让大家能够体会(x)到分析问题的Ҏ(gu)Q最重要的是Q希望这文章能够抛砖引玉,掀起大家的学习(fn)和讨论的兴趣Q以共同促进?
  最后需要说明的是,在试验中Q发现用户在q行大数据量查询的时候,Ҏ(gu)据库速度影响最大的不是内存大小Q而是CPU。在我的P4 2.4机器上试验的时候,查看“资源管理器”,CPUl常出现持箋?00%的现象,而内存用量却q没有改变或者说没有大的改变。即使在我们的HP ML 350 G3服务器上试验ӞCPU峰g能达?0%Q一般持l在70%左右?

  本文的试验数据都是来自我们的HP ML 350服务器。服务器配置Q双Inter Xeon 线E?CPU 2.4GQ内?GQ操作系lWindows Server 2003 Enterprise EditionQ数据库SQL Server 2000 SP3?/P>

转蝲完毕.


作者补?
1.columns in('aa','bb')
他等于columns = 'aa' or columns ='bb' 他先L询columns ='aa'攑֜一个(f)时的I间?然后{columns ='bb'查询完后,做个or查询得出l果.
至于效率的话Q在columns建立索引的话, columns ='aa' or columns ='bb'要来的效率高
语法分析器会(x)columns in('aa','bb')转化
为columns ='aa' or columns ='bb'来执行。我们期望它?x)根据每个or子句分别查找Q再结?
相加Q这样可以利用columns 上的索引Q但实际上(Ҏ(gu)showplanQ?它却采用?OR{略"
Q即先取出满x个or子句的行Q存入(f)时数据库的工作表中,再徏立唯一索引以去?
重复行,最后从q个临时表中计算l果。因此,实际q程没有利用columns 上烦引,q且?
成时间还要受tempdb数据库性能的媄响?


2.效率从高C count(1)>count(*)>count([id]) 

3.select max(cols) from table1 的效?gt;= select top 1 cols from table1 order by cols desc

4.在where 做ƈ列条件句?where cols1='aa' and cols2='bb'
如果cols1 ='aa' ?5% cols2?%的话Q把cols2='bb'攑֜前面 ,因ؓ(f)他在(g)索cols ='bb'的时候他只需查那5%,然后条g成立的话Q去在这5%的纪录里
L找cols1 ='aa'

5.避免用if条g?可以用or来替?
declare @vsql varchar(200)
set @vsql ='Renaski'
select * from titles where  @vsql ='Renaski' or price = 11.9500

如果@vsql为Renaski则把所有的U录都选出?如果不是的话Q则只查询price = 11.9500 的纪?

6.M对列的操作都导致表扫描Q它包括数据库函数、计表辑ּ{等Q查询时
要尽可能操作移至等号右辏V?

7.量避免使用游标.
如果使用了游标,p量避免在游标@环中再进行表q接的操?

8.取一个表的纪录数
Select rows from sysindexes where id=object_id(N'titles') and indid<2
效率?
select count(1) from titles来的?


9.取的一个表的数据信?
SELECT
表名=case when a.colorder=1 then d.name else '' end,
表说?case when a.colorder=1 then isnull(f.value,'') else '' end,
字段序号=a.colorder,
字段?a.name,
标识=case when COLUMNPROPERTY( a.id,a.name,'IsIdentity')=1 then '?else '' end,
主键=case when exists(SELECT 1 FROM sysobjects where xtype='PK' and name in (
SELECT name FROM sysindexes WHERE indid in(
SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid
))) then '? else '' end,
cd=b.name,
占用字节?a.length,
长度=COLUMNPROPERTY(a.id,a.name,'PRECISION'),
数位数=isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0),
允许I?case when a.isnullable=1 then '?else '' end,
默认?isnull(e.text,''),
字段说明=isnull(g.[value],''),
索引名称=isnull(h.索引名称,''),
索引序=isnull(h.排序,'')
FROM syscolumns a
left join systypes b on a.xtype=b.xusertype
inner join sysobjects d on a.id=d.id and d.xtype='U' and d.status>=0
left join syscomments e on a.cdefault=e.id
left join sysproperties g on a.id=g.id and a.colid=g.smallid
left join sysproperties f on d.id=f.id and f.smallid=0
left join(--q部分是索引信息,如果要显C烦引与表及(qing)字段的对应关p?可以只要此部?
select 索引名称=a.name,c.id,d.colid
,排序=case indexkey_property(c.id,b.indid,b.keyno,'isdescending')
when 1 then '降序' when 0 then '升序' end
from sysindexes a
join sysindexkeys b on a.id=b.id and a.indid=b.indid
join (--q里的作用是有多个烦引时,取烦引号最的那个
select id,colid,indid=min(indid) from sysindexkeys
group by id,colid) b1 on b.id=b1.id and b.colid=b1.colid and b.indid=b1.indid
join sysobjects c on b.id=c.id and c.xtype='U' and c.status>=0
join syscolumns d on b.id=d.id and b.colid=d.colid
where a.indid not in(0,255)
) h on a.id=h.id and a.colid=h.colid
--where d.name='要查询的? --如果只查询指定表,加上此条?
order by a.id,a.colorder


10.创徏一个表l构.
select * into #b from authors where 1=2;
注意:
#table1
##table1
@table1

局部(f)时表
以一个井P#Q开头的那些表名。只有在创徏本地临时表的q接上才能看到这些表?

全局临时?
以两个井P##Q开头的那些表名。在所有连接上都能看到全局临时表。如果在创徏全局临时表的q接断开前没有显式地除去q些表,那么只要所有其它Q务停止引用它们,q些表即被除厅R当创徏全局临时表的q接断开后,新的d不能再引用它们。当前的语句一执行完,d与表之间的关联即被除去;因此通常情况下,只要创徏全局临时表的q接断开Q全局临时表即被除厅R?

@?有和不同Q@@在内存,#在硬盘。我的体?x)是只要方便且数据量不大Q用@@?/P>

11.视图
他只是记住要q接,兌列的信息,他不存放M物理数据.
在调用的时候他q是d各个表中的数?

12.量不要用text属?
pȝZ专门开辟一个空间来存放.
用t-sql/varchar替代
pl/sql  varchar2 替代.

13
GO语句是个命o(h)识别q过osql和isql和SQL 查询分析器非T-SQL语句q行识别?
如果你用查询分析器作ؓ(f)你的d发工P其他语句和库文g不?x)识别GO语句作ؓ(f)一个T-SQL命o(h)

14.
用exec 效率来的?
declare @sql nvarchar(300)
   set @sql='select * from titles'
execute sp_executesql @sql

15,注意你的tempdb,使他自动增长.

16 使用no_log
select * from titles no_logs

17M重复U录?量用dictinct

18.量避免反复讉K同一张或几张表,其是数据量较大的表Q可以考虑先根据条件提取数据到临时表中Q然后再做连接?


19 量使用?gt;=”,不要使用?gt;”?他会(x)扑ֈ某个定的数字进行筛??gt;则没?

20注意表之间连接的数据cdQ避免不同类型数据之间的q接?

21.可用ASE调优命o(h)Qset statistics io on, set statistics time on , set showplan on {?q行优化

22.truncate table 删除数据
而不是delete from table


?死锁

像SQL server一L(fng)关系数据库用锁来防止用户“互相踩到对方的脚趾头”。也是_(d)锁可以防止用户造成修改数据时的撞。当一个用户锁住一D代码时候,其它的用户都不能修改q段数据。另外,一个锁L了用戯看未被授权的数据修改。用户必ȝ待到数据修改q保存之后才能够查看它。数据必M用不同的Ҏ(gu)来加锁。SQL Server 2000使用锁来实现多用户同时修Ҏ(gu)据库同一数据时的同步控制
如果数据量超q?00个数据页面(400kQ,那么pȝ会(x)q行锁升U,锁会(x)升成表U锁?  


死锁
一个数据库的死锁是发生在两个或多于两个讉K一些资源的数据库会(x)话中的,q且q些?x)话怺之间有依赖关pR死锁是可以在Q意一个多U程的系l成出现的一个情况,不仅仅局限于关系数据库管理系l。一个多U程pȝ中的U程可能需要一个或多个资源(例如Q锁)。如果申L(fng)资源正在被另外一个线E所使用Q那么第一个线E就需要等待持有该资源的线E的释放它所需要的资源。假讄待线E持有一个那个正拥有U程所依赖的资源。下面的q一D代码就可以造成死锁异常现象的发生:(x)
System.Data.SqlClient.SqlException: Transaction (Process ID 12) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

当一个SQL Server的调用和另外一个资源发生冲H时׃(x)抛出异常Q这个资源持有一个必要的资源。结果是Q一个进E就被终止了。当q程的IDh为系l的唯一标识的时候,q会(x)是一个很q_死锁的消息错误?/P>


锁的cd
一个数据库pȝ在许多情况下都有可能锁数据项。其可能性包括:(x)

Rows—数据库表中的一整行
Pages—行的集合(通常为几kbQ?
Extents—通常是几个页的集?
Table—整个数据库?
Database—被锁的整个数据库表

除非有其它的说明Q数据库Ҏ(gu)情况自己选择最好的锁方式。不q值得感谢的是QSQL Server提供了一U避免默认行为的Ҏ(gu)。这是由锁提C来完成的?/P>


提示
或许你有q许多如下的l历Q需要重设SQL Server的锁计划Qƈ且加强数据库表中锁范围。TansactQSQL提供了一pd不同U别的锁提示Q你可以在SELECT,INSERT,UPDATE和DELETE中用它们来告诉SQL Server你需要如何通过重设M的系l或事务U别来锁表格。可以实现的提示包括Q?

FASTFIRSTROW—选取l果集中的第一行,q将其优?
HOLDLOCK—持有一个共享锁直至事务完成
NOLOCK—不允许使用׃n锁或独n锁。这可能?x)造成数据重写或者没有被认p回的情况Q因此,有可能使用到脏数据。这个提C只能在SELECT中用?
PAGLOCK—锁表格
READCOMMITTED—只d被事务确认的数据。这是SQL Server的默认行为?
READPAST—蟩q被其它q程锁住的行Q所以返回的数据可能?x)忽略行的内宏V这也只能在SELECT中用?
READUNCOMMITTED—等价于NOLOCK.
REPEATABLEREAD—在查询语句中,Ҏ(gu)有数据用锁。这可以防止其它的用h新数据,但是新的行可能被其它的用h入到数据中,q且被最新访问该数据的用戯取?
ROWLOCK—按照行的别来Ҏ(gu)据上锁。SQL Server通常锁到|者表U别来修改行Q所以当开发者用单行的时候,通常要重设这个设|?
SERIALIZABLE—等价于HOLDLOCK.
TABLOCK—按照表U别上锁。在q行多个有关表别数据操作的时候,你可能需要用到q个提示?
UPDLOCK—当d一个表的时候,使用更新锁来代替׃n锁,q且保持一直拥有这个锁直至事务l束。它的好处是Q可以允怽在阅L据的时候可以不需要锁Qƈ且以最快的速度更新数据?
XLOCK—给所有的资源都上独n锁,直至事务l束?

对于数据库死锁,通常可以通过TRACE FLAG 1204?205?206Q检查ERRORLOG里面的输出,和分析SQLTRACE的执行上下文判断死锁问题的来由?
TRACEON函数的第三个参数讄?1Q表CZ单单针对当前connectionQ而是针对所有包括未来徏立的connection。这P才够完全Q否则只是监视当前已l徏立的数据库连接了?
 

执行下面的话可以把死锁记录到Errorlog中:(x)

dbcc traceon (1204, 3605, -1)
go
dbcc tracestatus(-1)
go
 
  
 
得到的输Zؓ(f)Q?
DBCC 执行完毕。如?DBCC 输出了错误信息,请与pȝ理员联pR?
TraceFlag Status
--------- ------
1204      1
1205      1
3605      1

Q所影响的行Cؓ(f) 3 行)

DBCC 执行完毕。如?DBCC 输出了错误信息,请与pȝ理员联pR?/P>


此后Q你可以查看数据库的例行日志Q每隔一D|_(d)数据库都?x)检查死?
2004-01-16 18:34:38.50 spid4     ----------------------------------
2004-01-16 18:34:38.50 spid4     Starting deadlock search 1976

 

2004-01-16 18:34:38.50 spid4     Target Resource Owner:
2004-01-16 18:34:38.50 spid4      ResType:LockOwner Stype:'OR' Mode: U SPID:55 ECID:0 Ec:(0xAA577570) Value:0x4c25cba0
2004-01-16 18:34:38.50 spid4      Node:1  ResType:LockOwner Stype:'OR' Mode: U SPID:55 ECID:0 Ec:(0xAA577570) Value:0x4c25cba0
2004-01-16 18:34:38.50 spid4      Node:2  ResType:LockOwner Stype:'OR' Mode: U SPID:71 ECID:0 Ec:(0xABF07570) Value:0x9bd0ba00
2004-01-16 18:34:38.50 spid4    
2004-01-16 18:34:38.50 spid4     -- next branch --
2004-01-16 18:34:38.50 spid4      Node:2  ResType:LockOwner Stype:'OR' Mode: U SPID:71 ECID:0 Ec:(0xABF07570) Value:0x9bd0ba00
2004-01-16 18:34:38.50 spid4    
2004-01-16 18:34:38.50 spid4    
2004-01-16 18:34:38.50 spid4     End deadlock search 1976 ... a deadlock was not found.
2004-01-16 18:34:38.50 spid4     ----------------------------------

DBCC TRACEON打开Q启用)指定的跟t标记?
 
注释跟踪标记用于自定义某些控?Microsoft? SQL Server? 操作方式的特性。跟t标记在服务器中一直保持启用状态,直到通过执行 DBCC TRACEOFF 语句对其用为止。在发出 DBCC TRACEON 语句之前Q连入到服务器的新连接看不到M跟踪标记。一旦发语句Q该q接p看到服务器中当前启用的所有跟t标讎ͼ即ɘq些标记是由其它q接启用Q?
跟踪标记跟踪标记用于临时讄服务器的特定特征或关闭特定行为。如果启?Microsoft? SQL Server 时设|了跟踪标记 3205Q将用带驱动E序的硬件压~。跟t标记经常用于诊断性能问题Q或调试存储q程或复杂的计算机系l?
下列跟踪标记?SQL Server 中可用。跟t标?描述 1204 q回参与死锁的锁的类型以?qing)当前受影响的命令?nbsp;
实际上可以在“错?1000 -1999”中扑ֈ他们Q?
1204 19 SQL Server 此时无法获取 LOCK 资源。请在活动用h较少旉新运行?zhn)的语句,或者请求系l管理员?gu)(g)?SQL Server 锁和内存配置?
1205 13 事务Q进E?ID %1!Q与另一个进E已被死锁在资源 {%2!} 上,且该事务已被选作死锁牺牲品。请重新q行该事务?
1206 18 事务理器已取消了分布式事务?

需要指出的是对锁的升,完全是由pȝ自行判断?而非Zؓ(f).如果要避免死锁的话,其根本还在与数据库的设计?



Titan 2005-11-28 23:06 发表评论
]]>
վ֩ģ壺 ո| | | | | Ȫ| | ܿ| | ˳| | | ɽ| | | ư| ɽ| | | | | | | Զ| | | | | ͼ| | | | | | ն| ˫| | | ĵ| | |