亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

寫有效率的SQL查詢(III)

系統 1893 0

先說說這些誤區。所謂“誤區”,有一些是新手很容易犯的錯誤或者很容易忽略的問題,另外一些,則是像“耗子吃了鹽會變成蝙蝠”一樣,讓我們從小就認為是正確的事情。如下:

1、? 表上不管用得著用不著,都加個聚集索引。

我們知道,表以兩種方式組織物理存儲:有聚集索引的“聚集表”;沒有聚集索引的“堆”。在聚集表中,數據行按照聚集索引的順序存儲(這也是為啥一張表最多只能有一個聚集索引的原因);堆中,數據行的存儲可以認為是不確定的。

在偶《寫有效率的 SQL 查詢( II )》中曾經介紹過 DB 引擎如何在聚集表中通過非聚集索引查找目標數據:從非聚集索引樹根開始 seek ,查找到目標索引行,然后通過索引行上存儲的聚集索引鍵值,爬聚集索引樹,并最終通過聚集索引行上的指針拿到目標數據。

但是堆上的非聚集索引存儲的不是聚集索引鍵值,它存儲的是指向目標行的指針。也就是說,如果在同樣的表是堆,通過非聚集索引 seek 數據將省掉爬聚集索引樹的損耗,而可以直接通過非聚集索引行上的行指針直接拿到目標數據。也就是說,在某些情況下,使用堆可以提高系統效率。

這個“某些情況”,就是你的需求,你的系統行為。一般情況下,所有人對要在什么樣的字段上創建聚集索引都非常了解;但是不是所有的人都對應該在什么樣的系統行為下,不創建聚集索引了解。假設你的表中有字段 col1, col2,col3,col4 等等, col1 col2 的分布密度很低。你觀察了系統行為,發現一半的查詢是 XXXX where col1 = YYYY ,另一半的查詢是 XXXX where col2 = YYYY 。這種情況下,使用堆就是更好的選擇。

2、? primary key 就是聚集索引。

primary key 上是得有索引,但是這個索引可不見得一定得是聚集索引。盡管語句

create table testPK

(

??? ?????? id int identity ( 1 , 1 ) primary key ,

??? ?????? fname varchar ( 64 )

)

會在 id 列上創建聚集索引。當然,一般主鍵都是聚集索引,但也僅僅是“一般”而已。個人感覺,聚集索引的唯一目標就是數據檢索,它應該建在什么字段上,完全由系統行為決定?!耙话阒麈I都是聚集索引”也僅僅是因為多數情況下, primary key 字段上建所有更有益于效率而已。

create table testPK

(

??? ?????? id int identity ( 1 , 1 ) primary key nonclustered ,

??? ?????? fname varchar ( 64 )

)

可以創建primary key為非聚集索引

3、? Log 類的表,有事沒事加個自增的 Id 列。

這事相信干過的人很多,哈,而且一般還會順手在這個 Id 列上加上個 primary key 的約束,聚集索引也就被無意識的建上了。就像一個記錄用戶活動的日志表,一般會有這么幾個典型字段: Id 、 LogTime 、 UserId 。實際上對這種表的查詢,大多集中在 LogTime UserId 上, Id 完全沒有實際意義。你的客服系統查找的,可能僅僅是某個用戶的操作記錄(一般按時間排序的),或者你的報表系統要生成每天的用戶操作統計。想想看,如果干脆砍了 Id 列,并直接把聚集索引創建在 LogTime 上多爽。

4、? 是個表就給加個 primary key 約束

就像 3 中的例子, primary 完全沒必要。呵呵,這條看著簡單是簡單了,犯這錯誤的人,那也不比 3 少。

5、? where 條件里對同一個表中的列做運算或比較,以為創建某種類型的索引可以提高效率。(這種情況下,任何索引都無法提升性能。解決辦法見偶前面的“寫有效率的 sql 查詢”)

見過了無數的這種寫法。最常見的,如:一張用戶表里有用戶注冊時間( t1,YYYYDD ),有退訂時間( t2,YYYYDD ),現在讓你獲取存活時間大于 3 天的用戶總數:很多人一不注意,就整一個 select count(*) from Users where t1 – t2 > 3 出來。而且常常會臆測在 t1 t2 上建個涵蓋索引(或者分別在 t1 t2 上建索引)會讓性能提升。

6、? 在表上創建了 col1 col2 順序的涵蓋索引(聚集的或非聚集的),但是 where 條件里就一個 col2 > XXX 。這種情況下,就不如分別在 col1 、 col2 上創建索引。

?

以上的誤區,都是在工作中常常犯或遇到的,沒遇到的肯定還有,歡迎各位安達補充:)

?

OK ,接下來我們說說“涵蓋索引”和 include 索引。

所謂的涵蓋索引,就是傳統方式在多個列上創建的索引。“ inlude 索引”是 SQL2k5 提供的新功能,允許添加非鍵列到非聚集索引的葉節點上。

創建涵蓋索引:

create index ix_tb_col1_col2 on tb

(

??? ??? col1 ,

??? ??? col2

)

創建 include 索引:

create index ix_tb_col1 on tb

(

??? ??? col1

) include ( col2 , col3 , col4 )

???????? 涵蓋索引和 include 索引的區別在于,涵蓋索引的所有列都是鍵列,索引行的物理存儲順序就是 col1 、 col2 的順序,這也是誤區 6 之所以稱為誤區的原因。涵蓋索引可以是聚集索引,也可以是非聚集索引。

