整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          selenium之css定位小結

          selenium之css定位小結

          大部分人在使用selenium定位元素時,用的是xpath定位,因為xpath基本能解決定位的需求。css定位往往被忽略掉了,其實css定位也有它的價值,css定位更快,語法更簡潔。
          這一篇css的定位方法,主要是對比上一篇的xpath來的,基本上xpath能完成的,css也可以做到。兩篇對比學習,更容易理解。

          CSS 選擇器:

          常見符號:

          #表示 id選擇器
          .表示 class選擇器
          >表示子元素,層級
          一個空格也表示子元素,但是是所有的后代子元素,相當于 xpath 中的相對路徑

          一、css:屬性定位

          1.css可以通過元素的id、class、標簽這三個常規(guī)屬性直接定位到

          2.如下是百度輸入框的的html代碼:

          <input id="kw" class="s_ipt" type="text" autocomplete="off" maxlength="100" name="wd"/>

          3.css用#號表示id屬性,如:#kw

          4.css用.表示class屬性,如:.s_ipt

          5.css直接用標簽名稱,無任何標示符,如:input

          二、css:其它屬性

          1.css除了可以通過標簽、class、id這三個常規(guī)屬性定位外,也可以通過其它屬性定位

          2.以下是定位其它屬性的格式
          [name=wd] [autocomplete='off'][maxlength='255']

          三、css:標簽

          css頁可以通過標簽與屬性的組合來定位元素
          input.s_ipt input#kw input[id='kw']

          四、css:層級關系

          //form的id屬性
          form#form>span>input
          //form的class屬性
          form.fm>span>input

          五、css:索引

          css也可以通過索引nth-child(1)來定位子元素,直接翻譯過來就是第幾個小孩
          總結:選擇標簽后,找第幾個小孩即可
          Select控件第三個Opel
          #select>select>option:nth-child(3)
          CheckBox第一個Volvo
          #checkbox>input:nth-child(1)

          CheckBox第二個Saab
          #checkbox>input:nth-child(4)
          RadioBox第二個Saab
          #radio>input:nth-child(4)


          通過索引nth-of-type(2)來定位子元素,按照分類指定

          選擇select的saab
          #select>select>option:nth-of-type(2);

          選擇 id 為 radio 的 div 下的第 1 個子節(jié)點
          div#radio>input:nth-of-type(4)+label

          選擇id 為radio 的div 下的第4 個input 節(jié)點之后挨著的 label
          節(jié)點
          div#radio>input:nth-of-type(4)~label

          六、css:邏輯運算

          css同樣也可以實現(xiàn)邏輯運算,同時匹配兩個屬性,這里跟xpath不一樣,無需寫and關鍵字
          [type='checkbox'][name='checkbox1']

          css語法遠遠不止上面提到的,還有更多更強大定位策略,有興趣的同學可以繼續(xù)深入研究!

          如覺得文章對您有幫助,還請幫忙轉發(fā)!

          者 | Amazing10

          責編 | 屠敏

          頭圖 | CSDN 下載自視覺中國

          本文為「業(yè)余碼農」投稿

          索引的概念基本所有人都會遇到過,就算沒有了解過數(shù)據(jù)庫中的索引,在生活中也不可避免的接觸到。比方說書籍的目錄,字典的查詢頁,圖書館的科目檢索等等。其實這些都是一種索引,并且所起到的作用大同小異。

          而對于數(shù)據(jù)庫而言,只不過是將索引的概念抽象出來,讓建立索引的過程更為靈活而自由,從而可以在不同的場景下優(yōu)化數(shù)據(jù)庫的查詢效率。

          索引在數(shù)據(jù)庫的實際應用場景中十分普遍,數(shù)據(jù)庫的優(yōu)化也離不開對索引的優(yōu)化。同時,索引相關的知識也是面試高頻的考點之一,是應試者理論結合現(xiàn)實最為直接的體現(xiàn)。

          因此,本文將從基礎理論出發(fā),介紹 MySQL 按照邏輯角度的索引分類和實現(xiàn),通過數(shù)據(jù)結構的實現(xiàn)原理闡述不同結構對建立索引帶來的優(yōu)劣勢,同時針對物理存儲的方式對索引的組織特點和應用場景進行分析。最后根據(jù)不同的應用場景盡可能的探究如何建立起高性能的索引。文章結構如下:

          概念

          什么是索引?

          索引似乎并沒有十分明確的定義,更多的是一種定性的描述。簡單來講,索引就是一種將數(shù)據(jù)庫中的記錄按照特殊形式存儲的數(shù)據(jù)結構。通過索引,能夠顯著地提高數(shù)據(jù)查詢的效率,從而提升服務器的性能。

          專業(yè)一點來說呢,索引是一個排好序的列表,在這個列表中存儲著索引的值和包含這個值的數(shù)據(jù)所在行的物理地址。在數(shù)據(jù)庫十分龐大的時候,索引可以大大加快查詢的速度,這是因為使用索引后可以不用掃描全表來定位某行的數(shù)據(jù),而是先通過索引表找到該行數(shù)據(jù)對應的物理地址然后訪問相應的數(shù)據(jù)。

          說起索引,其實并不是 MySQL 數(shù)據(jù)庫特有的機制,在關系型數(shù)據(jù)庫中都會有類似不同的實現(xiàn)。這里我們也只是討論 MySQL 數(shù)據(jù)庫中的索引實現(xiàn)。

          事實上,說是 MySQL 的索引其實并不準確。因為在 MySQL 中,索引是在存儲引擎層而不是服務器層實現(xiàn)的。這意味著我們所討論的索引準確來說是 InnoDB 引擎或 MyISAM 引擎或其它存儲引擎所實現(xiàn)的。

          所以索引即便是在 MySQL 中也沒有統(tǒng)一的標準,不同存儲引擎的所實現(xiàn)的索引工作方式也并不一樣。不是所有的存儲引擎都支持相同類型的索引,即便是多個引擎支持同一種類型的索引,其底層的實現(xiàn)也可能不同。

          為什么需要索引

          說了這么多,索引似乎就是給數(shù)據(jù)庫添加了一個「目錄頁」,能夠方便查詢數(shù)據(jù)。但是索引的作用就僅此而已了嗎,為什么需要大費周章的建立并優(yōu)化索引?

          說個題外話,我其實查字典從來都不喜歡查目錄頁,無論是查中文還是英文。因為覺得那樣很慢,一個個找索引,效率很低。我習慣用的方式就是直接翻開字典,根據(jù)翻開的位置進行前后調整。比方說我想找「醬 JIANG」字,會先隨機翻到一頁,可能是「F」開頭,在「J」前面,就往后翻一點;如果隨機翻到「L」,那就往前翻一點。重復直至找到。

          這大概就是類似于二分查找的方式,看起來好像是擺脫了索引的束縛,并且也能夠獲得比較高的查詢效率。但是其實轉念一想,在計算機的運行處理中,「一個個找索引」這個過程其實非常快,不能跟我們手動比對偏旁部首的效率相提并論。同時,為什么我可以直接翻開字典根據(jù)字母進行調整呢,這其實不就是因為我的腦子里存在一個大概的「索引表」,知道每個字母大概對應于字典的哪一個位置。雖然是模糊的,但卻是真實存在的。(好不容易強行解釋了一波...)

          如此一來,可以看出索引的一大好處是如其概念中所提及的,使用索引后可以不用掃描全表來定位某行的數(shù)據(jù),而是先通過索引表找到該行數(shù)據(jù)對應的物理地址然后訪問相應的數(shù)據(jù)。這樣的方式自然減少了服務器在響應時所需要對數(shù)據(jù)庫掃描的數(shù)據(jù)量。

          不僅如此,在執(zhí)行數(shù)據(jù)庫的范圍查詢時,若不使用索引,那么MySQL會先掃描數(shù)據(jù)庫的所有行數(shù)據(jù)并從中篩選出目標范圍內的行記錄,將這些行記錄進行排序并生成一張臨時表,然后通過臨時表返回用戶查詢的目標行記錄。這個過程會涉及到臨時表的建立和行記錄的排序,當目標行記錄較多的時候,會大大影響范圍查詢的效率。

          所以當添加索引時,由于索引本身具有的順序性,使得在進行范圍查詢時,所篩選出的行記錄已經(jīng)排好序,從而避免了再次排序和需要建立臨時表的問題。

          同時,由于索引底層實現(xiàn)的有序性,使得在進行數(shù)據(jù)查詢時,能夠避免在磁盤不同扇區(qū)的隨機尋址。使用索引后能夠通過磁盤預讀使得在磁盤上對數(shù)據(jù)的訪問大致呈順序的尋址。這本質上是依據(jù)局部性原理所實現(xiàn)的。

          局部性原理:當一個數(shù)據(jù)被用到時,其附近的數(shù)據(jù)也通常會馬上被使用。程序運行期間所需要的數(shù)據(jù)通常比較集中。由于磁盤順序讀取的效率很高(不需要尋道時間,只需很少的旋轉時間) ,因此對于具有局部性的程序來說,磁盤預讀可以提高I/O效率。

          磁盤預讀要求每次都會預讀的長度一般為頁的整數(shù)倍。而且數(shù)據(jù)庫系統(tǒng)將一個節(jié)點的大小設為等于一個頁,這樣每個節(jié)點只需要一次 I/O 就可以完全載入。這里的頁是通過頁式的內存管理所實現(xiàn)的,概念在這里簡單提一嘴。

          分頁機制就是把內存地址空間分為若干個很小的固定大小的頁,每一頁的大小由內存決定。這樣做是為了從虛擬地址映射到物理地址,提高內存和磁盤的利用率。

          所以呢,總結一下。索引的存在具有很大的優(yōu)勢,主要表現(xiàn)為以下三點:

          • 索引大大減少了服務器需要掃描的數(shù)據(jù)量

          • 索引可以幫助服務器避免排序和臨時表

          • 索引可以將隨機 I/O 變成順序 I/O

          以上三點能夠大大提高數(shù)據(jù)庫查詢的效率,優(yōu)化服務器的性能。因此一般來說,為數(shù)據(jù)庫添加高效的索引對數(shù)據(jù)庫進行優(yōu)化的重要工作之一。

          不過,凡事都有兩面性。索引的存在能夠帶來性能的提升,自然在其它方面也會付出額外的代價。

          索引本身以表的形式存儲,因此會占用額外的存儲空間;

          索引表的創(chuàng)建和維護需要時間成本,這個成本隨著數(shù)據(jù)量增大而增大;

          構建索引會降低數(shù)據(jù)的修改操作(刪除,添加,修改)的效率,因為在修改數(shù)據(jù)表的同時還需要修改索引表;

          所以對于非常小的表而言,使用索引的代價會大于直接進行全表掃描,這時候就并不一定非得使用索引了。沒辦法,成年人的世界總是這么的趨利避害。

          邏輯分類

          從邏輯的角度來對索引進行劃分的話,可以分為單列索引、全文索引、組合索引和空間索引。其中單列索引又可分為主鍵索引、唯一索引和普通索引。這里的邏輯可以理解為從 SQL 語句的角度,或者是從數(shù)據(jù)庫關系表的角度。下面就簡單介紹這些索引的作用和用法,以及在修改表的時候如何添加索引。

          主鍵索引

          即主索引,根據(jù)主鍵建立索引,不允許重復,不允許空值;

          主鍵:數(shù)據(jù)庫表中一列或列組合(字段)的值,可唯一標識表中的每一行。

          加速查詢 + 列值唯一(不可以有)+ 表中只有一個

          ALTER TABLE 'table_name' ADD PRIMARY KEY pk_index('col');

          唯一索引

          用來建立索引的列的值必須是唯一的,允許空值。唯一索引不允許表中任何兩行具有相同的索引值。比方說,在 employee 表中職員的姓 name 上創(chuàng)建了唯一索引,那么就表示任何兩個員工都不能同姓。

          加速查詢 + 列值唯一(可以有)

          ALTER TABLE 'table_name' ADD UNIQUE index_name('col');

          普通索引

          用表中的普通列構建的索引,沒有任何限制。

          僅加速查詢

          ALTER TABLE 'table_name' ADD INDEX index_name('col');

          全文索引

          用大文本對象的列構建的索引

          ALTER TABLE 'table_name' ADD FULLTEXT INDEX ft_index('col');

          組合索引

          用多個列組合構建的索引,這多個列中的值不允許有空值。

          多列值組成一個索引,專門用于組合搜索,其效率大于索引合并。

          ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3');

          在對多列組合建立索引時,會遵循「最左前綴」原則。

          最左前綴原則:顧名思義,就是最左優(yōu)先,上例中我們創(chuàng)建了 (col1, col2, col3) 多列索引,相當于創(chuàng)建了 (col1) 單列索引,(col1, col2) 組合索引以及 (col1, col2, col3) 組合索引。

          所以當我們在創(chuàng)建多列索引時,要根據(jù)業(yè)務場景,將 where 子句中使用最頻繁的一列放在最左邊。

          空間索引

          對空間數(shù)據(jù)類型的字段建立的索引,底層可通過 R 樹實現(xiàn)。只不過使用較少,了解即可。

          實現(xiàn)原理

          我們知道,索引的底層本身就是通過數(shù)據(jù)結構來進行實現(xiàn)的。那么根據(jù)其底層的結構,常見的索引類型可分為哈希索引,BTree 索引,B+Tree 索引等。這里我們就主要來介紹這三種索引背后的實現(xiàn)機制。

          哈希索引

          顧名思義,哈希索引是通過哈希表實現(xiàn)的。哈希表的特點在之前的文章「九大數(shù)據(jù)結構」中已經(jīng)詳細介紹過。通過哈希表的鍵值之間的對應關系,能夠在查詢時精確匹配索引的所有列。哈希索引將所有的根據(jù)索引列計算出來的哈希碼存儲在索引中,同時將指向每個數(shù)據(jù)行的指針保存在哈希表中。

          上圖是通過哈希索引查詢行數(shù)據(jù)的示意圖,可以發(fā)現(xiàn)哈希索引同樣會發(fā)生哈希沖突,并且是通過鏈地址法解決沖突的。當發(fā)送沖突時,還需要對鏈表進行遍歷對比,才能夠找到最終的結果。

          在 MySQL 中,只有 Memory 存儲引擎顯式的支持哈希索引,而innodb是隱式支持哈希索引的。

          這里的隱式支持是指,innodb引擎有一個特殊的功能 “自適應哈希索引”,當innodb注意到一些索引值被使用的非常頻繁時,且符合哈希特點(如每次查詢的列都一樣),它會在內存中基于 B-Tree 索引之上再創(chuàng)建一個哈希索引。這樣就讓 BTree 索引也具有哈希索引的一些有點。這是一個完全自動的、內部的行為。

          由于哈希結構的特殊性,其用于非常高的檢索效率,通過哈希函數(shù)的映射可以一步到位。但是同樣也是因為結構的特殊,導致哈希索引只適用于某些特定的場合。哈希索引的限制[1]:

          1. 不支持范圍查詢,比如 WHERE a > 5;只支持等值比較查詢,包括=、IN 、<=>

          2. 無法被用來避免數(shù)據(jù)的排序操作;因為經(jīng)過了哈希函數(shù)的映射過程,使得丟失了哈希前后的大小關系,從而無法按照索引值的順序存儲。

          3. 不支持部分索引列的匹配查找,因為哈希索引始終使用索引列的全部內容來計算哈希值。例如在數(shù)據(jù)列 (A, B) 上建立哈希索引,如果查詢只有數(shù)據(jù)列 A,則無法使用該索引。

          4. 無法避免表掃描。因為當出現(xiàn)哈希沖突的時候,存儲引擎必須遍歷鏈表(拉鏈法)中所有的行指針,逐行進行比較,直到找到所有符合條件的行。

          5. 哈希沖突很多的情況下,其索引維護的代價很高,并且性能并不一定會比 BTree 索引高。

          BTree 索引

          BTree 實際上是一顆多叉平衡搜索樹。從名字可以看出,BTree 首先是一顆多叉搜索樹,這意味著它是具有順序的;其次 BTree 還是平衡的,這意味著它的左右子樹高度差小于等于1。

          事實上一顆 BTree 需要滿足以下幾個條件:

          每個葉子結點的高度都是一樣的;

          每個非葉子結點由 n-1 個 key 和 n 個指針 point 組成,其中 d<=n<=2d, key 和 point 相互間隔,結點兩端一定是 key;

          葉子結點指針都為 ;

          非葉子結點的key都是 [key, data] 二元組,其中 key 表示作為索引的鍵,data 為鍵值所在行的數(shù)據(jù);

          一顆常見的BTree樹見下圖。

          這是一顆三階的BTree,可通過鍵值的大小排序進行數(shù)據(jù)的查詢和檢索,其中葉子節(jié)點的指針都為空,因此省略沒畫。從上圖可以發(fā)現(xiàn),BTree 的樹形狀相較于我們之前常見的二叉樹等結構,更為扁平和矮胖。

          之所以這樣設計,還是跟磁盤讀取的特點有關。我們知道在建立索引時,也是需要占據(jù)物理空間的。而實際上當數(shù)據(jù)量比較大的時候,索引文件的大小也十分嚇人。考慮到一個表上可能有多個索引、組合索引、數(shù)據(jù)行占用更小等情況,索引文件的大小可能達到物理盤中數(shù)據(jù)的1/10,甚至可達到1/3。

          這就意味著索引無法全部裝入內存之中。當通過索引對數(shù)據(jù)進行訪問時,不可避免的需要對磁盤進行讀寫訪問。同時我們還知道,內存的讀寫速度是磁盤的幾個數(shù)量級。因此在對索引結構進行設計時要盡可能的減少對磁盤的讀寫次數(shù),也就是所謂的磁盤 I/O 次數(shù)。

          這也就是索引會采用 BTree 這種扁平樹結構的原因,樹的層數(shù)越少,磁盤I/O的次數(shù)自然就越少。不僅如此,我們上面提到過磁盤預讀的局部性原理。根據(jù)這個原理再加上頁表機制,能夠在進行磁盤讀取的時候更大化的提升性能。

          BTree 相較于其它的二叉樹結構,對磁盤的 I/O 次數(shù)已經(jīng)非常少了。但是在實際的數(shù)據(jù)庫應用中仍有些問題無法解決。

          一是無法定位到數(shù)據(jù)行。通過 BTree 可以根據(jù)主鍵的排序定位出主鍵的位置,但是由于數(shù)據(jù)表的記錄有多個字段,僅僅定位到主鍵是不夠,還需要定位到數(shù)據(jù)行。雖然這個問題可以通過在 BTree 的節(jié)點中存儲數(shù)據(jù)行或者增加定位的字段,但是這種方式會使得 BTree 的深度大幅度提高,從而也導致 I/O 次數(shù)的提高。

          二是無法處理范圍查詢。在實際的應用中,數(shù)據(jù)庫范圍查詢的頻率非常高,而 BTree 只能定位到一個索引位置。雖然可以通過先后查詢范圍的左右界獲得,但是這樣的操作實際上無法很好的利用磁盤預讀的局部性原理,先后查詢可能會造成通過預讀取的物理地址離散,使得 I/O 的效率并不高。

          三是當數(shù)據(jù)量一大時,BTree的高度依舊會變得很高,搜索效率還是會大幅度的下降。

          問題總是推動改進的前提。基于以上的問題考慮,就出現(xiàn)了對 BTree 的優(yōu)化版本,也就是 B+Tree。

          B+Tree索引

          B+Tree 一看就是在 BTree 的基礎上做了改進,那么到底改變了什么呢。廢話不多說,先上圖。

          上圖實際上是一種帶有順序索引的 B+Tree,與最基本的 B+Tree 的區(qū)別就在于葉子節(jié)點是否通過指針相連。一般數(shù)據(jù)庫中常用的結構都是這種帶有順序索引的 B+Tree。后文探討的也都是帶順序索引的 B+Tree 結構。

          對比 BTree 和 B+Tree,我們可以發(fā)現(xiàn)二者主要在以下三個方面上的不同:

          1. 非葉子節(jié)點只存儲鍵值信息,不再存儲數(shù)據(jù)。

          2. 所有葉子節(jié)點之間都有一個鏈指針,指向下一個葉子節(jié)點。

          3. 數(shù)據(jù)都存放在葉子節(jié)點中。

          看著 B+Tree,像不像是一顆樹與一個有序鏈表的結合體。因而其實 B+Tree 也就是帶有樹和鏈表的部分優(yōu)勢。樹結構使得有序檢索更為簡單,I/O 次數(shù)更少;有序鏈表結構使得可以按照鍵值排序的次序遍歷全部記錄。

          B+Tree 在作為索引結構時能夠帶來的好處有:

          一,I/O 次數(shù)更少。這是因為上文也說過,BTree 的節(jié)點是存放在內存頁中的。那么在相同的內存頁大小(一般為4k)的情況下,B+Tree 能夠存儲更多的鍵值,那么整體樹結構的高度就會更小,需要的 I/O 次數(shù)也就越小。

          二,數(shù)據(jù)遍歷更為方便。這個優(yōu)勢很明顯是由有序鏈表帶來的。通過葉子節(jié)點的鏈接,使得對所有數(shù)據(jù)的遍歷只需要在線性的鏈表上完成,這就非常適合區(qū)間檢索和范圍查詢。

          三,查詢性能更穩(wěn)定。這自然是由于只在葉子節(jié)點存儲數(shù)據(jù),所以所有數(shù)據(jù)的查詢都會到達葉子節(jié)點,同時葉子節(jié)點的高度都相同,因此理論上來說所有數(shù)據(jù)的查詢速度都是一致的。

          正是由于 B+Tree 優(yōu)秀的結構特性,使得常用作索引的實現(xiàn)結構。在 MySQL 中,存儲引擎 MyISAM 和 InnoDB 都分別以 B+Tree 實現(xiàn)了響應的索引設計。

          物理存儲

          雖說 B+Tree 結構都可以用在 MyISAM 和 InnoDB,但是這二者對索引的在物理存儲層次的實現(xiàn)方式卻不相同。InnoDB 實現(xiàn)的是聚簇索引,而 MyISAM 實現(xiàn)的卻是非聚簇索引。在介紹聚簇索引之前,我們需要先了解以下啥是佩奇,不對,是啥是「主鍵索引」和「輔助索引」。

          其實概念很簡單。我們剛剛不是在講 B+Tree 的時候說過,樹的非葉子節(jié)點只存儲鍵值。沒錯就是這個鍵值,當這個鍵值是數(shù)據(jù)表的主鍵時,那么所建立的就是主鍵索引;當這個鍵值是其它字段的時候,就是輔助索引。因而可以得出,主鍵索引只能有一個,而輔助索引卻可以有很多個。

          聚簇索引和非聚簇索引的區(qū)別也就是根據(jù)其對應的主鍵索引和輔助索引的不同特點而實現(xiàn)的。

          聚簇索引

          說回聚簇索引。先丟個定義。

          聚簇索引的主鍵索引的葉子結點存儲的是鍵值對應的數(shù)據(jù)本身;輔助索引的葉子結點存儲的是鍵值對應的數(shù)據(jù)的主鍵鍵值。

          這句話的信息量挺大的。首先,分析第一句話,主鍵索引的葉子節(jié)點存儲的是鍵值對應的數(shù)據(jù)本身。

          我們知道,主鍵索引存儲的鍵值就是主鍵。那么也就是說,聚簇索引的主鍵索引,在葉子節(jié)點中存儲的是主鍵和主鍵對應的數(shù)據(jù)。數(shù)據(jù)和主鍵索引是存儲在一起的,一起作為葉子節(jié)點的一部分。

          然后,分析第二句話,輔助索引的葉子結點存儲的是鍵值對應的數(shù)據(jù)的主鍵鍵值。

          我們又知道,輔助索引存儲的鍵值是非主鍵的字段。那就也就是說,通過輔助索引,可以找到非主鍵字段對應的數(shù)據(jù)行中的主鍵。

          重點來了。當然主鍵索引和輔助索引一結合,能干啥呢。當直接采用主鍵進行檢索時,可通過主鍵索引直接獲得數(shù)據(jù);而當采用非主鍵進行檢索時,先需要通過輔助索引來獲得主鍵,然后再通過這個主鍵在主鍵索引中找到對應的數(shù)據(jù)行。

          舉個例子吧。假設有這么一個數(shù)據(jù)表。

          那么采用聚簇索引的存儲方式,對應的主鍵索引為:(主鍵為ID)

          對應的輔助索引為:(鍵值為Name,大概的意思):

          所以當使用where ID=7這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對應的葉節(jié)點,之后獲得行數(shù)據(jù)。對Name列進行條件搜索,則需要兩個步驟:第一步在輔助索引B+樹中檢索Name,到達其葉子節(jié)點獲取對應的主鍵。第二步使用主鍵在主鍵索引B+樹種再執(zhí)行一次B+樹檢索操作,最終到達葉子節(jié)點即可獲取整行數(shù)據(jù)。

          最后把以上過程整理總結一下,聚簇索引實際上的過程就分為以下兩個過程。現(xiàn)在這個圖應該能夠看懂了吧。

          非聚簇索引

          學完了聚簇索引,非聚簇索引就簡單多啦。同樣,先上定義。

          非聚簇索引的主鍵索引和輔助索引幾乎是一樣的,只是主索引不允許重復,不允許空值,他們的葉子結點都存儲指向鍵值對應的數(shù)據(jù)的物理地址。

          與聚簇索引來對比著看,上面的定義能夠說明什么呢。首先,主鍵索引和輔助索引的葉子結點都存儲著鍵值對應的數(shù)據(jù)的物理地址,這說明無論是主鍵索引還是輔助索引都能夠通過直接獲得數(shù)據(jù),而不需要像聚簇索引那樣在檢索輔助索引時還得多繞一圈。

          同時還說明一個點,葉子結點存儲的是物理地址,那么表示數(shù)據(jù)實際上是存在另一個地方的,并不是存儲在B+樹的結點中。這說明非聚簇索引的數(shù)據(jù)表和索引表是分開存儲的。

          同樣,對非聚簇索引的檢索過程來個總結。

          無論是主鍵索引還是輔助索引的檢索過程,都只需要通過相應的 B+Tree 進行搜索即可獲得數(shù)據(jù)對應的物理地址,然后經(jīng)過依次磁盤 I/O 就可訪問數(shù)據(jù)。

          對比聚簇索引和非聚簇索引,可以發(fā)現(xiàn)二者最主要的區(qū)別就是在于是否在 B+Tree 的節(jié)點中存儲數(shù)據(jù),也就是數(shù)據(jù)和索引是否存儲在一起。這個區(qū)別導致最大的問題就是聚簇索引的索引的順序和數(shù)據(jù)本身的順序是相同的,而非聚簇索引的順序跟數(shù)據(jù)的順序沒有啥關系。

          索引優(yōu)化

          介紹了這么多的索引,其實最終都是為了建立高性能的索引策略,對數(shù)據(jù)庫中的索引進行優(yōu)化。索引的優(yōu)化有很多角度,針對特定的業(yè)務場景可采用不同的優(yōu)化策略。這里考慮到文章篇幅,就不具體介紹,下次再出一篇專門講索引優(yōu)化的文章。簡單列舉一下在進行優(yōu)化時可以考慮的幾個方向:

          1 獨立的列。索引列不能是表達式的一部分,也不能是函數(shù)的參數(shù)。

          2 前綴索引和索引選擇性。這二者實際上是相互制約的關系,制約條件在于前綴的長度。一般應選擇足夠長的前綴以保證較高的選擇性(保證查詢效率),同時又不能太長以便節(jié)省空間。

          3 盡量使用覆蓋索引。覆蓋索引是指一個索引包含所有需要查詢的字段的值,這樣在查詢時只需要掃描索引而無須再去讀取數(shù)據(jù)行,從而極大的提高性能。

          4 使用索引掃描來做排序。要知道,掃描索引本身是很快的,在設計索引時,可盡可能的使用同一個索引既滿足排序,又滿足查找行數(shù)據(jù)。

          最后,在建立索引時給幾個小貼士:

          1 優(yōu)先使用自增key作為主鍵

          2 記住最左前綴匹配原則

          3 索引列不能參與計算

          4 選擇區(qū)分度高的列作索引

          5 能擴展就不要新建索引

          總結

          索引的概念和原理是我們在了解和精通數(shù)據(jù)庫過程中無法逃避的重點,而事實上建立高性能的索引對實際的應用場景也具有重要意義。本文的目的依舊是由淺入深的介紹索引這么個東西,從概念到實現(xiàn)再到最終的優(yōu)化策略。

          點到為止,學無止境。掌握了基本的理論和概念后,還需要在實際的服務器開發(fā)場景中針對具體的問題和服務進行索引優(yōu)化方案的設計和使用。功力不夠,仍需努力。

          Reference

          • 高性能 MySQL,Baron Schwartz 等人著,電子工業(yè)出版社

          公眾號碼海系列文章:

          • https://www.jianshu.com/p/9e9aca844c13

          • https://www.runoob.com/mysql/mysql-index.html

          • https://www.cnblogs.com/Aiapple/p/5693239.html

          • https://blog.csdn.net/tongdanping/article/details/79878302

          • https://www.cnblogs.com/igoodful/p/9361500.html

          文分享自華為云社區(qū) 《華為云GES持久化圖數(shù)據(jù)庫復合索引介紹-云社區(qū)-華為云》,作者:村頭樹下。

          本文章主要介紹索引的作用,以及如何實現(xiàn)這種功能,希望可以幫助理解索引的作用以及如何使用索引

          1. 什么是復合索引

          復合索引是用戶手動建立的用于加速查詢的一類額外數(shù)據(jù)。詳細參數(shù)可以參考規(guī)格文檔

          https://support.huaweicloud.com/api-ges/ges_03_0454.html

          2. 復合索引能做什么

          復合索引有兩類。一是label索引,用于加速label的掃描。二是屬性索引,用于加速屬性過濾。

          這里列舉了一些常用接口(語句)與索引的關系

          api接口

          索引加速方式

          summary

          掃描label索引,統(tǒng)計各label點邊數(shù)目

          match (n:user) return count(*)

          掃描點label索引,統(tǒng)計label為user的點數(shù)目

          match ()-[r:label]-() return count?

          掃描邊label索引,統(tǒng)計指定label點數(shù)目

          match (n:user) return n limit 1

          通過點label索引快速尋找label為user的點

          match (n:user) where n.age > 10 return n limit 1

          僅有l(wèi)abel索引時掃描label索引,尋找user的點,然后進行屬性過濾。當存在age屬性索引時直接使用屬性索引定位到目標點

          match (n:user) where n.age in [1, 10] return n limit 1

          同上

          3. 無索引時如何查詢

          首先了解無索引的情況下,查詢的邏輯,才可以理解索引在此基礎上做了什么使得查詢能夠加速。查詢邏輯主要與兩個方面有關:數(shù)據(jù)結構,以及數(shù)據(jù)訪問方式,以及查詢場景。

          a) 原始點結構

          持久化版本所有數(shù)據(jù)都是以KV(鍵值對)的方式存儲在分布式KV數(shù)據(jù)庫中,在沒有建立索引的時候,數(shù)據(jù)庫中僅有原始點邊KV。以點數(shù)據(jù)結構為例:

          Key:

          Value:

          key的開始部分為kVType,這是所有數(shù)據(jù)都會存在的固定前綴,用以區(qū)分不同類型的數(shù)據(jù)。然后是Vid是全局唯一點id。Labelid是標識label的內置編碼。Value則是屬性的數(shù)據(jù)。

          b) 數(shù)據(jù)訪問方式

          所有的圖數(shù)據(jù)的查詢最終都是依托于KV數(shù)據(jù)庫的訪問。常用的訪問KV數(shù)據(jù)的方式有兩種:

          1. 精確查詢接口,指定完整的key查詢value
          2. 前綴查詢接口,僅指定key的前綴部分,查詢所有key的前綴匹配的KV數(shù)據(jù)對。前綴查相對來說會更加頻繁的使用。一個場景可能會需要多次前綴查,而前綴查的次數(shù)越多,結果越多,相應的此場景響應速度就越慢。前綴查結果大小直接與前綴的長度有關,前綴越長或者越精確,那么前綴查的結果越少。需要的計算量也越少。相應速度就會越快。

          c) 查詢場景:

          常見查詢場景的對應的kv層接口調用:

          場景

          KV接口及調用次數(shù)

          查詢速度

          對應Cypher語句

          指定id過濾

          前綴查 * 1

          快,由于KVType和Vid已知,可以拼出前綴,同時一個id一般不會有太多l(xiāng)abel,前綴查的結果不會特別多。

          match(n) where id(n)=‘0’ return n

          指定label過濾

          前綴查

          n + 過濾

          m

          慢, 由于不知道Vid,所以只能先拼出只有KVType的前綴,然后前綴查出所有點,再逐個過濾Label,點數(shù)據(jù)較多時,會有多次前綴查,分批獲取再過濾。

          match(n:Label) return n

          指定label+屬性過濾

          前綴查

          n + 過濾

          m

          慢, 查詢前綴為KvType,遍歷全圖點,先進行Label過濾,再進行屬性過濾

          match (n:Label) where n.prop=‘xx’ return n

          指定屬性過濾

          前綴查

          n + 過濾

          m

          非常慢, 查詢前綴為KvType,遍歷全圖點,全部進行屬性過濾

          match (n) where n.prop=‘xx’ return n

          可見,除了指定id的查詢,其他所有查詢均非常慢。這些查詢都需要進行全圖點掃描加過濾的方式來獲取結果。這與查詢出來的結果數(shù)目無關。對于較大的圖來說,這樣的查詢代價是十分巨大的。

          4. 復合索引如何加速

          查詢慢的場景無外乎兩種場景,label查詢或者屬性查詢。在沒有索引的情況下,這兩種查詢都是建立在全局點掃描的基礎上,進行過濾。當有效數(shù)據(jù)占比越低(例如全局點1w,目標點僅有1個),這種掃描方式就越顯得不劃算。

          對于這兩種場景,我們可以建立對應的索引。索引本身也是KV數(shù)據(jù)。所以其key的布局就決定了其功能。

          1.對于label過濾場景,索引的key的格式為:

          對于每一個點,都會有一條對應的Label索引KV。

          當需要過濾特定Label時,可以拼出KVType+Label的前綴,利用kv數(shù)據(jù)底座的前綴查接口,就能直接將所有符合條件的點過濾出來。

          2. 對于屬性過濾的場景,索引的key格式為:

          屬性索引只針對個別過濾較為頻繁的屬性而建立。所以也只會對包含此屬性的點才會生成屬性索引kv。相比于Label索引這里只是多了一個property字段。此字段填的是Vid對應點的屬性的值。需要注意的是,property字段并不包含全部的點屬性,僅僅是待過濾屬性的值。

          當進行屬性查詢時,由于知道目標值(例如where n.prop=1,目標值就是1)。直接拼出KVTypr+Label+Property,調用前綴查詢接口。即可查出所有符合條件的點。

          當利用索引查出匹配的索引KV之后,就可以很方便的拿到對應的VId。然后根據(jù)此Vid,就能快速查詢到這個點的屬性,或者鄰居等信息。

          5. 索引建立的若干建議

          索引并不是沒有代價的,雖然它能加速查詢,但是會降低寫操作的性能,以及耗費更多的磁盤空間。所以建立索引之前需要考慮是不是必要的。這可以從數(shù)據(jù)區(qū)分度,數(shù)據(jù)大小,以及訪問頻率三個方面來評估。

          • 數(shù)據(jù)區(qū)分度:對于屬性索引建議在過濾性好的屬性上建立。值分布較為分散,比較適合建立。例如身份證號,手機號。但是對于性別這種屬性,就不建議為此建立。對于label索引,如果圖里面只有一個label,那么建label索引其實也是沒有什么必要的,但是大部分情況,label索引都是必要的。
          • 數(shù)據(jù)大小:這主要是針對屬性索引來說的,在已經(jīng)有Label索引的前提下,如果某個label下的點邊數(shù)目很少,即使掃描所有l(wèi)abel代價也不高,這時候沒有必要再為其建立屬性索引。
          • 訪問頻率:這一點很好理解,只對頻繁在where子句中出現(xiàn)的屬性建立索引。

          關注#華為云開發(fā)者聯(lián)盟# 點擊下方,第一時間了解華為云新鮮技術~

          華為云博客_大數(shù)據(jù)博客_AI博客_云計算博客_開發(fā)者中心-華為云


          主站蜘蛛池模板: 久久精品无码一区二区三区| 午夜福利国产一区二区| 国产乱人伦精品一区二区在线观看| 无码精品久久一区二区三区 | 无码毛片一区二区三区中文字幕| 精品少妇ay一区二区三区| 三上悠亚一区二区观看| 亚洲AV综合色一区二区三区| 成人精品视频一区二区三区尤物| 亚洲视频一区网站| 亚洲AⅤ视频一区二区三区| 中文字幕乱码亚洲精品一区| 91国在线啪精品一区| 精品乱码一区内射人妻无码| 国产高清一区二区三区视频| 亚欧在线精品免费观看一区 | 国产精品无码一区二区在线| 久久久久人妻一区精品色| 亚洲AV无码一区二三区| 国产一区二区在线|播放| 国精产品999一区二区三区有限 | 日韩一区二区视频| 亚洲一区电影在线观看| 无码av免费一区二区三区| 在线精品亚洲一区二区三区| 国产伦精品一区二区三区视频猫咪| 免费视频精品一区二区| 亚洲乱码国产一区网址| 亚洲男人的天堂一区二区| 国产无码一区二区在线| 久久国产精品一区| 一区二区三区在线播放视频| 一区二区高清视频在线观看| 精品视频一区二区三区四区五区| 精品视频在线观看你懂的一区| 国产美女av在线一区| 蜜桃传媒视频麻豆第一区| 久久精品无码一区二区无码| 国产精品视频一区麻豆| 国产精品无码一区二区三区不卡| 国产精品熟女视频一区二区|