1. 程式人生 > 資料庫 >索引、索引和SQL語句優化策略、索引管理、併發控制、事務

索引、索引和SQL語句優化策略、索引管理、併發控制、事務

索引

索引:是特殊資料結構,定義在查詢時作為查詢條件的欄位,在MySQL又稱為鍵key,索引通過儲存引擎實現

優點:
索引可以降低服務需要掃描的資料量,減少了IO次數
索引可以幫助伺服器避免排序和使用臨時表
索引可以幫助將隨機I/O轉為順序I/O

缺點:
佔用額外空間,影響插入速度

索引型別:
B+ TREE、HASH、R TREE
聚簇(集)索引、非聚簇索引:資料和索引是否儲存在一起
主鍵索引、二級(輔助)索引
稠密索引、稀疏索引:是否索引了每一個數據項
簡單索引、組合索引
左字首索引:取前面的字元做索引
覆蓋索引:從索引中即可取出要查詢的資料,效能高

B+Tree索引:順序儲存,每一個葉子節點到根結點的距離是相同的;左字首索引,適合查詢範圍類的資料

可以使用B+Tree索引的查詢型別:
全值匹配:精確所有索引列,如:姓zhang,名san,年齡30
匹配最左字首:即只使用索引的第一列,如:姓zhang
匹配列字首:只匹配一列值開頭部分,如:姓以z開頭的
匹配範圍值:如:姓li和姓zhang之間
精確匹配某一列並範圍匹配另一列,如:姓z,名以s開頭的
只訪問索引的查詢

B+Tree索引的限制
如不從最左列開始,則無法使用索引,如:查詢名為xiaochun,或姓為g結尾

不能跳過索引中的列:如:查詢姓wang,年齡30的,只能使用索引第一列

如果查詢中某個列是為範圍查詢,那麼其右側的列都無法再使用索引:如:姓zhang,名s%,年齡30,只能利用姓和名上面的索引

注意:
索引列的順序和查詢語句的寫法應相匹配,才能更好的利用索引
為優化效能,可能需要針對相同的列但順序不同建立不同的索引來滿足不同型別的查詢需求

Hash索引
基於雜湊表實現,只有精確匹配索引中的所有列的查詢才有效,索引自身只儲存索引列對應的雜湊值和資料指標,索引結構緊湊,查詢效能好
Memory儲存引擎支援顯式hash索引,InnoDB和MyISAM儲存引擎不支援
適用場景:只支援等值比較查詢,包括=,<=>,IN()
不適合使用hash索引的場景
不適用於順序查詢:索引儲存順序的不是值的順序
不支援模糊匹配
不支援範圍查詢
不支援部分索引列匹配查詢:如A,B列索引,只查詢A列索引無效

R-Tree( Geospatial indexing )
MyISAM支援地理空間索引,可以使用任意維度組合查詢,使用特有的函式訪問,常用於做地理資料儲存,使用不多
InnoDB從MySQL5.7之後也開始支援
全文索引(FULLTEXT)
在文字中查詢關鍵詞,而不是直接比較索引中的值,類似搜尋引擎
InnoDB從MySQL 5.6之後也開始支援


索引和SQL語句優化策略

索引優化策略
避免冗餘和重複索引
冗餘索引:(A),(A,B)
重複索引:已經有索引,再次建立索引

獨立地使用列:儘量避免其參與運算,獨立的列指索引列不能是表示式的一部分,也不能是函式的引數,在where條件中,始終將索引列單獨放在比較符號的一側

左字首索引:構建指定索引欄位的左側的字元數,要通過索引選擇性來評估索引選擇性:不重複的索引值和資料表的記錄總數的比值

多列索引:AND操作時更適合使用多列索引,而非為每個列建立單獨的索引

選擇合適的索引列順序:無排序和分組時,將選擇性最高放左側

只要列中含有NULL值,就最好不要在此例設定索引,複合索引如果有NULL值,此列在使用時也不會使用索引

儘量使用短索引,如果可以,應該制定一個字首長度

對於經常在where子句使用的列,最好設定索引

對於有多個列where或者order by子句,應該建立複合索引

對於like語句,以%或者‘-’開頭的不會使用索引,以%結尾會使用索引

儘量不要在列上進行運算(函式操作和表示式操作)

儘量不要使用not in和<>操作

SQL語句效能優化
查詢時,能不要*就不用*,儘量寫全欄位名
大部分情況連線效率遠大於子查詢
多表連線時,儘量小表驅動大表,即小表 join 大表
在有大量記錄的表分頁時使用limit
對於經常使用的查詢,可以開啟快取
多使用explain和profile分析查詢語句
檢視慢查詢日誌,找出執行時間長的sql語句優化

索引管理

建立索引:
CREATE INDEX [UNIQUE] index_name ON tbl_name (index_col_name[(length)],…);
ALTER TABLE tbl_name ADD INDEX index_name(index_col_name);
help CREATE INDEX;

刪除索引:
DROP INDEX index_name ON tbl_name;
ALTER TABLE tbl_name DROP INDEX index_name(index_col_name);

檢視索引:
SHOW INDEXES FROM [db_name.]tbl_name;

優化表空間:
OPTIMIZE TABLE tb_name;

檢視索引的使用
SET GLOBAL userstat=1;
SHOW INDEX_STATISTICS;

通過EXPLAIN來分析索引的有效性
EXPLAIN SELECT * from test where name like ‘a%’
獲取查詢執行計劃資訊,用來檢視查詢優化器如何執行查詢