???????? include 索引 include 的列并不影響索引行的物理存儲順序,它們作為一個掛件“掛在”索引行上。掛著這些掛件的作用在于,諸如 select col2, col3, col4 from tb where col1 = XXX 只需要 seek 一把非聚集索引 ix_tb1_col1 OK 了,拿到索引行就拿到了需要的所有數據。掛件們是要占用索引行空間的,我們知道,索引字段寬度要盡可能窄是選擇索引的一項基本原則(這項原則背后的原理是盡可能讓索引樹深度小),所以并不是 include 的字段越多越好,這得跟你的系統行為有一個平衡。

???????? 從上面敘述可以看到,涵蓋索引實際上是 include 索引的加強版。也就是說,你的 where 條件里除了涵蓋索引的第一個索引列之外還有其他索引列的比較,創建涵蓋索引要比 include 索引高效一點點。同樣,維護涵蓋索引的消耗也會多少高于 Include 索引。

???????? 聚集索引的索引行直接包含了數據行指針,也就是說,通過聚集索引行,可以直接拿到其他所有列的數據,從某種意義上說,聚集索引就是最大的 include 索引,這也是 include 索引只能是非聚集索引的原因所在。

???????? OK ,給你一條 SQL 語句:

select col1, col2, col3, col4 from tb where col5 > XXX and col6 > yyy

你既可以在上面創建涵蓋索引 col5 、 col6 ,又可以創建 include 索引( col5/col6 include(col1 col2 、 col3 col4) 。選擇如何創建,就要看你的表各字段寬度、系統行為了。在此不再贅述。

?

最后講講如何拿到在文中頻頻提到的系統行為統計信息。這東西說白了就是各種 SQL 的執行次數、邏輯 IO 、物理 IO 、執行消耗 CPU 時間等等等等。想想看,假如你拿了一份系統中所有 SQL 的文本、執行總次數、邏輯 IO 占用總 IO 比例、物理 IO 占用總 IO 比例、平均邏輯 IO 、平均物理 IO 等等等等,你八成能夠指出系統瓶頸所在,老板和伙計們的眼光也會會極大的滿足你小小的虛榮心,哈。這些東西就在動態視圖 sys.dm_exec_query_stats 里面,自個翻翻聯機文檔吧:)

拿到系統行為統計信息之后,你終于調整了索引,于是系統明顯 nb 了。如果你要看看它變得有多 nb ,可以關注動態視圖 sys.dm_db_index_usage_stats ,這個也就不多說了。

?

最后,多讀聯機文檔,多做嘗試,盡力不用工具而手寫 SQL 才是硬道理。

=====================

關于表上是不是都需要一個聚集索引,各位安達展開了劇烈討論.摘錄部分到這里:
from RicCC:
描述的確不足,是否選擇聚集索引不是這么簡單
1. heap表的查詢,除了table scan和covering index之外,都需要bookmark lookup,covering index的使用是有限的,剩下的都是成本很高的操作。除非對這個表的查詢很少。
2. heap的數據頁之間沒有link,順序讀取數據性能低,I/O開銷大。除非每次都用unique index seek。
3. heap每個insert數據都是在末尾,并發的insert阻塞問題比較大。因為insert位置一次只能有一個任務加排它鎖??梢杂胏lustered改善。
4. delete多時,heap比clustered更浪費磁盤空間,碎片更嚴重,并且沒有正常的方式消除heap數據頁的碎片,只能建clustered或者drop table重建。

目前為止我基本沒有發現充足的證據使用heap.
============
index seek跟unique index seek不一樣,例如你要找8.1-8.9號的log,執行計劃里面只會看到一個index seek,它seek的是第一條數據,從第一條數據到最后一條用的是scan,并且heap肯定要用到rid/index lookup,假如要取的是1.1-8.9,rid/index lookup的成本很可能導致sql server放棄index而使用table scan

綜合考慮,使用heap的范圍實在是太狹窄,clustered index怎樣建倒很有文章,需要極為認真的對待.
============
index是unique的,index條件都給出來了并且全部是=,每次seek操作輸出都只有一條記錄,就是unique index seek,oracle是有這個操作的
如果不是unique index seek,就一定會有range index scan。sql server heap表的range index scan需要在IAM跟數據頁間切換,效率不好,clustered index就是用于改善這種狀況,并且充分利用磁盤設備讀取連續數據的優化措施
========================================================================

Me:到目前為止,我找到的最有理由使用堆的地方是一張每天產生kw級記錄的日志表,這張表上的查詢主要以查詢指定Id的用戶在某段時間內的記錄.

寫有效率的SQL查詢(III)


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。。?/p>

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲一区在线日韩在线深爱 | 国产精品久久久久毛片真精品 | 国产大学生一级毛片绿象 | 国产一区二区三区乱码网站 | 不卡中文一二三区 | 日韩精品一区二区三区免费视频 | 开心激情五月婷婷 | 国产精品久久久久久久久齐齐 | 国产亚洲日本 | 久久精品久久精品久久 | 综合网色 | 99视频全部免费精品全部四虎 | 国产玖玖在线观看 | 国内精品久久久久久中文字幕 | 福利视频影院 | 久久美剧 | 久久性网 | 人成午夜欧美大片免费视频 | 伊人久操| 久久93精品国产91久久综合 | h片在线免费观看 | 人人爱天天做夜夜爽88 | 免费观看大片毛片 | 乱人伦中文字幕在线看 | 国产极品白嫩美女在线观看看 | 阳光灿烂的日子在线观看 | 亚洲国产高清美女在线观看 | 精品久久久久久中文字幕一区 | 97在线观看免费版 | 污影院 | 天天射天天 | 亚洲精品色综合色在线观看 | 久久久久久青草大香综合精品 | 在线亚洲激情 | 亚洲综合色网站 | 99久久精品国内 | 中文字幕在线不卡精品视频99 | 欧美综合色网 | 精品伊人久久久99热这里只 | 久久伊人网站 | 国产精品人人视频 |