<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    索引初步接觸

    Posted on 2007-09-11 11:17 久城 閱讀(581) 評論(1)  編輯  收藏 所屬分類: 數據庫學習
    一直不理解索引到底是什么東西,把它跟primary key和unique的概念弄得十分模糊。上午查閱了一些資料,剛剛有些開朗的感覺。

    primary key和unique都是針對某一列的一種約束。一種限制,看不見摸不著。

    primary key表示該列中的數據唯一,且非空。

    unique表示該列中的數據唯一,可為空。

    而索引并不是一種約束,而是實際存在在物理空間中的。

    索引就同論文中的目錄(也叫索引)是一樣的。創建了目錄,能夠方便我們快速的找到我們想看的內容(查詢速度快的體現),但是,當論文的內容結構有變化的時候,比如說插入了新的一個章節,那么目錄的內容也會跟著變化,如果修改比較頻繁的話,那么我們可以想象得到,每修改一次內容都要修改一次索引,會比較麻煩。(頻繁插入,更新或刪除時遇到的問題的體現)

    我們在對表中的某一列進行primary key約束或unique約束的時候,oracle服務器會自動的為這個表創建一個索引(唯一索引,具體參考:http://msdn2.microsoft.com/zh-cn/library/ms187019.aspx)。
    設置主鍵之后,當查詢時,實際上起作用的是主鍵索引而并非是主鍵。索引也分為很多種類型,我平時用不上,沒做細研究。只知道索引可以分為聚集索引和非聚集索引。

    在MSDN上的資料:

    聚集索引
  • 聚集索引根據數據行的鍵值在表或視圖中排序和存儲這些數據行。索引定義中包含聚集索引列。每個表只能有一個聚集索引,因為數據行本身只能按一個順序排序。
  • 只有當表包含聚集索引時,表中的數據行才按排序順序存儲。如果表具有聚集索引,則該表稱為聚集表。如果表沒有聚集索引,則其數據行存儲在一個稱為堆的無序結構中。


    非聚集索引

  • 非聚集索引具有獨立于數據行的結構。非聚集索引包含非聚集索引鍵值,并且每個鍵值項都有指向包含該鍵值的數據行的指針。
  • 從非聚集索引中的索引行指向數據行的指針稱為行定位器。行定位器的結構取決于數據頁是存儲在堆中還是聚集表中。對于堆,行定位器是指向行的指針。對于聚集表,行定位器是聚集索引鍵。
  • 在 SQL Server 2005 中,可以向非聚集索引的葉級別添加非鍵列以跳過現有的索引鍵限制(900 字節和 16 鍵列),并執行完整范圍內的索引查詢。


    聚集索引和非聚集索引都可以是唯一的。這意味著任何兩行都不能有相同的索引鍵值。另外,索引也可以不是唯一的,即多行可以共享同一鍵值。


    每當修改了表數據后,都會自動維護表或視圖的索引。

    由此可見,設計一個良好的索引能夠大大提高表的查詢速度,但同時也承擔著一些風險。

    索引的工作:
    表是平面的,沒有層級關系,在進行查詢的時候,就是一行一行的掃。而索引實際上是使用了一個復雜的自平衡B+tree結構,有層級關系,所以使用索引查找數據能夠快速準確的定位到相關數據,并根據索引上的指針找到對應的數據記錄。因此通過索引查詢數據比全表掃描快得多。同樣在聯結多個表時使用索引也可以提高效率。

    進一步理解:
    索引和表之間是相對獨立而又關系密切的,簡單的說就是索引是將表的部分字段拿出來重新組織排序并為表查詢服務。
    所以當一個表在執行insert,update,delete操作的時候,索引也將會發生變化(怎么變化的跟B+樹的結構有關,我不大懂,反正會變化,簡單的講絕大部分情況增加一個記錄只會影響一個索引塊)。所以當對一個表的insert,update,delete操作比較頻繁的時候,我們就要考慮索引的使用與維護的問題。如何使其最優,有待研究。

    最后理解:
    過多的索引會降低數據操作的速度,但會提高查詢的速度,這需要自己在數據操作和查詢中進行權衡。
    如果進行大量insert和delete之后,會影響一些效率,這時候通常要將索引rebuild一下。
    ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>



  • 歡迎來訪!^.^!
    本BLOG僅用于個人學習交流!
    目的在于記錄個人成長.
    所有文字均屬于個人理解.
    如有錯誤,望多多指教!不勝感激!

    Feedback

    # re: 索引初步接觸  回復  更多評論   

    2007-09-11 11:31 by 久城
    在網上查到的傳閱比較廣泛的一個實例,感覺對理解索引的應用有很大的幫助。

    具體出處不詳。

    如何讓你的SQL運行得更快

    ---- 人們在使用SQL時往往會陷入一個誤區,即太關注于所得的結果是否正確,而忽略了不同的實現方法之間可能存在的性能差異,這種性能差異在大型的或是復雜的數據庫環境中(如聯機事務處理OLTP或決策支持系統DSS)中表現得尤為明顯。筆者在工作實踐中發現,不良的SQL往往來自于不恰當的索引設計、不充份的連接條件和不可優化的where子句。在對它們進行適當的優化后,其運行速度有了明顯地提高!下面我將從這三個方面分別進行總結:
    ---- 為了更直觀地說明問題,所有實例中的SQL運行時間均經過測試,不超過1秒的均表示為(< 1秒)。
    ---- 測試環境--
    ---- 主機:HP LH II
    ---- 主頻:330MHZ
    ---- 內存:128兆
    ---- 操作系統:Operserver5.0.4
    ---- 數據庫:Sybase11.0.3


    一、不合理的索引設計

    ----例:表record有620000行,試看在不同的索引下,下面幾個 SQL的運行情況:
    ---- 1.在date上建有一非個群集索引
    select count(*) from record where date >
    '19991201' and date < '19991214'and amount >
    2000 (25秒)
    select date,sum(amount) from record group by date
    (55秒)
    select count(*) from record where date >
    '19990901' and place in ('BJ','SH') (27秒)
    ---- 分析:
    ----date上有大量的重復值,在非群集索引下,數據在物理上隨機存放在數據頁上,在范圍查找時,必須執行一次表掃描才能找到這一范圍內的全部行。

    ---- 2.在date上的一個群集索引
    select count(*) from record where date >
    '19991201' and date < '19991214' and amount >
    2000 (14秒)
    select date,sum(amount) from record group by date
    (28秒)
    select count(*) from record where date >
    '19990901' and place in ('BJ','SH')(14秒)
    ---- 分析:
    ---- 在群集索引下,數據在物理上按順序在數據頁上,重復值也排列在一起,因而在范圍查找時,可以先找到這個范圍的起末點,且只在這個范圍內掃描數據頁,避免了大范 圍掃描,提高了查詢速度。

    ---- 3.在place,date,amount上的組合索引
    select count(*) from record where date >
    '19991201' and date < '19991214' and amount >
    2000 (26秒)
    select date,sum(amount) from record group by date
    (27秒)
    select count(*) from record where date >
    '19990901' and place in ('BJ, 'SH')(< 1秒)
    ---- 分析:
    ---- 這是一個不很合理的組合索引,因為它的前導列是place,第一和第二條SQL沒有引用place,因此也沒有利用上索引;第三個SQL使用了place,且引用的所有列都包含在組合索引中,形成了索引覆蓋,所以它的速度是非常快的。

    ---- 4.在date,place,amount上的組合索引
    select count(*) from record where date >
    '19991201' and date < '19991214' and amount >
    2000(< 1秒)
    select date,sum(amount) from record group by date
    (11秒)
    select count(*) from record where date >
    '19990901' and place in ('BJ','SH')(< 1秒)
    ---- 分析:
    ---- 這是一個合理的組合索引。它將date作為前導列,使每個SQL都可以利用索引,并且在第一和第三個SQL中形成了索引覆蓋,因而性能達到了最優。

    ---- 5.總結:
    ---- 缺省情況下建立的索引是非群集索引,但有時它并不是最佳的;合理的索引設計要建立在對各種查詢的分析和預測上。一般來說:
    ---- ①.有大量重復值、且經常有范圍查詢
    (between, >,< ,>=,< =)和order by
    、group by發生的列,可考慮建立群集索引;
    ---- ②.經常同時存取多列,且每列都含有重復值可考慮建立組合索引;
    ---- ③.組合索引要盡量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列。


    二、不充份的連接條件:

    ---- 例:表card有7896行,在card_no上有一個非聚集索引,表account有191122行,在account_no上有一個非聚集索引,試看在不同的表連接條件下,兩個SQL的執行情況:

    select sum(a.amount) from account a,
    card b where a.card_no = b.card_no(20秒)
    ---- 將SQL改為:
    select sum(a.amount) from account a,
    card b where a.card_no = b.card_no and a.
    account_no=b.account_no(< 1秒)
    ---- 分析:
    ---- 在第一個連接條件下,最佳查詢方案是將account作外層表,card作內層表,利用card上的索引,其I/O次數可由以下公式估算為:
    ---- 外層表account上的22541頁+(外層表account的191122行*內層表card上對應外層表第一行所要查找的3頁)=595907次I/O
    ---- 在第二個連接條件下,最佳查詢方案是將card作外層表,account作內層表,利用account上的索引,其I/O次數可由以下公式估算為:
    ---- 外層表card上的1944頁+(外層表card的7896行*內層表account上對應外層表每一行所要查找的4頁)= 33528次I/O
    ---- 可見,只有充份的連接條件,真正的最佳方案才會被執行。
    ---- 總結:
    ---- 1.多表操作在被實際執行前,查詢優化器會根據連接條件,列出幾組可能的連接方案并從中找出系統開銷最小的最佳方案。連接條件要充份考慮帶有索引的表、行數多的表;內外表的選擇可由公式:外層表中的匹配行數*內層表中每一次查找的次數確定,乘積最小為最佳方案。
    ---- 2.查看執行方案的方法-- 用set showplanon,打開showplan選項,就可以看到連接順序、使用何種索引的信息;想看更詳細的信息,需用sa角色執行dbcc(3604,310,302)。


    三、不可優化的where子句

    ---- 1.例:下列SQL條件語句中的列都建有恰當的索引,但執行速度卻非常慢:
    select * from record where
    substring(card_no,1,4)='5378'(13秒)
    select * from record where
    amount/30< 1000(11秒)
    select * from record where
    convert(char(10),date,112)='19991201'(10秒)
    ---- 分析:
    ---- where子句中對列的任何操作結果都是在SQL運行時逐列計算得到的,因此它不得不進行表搜索,而沒有使用該列上面的索引;如果這些結果在查詢編譯時就能得到,那么就可以被SQL優化器優化,使用索引,避免表搜索,因此將SQL重寫成下面這樣:
    select * from record where card_no like
    '5378%'(< 1秒)
    select * from record where amount
    < 1000*30(< 1秒)
    select * from record where date= '1999/12/01'
    (< 1秒)
    ---- 你會發現SQL明顯快起來!

    ---- 2.例:表stuff有200000行,id_no上有非群集索引,請看下面這個SQL:
    select count(*) from stuff where id_no in('0','1')
    (23秒)
    ---- 分析:
    ---- where條件中的'in'在邏輯上相當于'or',所以語法分析器會將in ('0','1')轉化為id_no ='0' or id_no='1'來執行。我們期望它會根據每個or子句分別查找,再將結果相加,這樣可以利用id_no上的索引;但實際上(根據showplan),它卻采用了"OR策略",即先取出滿足每個or子句的行,存入臨時數據庫的工作表中,再建立唯一索引以去掉重復行,最后從這個臨時表中計算結果。因此,實際過程沒有利用id_no上索引,并且完成時間還要受tempdb數據庫性能的影響。
    ---- 實踐證明,表的行數越多,工作表的性能就越差,當stuff有620000行時,執行時間竟達到220秒!還不如將or子句分開:
    select count(*) from stuff where id_no='0'
    select count(*) from stuff where id_no='1'
    ---- 得到兩個結果,再作一次加法合算。因為每句都使用了索引,執行時間只有3秒,在620000行下,時間也只有4秒。或者,用更好的方法,寫一個簡單的存儲過程:
    create proc count_stuff as
    declare @a int
    declare @b int
    declare @c int
    declare @d char(10)
    begin
    select @a=count(*) from stuff where id_no='0'
    select @b=count(*) from stuff where id_no='1'
    end
    select @c=@a+@b
    select @d=convert(char(10),@c)
    print @d

    ---- 直接算出結果,執行時間同上面一樣快!
    ---- 總結:
    ---- 可見,所謂優化即where子句利用了索引,不可優化即發生了表掃描或額外開銷。

    ---- 1.任何對列的操作都將導致表掃描,它包括數據庫函數、計算表達式等等,查詢時要盡可能將操作移至等號右邊。
    ---- 2.in、or子句常會使用工作表,使索引失效;如果不產生大量重復值,可以考慮把子句拆開;拆開的子句中應該包含索引。
    ---- 3.要善于使用存儲過程,它使SQL變得更加靈活和高效。
    ---- 從以上這些例子可以看出,SQL優化的實質就是在結果正確的前提下,用優化器可以識別的語句,充份利用索引,減少表掃描的I/O次數,盡量避免表搜索的發生。其實SQL的性能優化是一個復雜的過程,上述這些只是在應用層次的一種體現,深入研究還會涉及數據庫層的資源配置、網絡層的流量控制以及操作系統層的總體設計。

    1 邏輯數據庫和表的設計
      數據庫的邏輯設計、包括表與表之間的關系是優化關系型數據庫性能的核心。一個好的邏輯數據庫設計可以為優化數據庫和應用程序打下良好的基礎。

      標準化的數據庫邏輯設計包括用多的、有相互關系的窄表來代替很多列的長數據表。下面是一些使用標準化表的一些好處。

    A:由于表窄,因此可以使排序和建立索引更為迅速
    B:由于多表,所以多鏃的索引成為可能
    C:更窄更緊湊的索引
    D:每個表中可以有少一些的索引,因此可以提高insert update delete等的速度,因為這些操作在索引多的情況下會對系統性能產生很大的影響
    E:更少的空值和更少的多余值,增加了數據庫的緊湊性由于標準化,所以會增加了在獲取數據時引用表的數目和其間的連接關系的復雜性。太多的表和復雜的連接關系會降低服務器的性能,因此在這兩者之間需要綜合考慮。
      定義具有相關關系的主鍵和外來鍵時應該注意的事項主要是:用于連接多表的主鍵和參考的鍵要有相同的數據類型。

      2 索引的設計
    A:盡量避免表掃描
    檢查你的查詢語句的where子句,因為這是優化器重要關注的地方。包含在where里面的每一列(column)都是可能的侯選索引,為能達到最優的性能,考慮在下面給出的例子:對于在where子句中給出了column1這個列。
    下面的兩個條件可以提高索引的優化查詢性能!
    第一:在表中的column1列上有一個單索引
    第二:在表中有多索引,但是column1是第一個索引的列
    避免定義多索引而column1是第二個或后面的索引,這樣的索引不能優化服務器性能
    例如:下面的例子用了pubs數據庫。
    SELECT au_id, au_lname, au_fname FROM authors
    WHERE au_lname = ’White’
    按下面幾個列上建立的索引將會是對優化器有用的索引
    ?au_lname
    ?au_lname, au_fname
    而在下面幾個列上建立的索引將不會對優化器起到好的作用
    ?au_address
    ?au_fname, au_lname
    考慮使用窄的索引在一個或兩個列上,窄索引比多索引和復合索引更能有效。用窄的索引,在每一頁上將會有更多的行和更少的索引級別(相對與多索引和復合索引而言),這將推進系統性能。
    對于多列索引,SQL Server維持一個在所有列的索引上的密度統計(用于聯合)和在第一個索引上的histogram(柱狀圖)統計。根據統計結果,如果在復合索引上的第一個索引很少被選擇使用,那么優化器對很多查詢請求將不會使用索引。
    有用的索引會提高select語句的性能,包括insert,uodate,delete。
    但是,由于改變一個表的內容,將會影響索引。每一個insert,update,delete語句將會使性能下降一些。實驗表明,不要在一個單表上用大量的索引,不要在共享的列上(指在多表中用了參考約束)使用重疊的索引。
    在某一列上檢查唯一的數據的個數,比較它與表中數據的行數做一個比較。這就是數據的選擇性,這比較結果將會幫助你決定是否將某一列作為侯選的索引列,如果需要,建哪一種索引。你可以用下面的查詢語句返回某一列的不同值的數目。
    select count(distinct cloumn_name) from table_name
    假設column_name是一個10000行的表,則看column_name返回值來決定是否應該使用,及應該使用什么索引。
    Unique values Index

    5000 Nonclustered index
    20 Clustered index
    3 No index

    鏃索引和非鏃索引的選擇

    <1:>鏃索引是行的物理順序和索引的順序是一致的。頁級,低層等索引的各個級別上都包含實際的數據頁。一個表只能是有一個鏃索引。由于update,delete語句要求相對多一些的讀操作,因此鏃索引常常能加速這樣的操作。在至少有一個索引的表中,你應該有一個鏃索引。
    在下面的幾個情況下,你可以考慮用鏃索引:
    例如: 某列包括的不同值的個數是有限的(但是不是極少的)
    顧客表的州名列有50個左右的不同州名的縮寫值,可以使用鏃索引。
    例如: 對返回一定范圍內值的列可以使用鏃索引,比如用between,>,>=,<,<=等等來對列進行操作的列上。
    select * from sales where ord_date between ’5/1/93’ and ’6/1/93’
    例如: 對查詢時返回大量結果的列可以使用鏃索引。
    SELECT * FROM phonebook WHERE last_name = ’Smith’

    當有大量的行正在被插入表中時,要避免在本表一個自然增長(例如,identity列)的列上建立鏃索引。如果你建立了鏃的索引,那么insert的性能就會大大降低。因為每一個插入的行必須到表的最后,表的最后一個數據頁。
    當一個數據正在被插入(這時這個數據頁是被鎖定的),所有的其他插入行必須等待直到當前的插入已經結束。
    一個索引的葉級頁中包括實際的數據頁,并且在硬盤上的數據頁的次序是跟鏃索引的邏輯次序一樣的。

    <2:>一個非鏃的索引就是行的物理次序與索引的次序是不同的。一個非鏃索引的葉級包含了指向行數據頁的指針。
    在一個表中可以有多個非鏃索引,你可以在以下幾個情況下考慮使用非鏃索引。
    在有很多不同值的列上可以考慮使用非鏃索引
    例如:一個part_id列在一個part表中
    select * from employee where emp_id = ’pcm9809f’
    查詢語句中用order by 子句的列上可以考慮使用鏃索引

    3 查詢語句的設計

    SQL Server優化器通過分析查詢語句,自動對查詢進行優化并決定最有效的執行方案。優化器分析查詢語句來決定那個子句可以被優化,并針對可以被優化查詢的子句來選擇有用的索引。最后優化器比較所有可能的執行方案并選擇最有效的一個方案出來。
    在執行一個查詢時,用一個where子句來限制必須處理的行數,除非完全需要,否則應該避免在一個表中無限制地讀并處理所有的行。
    例如下面的例子,
    select qty from sales where stor_id=7131
    是很有效的比下面這個無限制的查詢
    select qty from sales
    避免給客戶的最后數據選擇返回大量的結果集。允許SQL Server運行滿足它目的的函數限制結果集的大小是更有效的。
    這能減少網絡I/O并能提高多用戶的相關并發時的應用程序性能。因為優化器關注的焦點就是where子句的查詢,以利用有用的索引。在表中的每一個索引都可能成為包括在where子句中的侯選索引。為了最好的性能可以遵照下面的用于一個給定列column1的索引。
    第一:在表中的column1列上有一個單索引
    第二:在表中有多索引,但是column1是第一個索引的列不要在where子句中使用沒有column1列索引的查詢語句,并避免在where子句用一個多索引的非第一個索引的索引。
    這時多索引是沒有用的。
    For example, given a multicolumn index on the au_lname, au_fname columns of the authors table in
    the pubs database,
    下面這個query語句利用了au_lname上的索引
    SELECT au_id, au_lname, au_fname FROM authors
    WHERE au_lname = ’White’
    AND au_fname = ’Johnson’
    SELECT au_id, au_lname, au_fname FROM authors
    WHERE au_lname = ’White’
    下面這個查詢沒有利用索引,因為他使用了多索引的非第一個索引的索引
    SELECT au_id, au_lname, au_fname FROM authors
    WHERE au_fname = ’Johnson’

    Copyright © 久城

    主站蜘蛛池模板: 99在线精品视频观看免费| 亚洲 无码 在线 专区| 无人在线观看完整免费版视频| 国产免费变态视频网址网站| 亚洲av无码一区二区三区网站 | 久久国产精品成人片免费| 国产精品免费看久久久无码| 亚洲视频一区二区在线观看| 水蜜桃视频在线观看免费| 免费A级毛片无码免费视| 亚洲啪啪综合AV一区| 精品在线视频免费| 成年美女黄网站色大免费视频| 久久亚洲高清观看| 色多多www视频在线观看免费| 免费鲁丝片一级观看| 亚洲毛片在线免费观看| 大地资源网高清在线观看免费| www.91亚洲| 99热在线日韩精品免费| 337p日本欧洲亚洲大胆裸体艺术| 久久精品国产亚洲av天美18| 一二三四视频在线观看中文版免费 | 亚洲精品无码久久久久久久| 69成人免费视频| 亚洲精品无码久久久久A片苍井空| 69视频在线观看高清免费| 亚洲免费视频观看| 无码国产精品一区二区免费式影视| 亚洲最大福利视频网站| 久久久国产精品无码免费专区| 免费毛片在线播放| 国产成人无码免费看片软件| 亚洲另类少妇17p| 美女无遮挡免费视频网站| 国产精品视频免费一区二区三区| h在线看免费视频网站男男| 亚洲精品一区二区三区四区乱码| 女人与禽交视频免费看| 亚洲熟妇无码一区二区三区导航| 成人免费视频观看无遮挡|