id: 當前查詢語句中,每個SELECT語句的編號
複雜型別的查詢有三種:
    簡單子查詢
    用於FROM中的子查詢
    聯合查詢:UNION
UNION查詢的分析結果會出現一個額外匿名臨時表

select_type:
簡單查詢為SIMPLE

複雜查詢:
SUBQUERY 簡單子查詢
PRIMARY 最外面的SELECT
DERIVED 用於FROM中的子查詢
UNION UNION語句的第一個之後的SELECT語句
UNION RESULT 匿名臨時表

table:SELECT語句關聯到的表

type:關聯型別或訪問型別,即MySQL決定的如何去查詢表中的行的方式,以下順序,效能從低到高

ALL: 全表掃描

ndex:根據索引的次序進行全表掃描;如果在Extra列出現“Using index”
表示了使用覆蓋索引,而非全表掃描

range:有範圍限制的根據索引實現範圍掃描;掃描位置始於索引中的某一
點,結束於另一點

ref: 根據索引返回表中匹配某單個值的所有行

eq_ref:僅返回一個行,但與需要額外與某個參考值做比較

const,system: 直接返回單個行

possible_keys:查詢可能會用到的索引

key: 查詢中使用到的索引

key_len: 在索引使用的位元組數

ref: 在利用key欄位所表示的索引完成查詢時所用的列或某常量值

rows:MySQL估計為找所有的目標行而需要讀取的行數

Extra:額外資訊

Using index:MySQL將會使用覆蓋索引,以避免訪問表
Using where:MySQL伺服器將在儲存引擎檢索後,再進行一次過濾
Using temporary:MySQL對結果排序時會使用臨時表
Using filesort:對結果使用一個外部索引排序

併發控制

鎖粒度:
表級鎖
行級鎖

鎖:
讀鎖:共享鎖,只讀不可寫(包括當前事務) ,多個讀互不阻塞
寫鎖:獨佔鎖,排它鎖,寫鎖會阻塞其它事務(不包括當前事務)的讀和它鎖

實現
儲存引擎:自行實現其鎖策略和鎖粒度
伺服器級:實現了鎖,表級鎖,使用者可顯式請求

分類:
隱式鎖:由儲存引擎自動施加鎖
顯式鎖:使用者手動請求

鎖策略:在鎖粒度及資料安全性尋求的平衡機制
顯式使用鎖

LOCK TABLES 加鎖
tbl_name [[AS] alias] lock_type
[,tbl_name [[AS] alias] lock_type] …
lock_type: READ , WRITE

UNLOCK TABLES 解鎖

關閉正在開啟的表(清除查詢快取),通常在備份前加全域性讀鎖
FLUSH TABLES [tb_name[,…]] [WITH READ LOCK]

查詢時加寫或讀鎖
SELECT clause [FOR UPDATE | LOCK IN SHARE MODE]

事務

事務Transactions
一組原子性的SQL語句,或一個獨立工作單元
事務日誌:記錄事務資訊,實現undo,redo等故障恢復功能
ACID特性:
A:atomicity原子性;整個事務中的所有操作要麼全部成功執行,要麼全部
失敗後回滾

C:consistency一致性;資料庫總是從一個一致性狀態轉換為另一個一致性狀態

I:Isolation隔離性;一個事務所做出的操作在提交之前,是不能為其它事務所見;隔離有多種隔離級別,實現併發

D:durability永續性;一旦事務提交,其所做的修改會永久保存於資料庫中

事務日誌如何工作:
開始事務–>增刪改查–>結束事務–>資料更新
事務中執行的動作會記錄到事務日誌,如果在結束事務前斷電,下次啟動時會發現該事務沒有結束,則執行undo,資料不會更新

啟動事務:
BEGIN
BEGIN WORK
START TRANSACTION

結束事務:
COMMIT:提交
ROLLBACK: 回滾
只有事務型儲存引擎中的DML語句方能支援此類操作

自動提交:set autocommit={1|0} 預設為1,為0時設為非自動提交
顯式請求和提交事務,而不要使用“自動提交”功能

事務支援儲存點:savepoint
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier

事務隔離級別
從上至下更加嚴格
READ UNCOMMITTED 可讀取到未提交資料,產生髒讀

READ COMMITTED 可讀取到提交資料,但未提交資料不可讀,產生不可重複讀,即可讀取到多個提交資料,導致每次讀取資料不一致

REPEATABLE READ 可重複讀,多次讀取資料都一致,產生幻讀,即讀取過程中,即使有其它提交的事務修改資料,仍只能讀取到未修改前的舊資料。此為MySQL預設設定

SERIALIZABILE 可序列化,未提交的讀事務阻塞修改事務,或者未提交的修改事務阻塞讀事務。導致併發效能差

指定事務隔離級別:
伺服器變數tx_isolation指定,預設為REPEATABLE-READ,可在GLOBAL和SESSION級進行設定
SET tx_isolation=’’
READ-UNCOMMITTED
READ-COMMITTED
REPEATABLE-READ
SERIALIZABLE

伺服器選項中指定
[mysqld]
transaction-isolation=SERIALIZABLE

死鎖:
兩個或多個事務在同一資源相互佔用,並請求鎖定對方佔用的資源的狀態

事務日誌:
事務日誌的寫入型別為“追加”,因此其操作為“順序IO”;通常也被稱為:預寫式日誌 write ahead logging
事務日誌檔案: ib_logfile0, ib_logfile1