簡體   English   中英

何時在SQL表字段(MySQL)上添加索引?

[英]When to add an index on a SQL table field (MySQL)?

我被告知如果你知道你經常使用一個字段進行連接,那么在它上面創建一個索引可能會很好。

我通常理解索引表的概念(很像紙質書中的索引允許您查找特定術語而無需逐頁搜索)。 但我不太清楚何時使用它們。

假設我有3個表:USERS,COMMENTS和VOTES表。 我想創建一個類似Stackoverflow的評論線程,其中查詢返回注釋以及這些注釋上/下投票的數量。

USERS table
user_id user_name   
 1         tim
 2         sue
 3         bill 
 4         karen
 5         ed

COMMENTS table
comment_id topic_id    comment   commenter_id
 1            1       good job!         1
 2            2       nice work         2
 3            1       bad job :)        3

VOTES table
 vote_id    vote  comment_id  voter_id
  1          -1       1          5
  2           1       1          4
  3           1       3          1
  4          -1       2          5
  5           1       2          4

這是在topic_id = 1上返回投票的查詢和SQLFiddle

select u.user_id, u.user_name,
   c.comment_id, c.topic_id, c.comment,
   count(v.vote) as totals, sum(v.vote > 0) as yes, sum(v.vote < 0) as no,
   my_votes.vote as did_i_vote
from comments c
join users u on u.user_id = c.commenter_id
left join votes v on v.comment_id = c.comment_id
left join votes my_votes on my_votes.comment_id = c.comment_id
and my_votes.voter_id = 1
where c.topic_id = 1
group by c.comment_id, u.user_name, c.comment_id, c.topic_id, did_i_vote;

讓我們假設評論和投票的數量達到數百萬。 為了加快查詢速度,我的問題是我應該在comments.commenter_idvotes.voter_idvotes.comment_idvotes.voter_id votes.comment_id嗎?

在SQL表中使用索引的位置並不總是很明確。 但是有一些一般的經驗法則可以幫助您在大多數情況下做出決定。

  1. 將索引放在where子句中使用的列上
  2. 將索引放在您用於加入的列上。
  3. 盡量不要在同一個表中的列上使用超過4-5個索引。

您應該記住的一般概念是:

  1. 您使用的任何索引都會更快地搜索這些列。
  2. 您添加的任何索引導致插入此表的速度要慢一些。
  3. 從前兩個。 您有責任決定在表上執行多少次插入和查詢,以決定是否使用索引以及是否使用哪些列。

編輯

@AndrewLazarus評論非常重要,我決定將其添加到答案中:

  1. 不要在只有很少不同值的列上使用索引。 例如,當只有很少的狀態時,保持狀態的列或布爾值。 不這樣做的原因是索引並沒有真正幫助你,因為它只會被值的數量除以,因為你只有少數幾個,所以沒有任何實際的好處。 索引會占用更多空間,插入時預制會變慢,但查詢時不會獲得明顯更好的性能

這是使用http://www.sqlfiddle.com/#!2/94daa/1使用的一些密鑰的更新

引擎必須將使用索引的成本與不這樣做的成本進行比較。 您會注意到我必須添加更多行才能獲得所使用的索引。

使用索引,引擎必須使用索引來獲取匹配值,這很快。 然后它必須使用匹配來查找表中的實際行。 如果索引沒有縮小行數,那么只需查找表中的所有行就可以更快。

我不確定mysql是否有類似於SQL Server聚簇索引的東西。 在這種情況下,索引和表數據具有相同的結構,因此您沒有索引查找的第二步。

我以兩種不同的方式介紹了索引,首先是通過定義主鍵在users表上。 這將隱式在user_id列上創建唯一索引。 唯一索引意味着您不能兩次插入相同的值集。 對於單列索引,這只意味着您不能兩次具有相同的值。

如果您想象一本桌面的用戶書,每頁有一個用戶,那么創建的索引會為您提供一個user_id的排序列表,每個列表都包含用戶的頁碼。 該列表通常以某種樹形式存儲,以便快速查找特定數字。 考慮一下你在電話簿中查找名字的方式,你不僅要掃描所有頁面,直到找到它,你猜測它會在哪里,然后跳過或轉發大塊的頁面直到你接近。 您通常可以在O(log 2 n)時間內查找索引中的值,其中n是行數,您需要讀取相似數量的索引頁。

現在,如果給DB引擎查詢select * from users Where user_id = 3 ,它有兩個選擇。 它可以讀取每個數據頁面,並查找正確的值(它可能會使用主鍵在第一個時停止的事實)。 另一種方法是讀取索引以獲取正確的數據頁,然后查找數據頁。

為了具體和簡單,假設該表有1024個條目。 假設每個條目都占用一個數據頁面。 假設索引樹中的每個條目都占用一個索引頁。 假設索引是平衡的,因此它有10個級別,總共2047個頁面。 (所有這些假設都是可疑的,但是他們得到了相應的點,特別是索引頁幾乎總是小於數據頁,因為你不傾向於一次索引所有列)。

要執行表掃描方法,需要讀取1024個數據頁。 要使用索引,需要讀取10個索引頁和一個數據頁。 幾乎所有數據庫性能都與最小化讀取頁數有關。

多列索引允許快速查找數據集。 如果你有一個索引(col1,col2),即使只是匹配col1也會得到改進。

create index語句只是說明索引了哪些列,以及是否允許重復值。

再次使用本書類比, Create Index ix_comment_id on votes (comment_id, voter_id)將創建一個有序的comment_id列表,然后是voter_id,並引用相應的數據行。

+------------+--------------+---------+
| comment_id | reference_id | row_ref |
+------------+--------------+---------+
|          1 |            4 |    ref1 |
|          1 |            5 |    ref2 |
|          2 |            4 |    ref3 |
|          2 |            5 |    ref4 |
|          3 |            1 |    ref5 |
+------------+--------------+---------+

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM