婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁(yè) > 知識(shí)庫(kù) > Mysql索引選擇以及優(yōu)化詳解

Mysql索引選擇以及優(yōu)化詳解

熱門標(biāo)簽:南昌三維地圖標(biāo)注 外呼系統(tǒng)打電話上限是多少 啥是企業(yè)400電話辦理 曲靖移動(dòng)外呼系統(tǒng)公司 武漢網(wǎng)絡(luò)外呼系統(tǒng)服務(wù)商 怎樣在地圖標(biāo)注銷售區(qū)域 電話外呼系統(tǒng)改號(hào) 地圖標(biāo)注費(fèi)用是多少 百應(yīng)電話機(jī)器人優(yōu)勢(shì)

索引模型

哈希表

  • 適用于只有等值查詢的場(chǎng)景,Memory引擎默認(rèn)索引
  • InnoDB支持自適應(yīng)哈希索引,不可干預(yù),由引擎自行決定是否創(chuàng)建

有序數(shù)組:在等值查詢和范圍查詢場(chǎng)景中的性能都非常優(yōu)秀,但插入和刪除數(shù)據(jù)需要進(jìn)行數(shù)據(jù)移動(dòng),成本太高。因此,只適用于靜態(tài)存儲(chǔ)引擎

二叉平衡樹(shù):每個(gè)節(jié)點(diǎn)的左兒子小于父節(jié)點(diǎn),父節(jié)點(diǎn)又小于右兒子,時(shí)間復(fù)雜度是 O(log(N))

多叉平衡樹(shù):索引不止存在內(nèi)存中,還要寫到磁盤上。為了讓一個(gè)查詢盡量少地讀磁盤,就必須讓查詢過(guò)程訪問(wèn)盡量少的數(shù)據(jù)塊。因此,要使用“N 叉”樹(shù)。

B+Tree

B-Tree 與 B+Tree

B-Tree

B+Tree

InnoDB 使用了 B+ 樹(shù)索引模型。假設(shè),我們有一個(gè)主鍵列為 ID 的表,表中有字段 k,并且在 k 上有索引,如下所示:

  • 主鍵索引:也被稱為聚簇索引,葉子節(jié)點(diǎn)存的是整行數(shù)據(jù)
  • 非主鍵索引:也被稱為二級(jí)索引,葉子節(jié)點(diǎn)內(nèi)容是主鍵的值

注意事項(xiàng)

  • 索引基于數(shù)據(jù)頁(yè)有序存儲(chǔ),可能發(fā)生數(shù)據(jù)頁(yè)的分裂(頁(yè)存儲(chǔ)空間不足)和合并(數(shù)據(jù)刪除造成頁(yè)利用率低)
  • 數(shù)據(jù)的無(wú)序插入會(huì)造成數(shù)據(jù)的移動(dòng),甚至數(shù)據(jù)頁(yè)的分裂
  • 主鍵長(zhǎng)度越小,普通索引的葉子節(jié)點(diǎn)就越小,普通索引占用的空間也就越小
  • 索引字段越小,單層可存儲(chǔ)數(shù)據(jù)量越多,可減少磁盤IO
// 假設(shè)一個(gè)數(shù)據(jù)頁(yè)16K、一行數(shù)據(jù)1K、索引間指針6字節(jié)、索引字段bigint類型(8字節(jié))

// 索引個(gè)數(shù)
K = 16*1024/(8+6) =1170

// 單個(gè)葉子節(jié)點(diǎn)記錄數(shù)
N = 16/1 = 16

// 三層B+記錄數(shù)
V = K*K*N = 21902400

MyISAM也是使用B+Tree索引,區(qū)別在于不區(qū)分主鍵和非主鍵索引,均是非聚簇索引,葉子節(jié)點(diǎn)保存的是數(shù)據(jù)文件的指針

索引選擇

優(yōu)化器選擇索引的目的,是找到一個(gè)最優(yōu)的執(zhí)行方案,并用最小的代價(jià)去執(zhí)行語(yǔ)句。在數(shù)據(jù)庫(kù)里面,掃描行數(shù)是影響執(zhí)行代價(jià)的因素之一。掃描的行數(shù)越少,意味著訪問(wèn)磁盤數(shù)據(jù)的次數(shù)越少,消耗的 CPU 資源越少。

當(dāng)然,掃描行數(shù)并不是唯一的判斷標(biāo)準(zhǔn),優(yōu)化器還會(huì)結(jié)合是否使用臨時(shí)表、是否排序等因素進(jìn)行綜合判斷。

掃描行數(shù)如何計(jì)算

一個(gè)索引上不同的值越多,這個(gè)索引的區(qū)分度就越好。而一個(gè)索引上不同的值的個(gè)數(shù),稱之為“基數(shù)”(cardinality)。

-- 查看當(dāng)前索引基數(shù)
mysql> show index from test;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test |   0 | PRIMARY |   1 | id   | A   |  100256 | NULL  | NULL |  | BTREE  |   |    |
| test |   1 | index_a |   1 | a   | A   |  98199 | NULL  | NULL | YES | BTREE  |   |    |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

從性能的角度考慮,InnoDB 使用采樣統(tǒng)計(jì),默認(rèn)會(huì)選擇 N 個(gè)數(shù)據(jù)頁(yè),統(tǒng)計(jì)這些頁(yè)面上的不同值,得到一個(gè)平均值,然后乘以這個(gè)索引的頁(yè)面數(shù),就得到了這個(gè)索引的基數(shù)。因此,上述兩個(gè)索引顯示的基數(shù)并不相同。

而數(shù)據(jù)表是會(huì)持續(xù)更新的,索引統(tǒng)計(jì)信息也不會(huì)固定不變。所以,當(dāng)變更的數(shù)據(jù)行數(shù)超過(guò) 1/M 的時(shí)候(innodb_stats_persistent=on時(shí)默認(rèn)10,反之16),會(huì)自動(dòng)觸發(fā)重新做一次索引統(tǒng)計(jì)。

mysql> show variables like '%innodb_stats_persistent%';
+--------------------------------------+-------------+
| Variable_name      | Value  |
+--------------------------------------+-------------+
-- 是否自動(dòng)觸發(fā)更新統(tǒng)計(jì)信息,當(dāng)被修改的數(shù)據(jù)超過(guò)10%時(shí)就會(huì)觸發(fā)統(tǒng)計(jì)信息重新統(tǒng)計(jì)計(jì)算
| innodb_stats_auto_recalc    | ON   |
-- 控制在重新計(jì)算統(tǒng)計(jì)信息時(shí)是否會(huì)考慮刪除標(biāo)記的記錄
| innodb_stats_include_delete_marked | OFF   |
-- 對(duì)null值的統(tǒng)計(jì)方法,當(dāng)變量設(shè)置為nulls_equal時(shí),所有NULL值都被視為相同
| innodb_stats_method     | nulls_equal | 
-- 操作元數(shù)據(jù)時(shí)是否觸發(fā)更新統(tǒng)計(jì)信息
| innodb_stats_on_metadata    | OFF   |
-- 統(tǒng)計(jì)信息是否持久化存儲(chǔ)
| innodb_stats_persistent    | ON   |
-- innodb_stats_persistent=on,持久化統(tǒng)計(jì)信息采樣的抽樣頁(yè)數(shù)
| innodb_stats_persistent_sample_pages | 20   |
-- 不推薦使用,已經(jīng)被innodb_stats_transient_sample_pages替換
| innodb_stats_sample_pages   | 8   |
-- 瞬時(shí)抽樣page數(shù)
| innodb_stats_transient_sample_pages | 8   |
+--------------------------------------+-------------+
  • 除了因?yàn)槌闃訉?dǎo)致統(tǒng)計(jì)基數(shù)不準(zhǔn)外,MVCC也會(huì)導(dǎo)致基數(shù)統(tǒng)計(jì)不準(zhǔn)確。例如:事務(wù)A先事務(wù)B開(kāi)啟且未提交,事務(wù)B刪除部分?jǐn)?shù)據(jù),在可重復(fù)讀中事務(wù)A還可以查詢到刪除的數(shù)據(jù),此部分?jǐn)?shù)據(jù)目前至少有兩個(gè)版本,有一個(gè)標(biāo)識(shí)為deleted的數(shù)據(jù)。
  • 主鍵是直接按照表的行數(shù)來(lái)估計(jì)的,表的行數(shù),優(yōu)化器直接使用show table status like 't'的值
  • 手動(dòng)觸發(fā)索引統(tǒng)計(jì):
-- 重新統(tǒng)計(jì)索引信息
mysql> analyze table t;

排序?qū)λ饕x擇的影響

-- 創(chuàng)建表
mysql> CREATE TABLE `t` (
`id` int(11) NOT NULL,
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `b` (`b`)
) ENGINE=InnoDB;

-- 定義測(cè)試數(shù)據(jù)存儲(chǔ)過(guò)程
mysql> delimiter ;
CREATE PROCEDURE idata ()
BEGIN

DECLARE i INT ;
SET i = 1 ;
WHILE (i = 100000) DO
 INSERT INTO t
VALUES
 (i, i, i) ;
SET i = i + 1 ;
END
WHILE ;
END;
delimiter ;

-- 執(zhí)行存儲(chǔ)過(guò)程,插入測(cè)試數(shù)據(jù)
mysql> CALL idata ();

-- 查看執(zhí)行計(jì)劃,使用了字段a上的索引
mysql> explain select * from t where a between 10000 and 20000;
+----+-------------+-------+-------+---------------+-----+---------+------+-------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra         |
+----+-------------+-------+-------+---------------+-----+---------+------+-------+-----------------------+
| 1 | SIMPLE   | t   | range | a       | a  | 5    | NULL | 10000 | Using index condition |
+----+-------------+-------+-------+---------------+-----+---------+------+-------+-----------------------+

-- 由于需要進(jìn)行字段b排序,雖然索引b需要掃描更多的行數(shù),但本身是有序的,綜合掃描行數(shù)和排序,優(yōu)化器選擇了索引b,認(rèn)為代價(jià)更小
mysql> explain select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
+----+-------------+-------+-------+---------------+-----+---------+------+-------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra               |
+----+-------------+-------+-------+---------------+-----+---------+------+-------+------------------------------------+
| 1 | SIMPLE   | t   | range | a,b      | b  | 5    | NULL | 50128 | Using index condition; Using where |
+----+-------------+-------+-------+---------------+-----+---------+------+-------+------------------------------------+

-- 方案1:通過(guò)force index強(qiáng)制走索引a,糾正優(yōu)化器錯(cuò)誤的選擇,不建議使用(不通用,且索引名稱更變語(yǔ)句也需要變)
mysql> explain select * from t force index(a) where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
+----+-------------+-------+-------+---------------+-----+---------+------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra                       |
+----+-------------+-------+-------+---------------+-----+---------+------+------+----------------------------------------------------+
| 1 | SIMPLE   | t   | range | a       | a  | 5    | NULL | 999 | Using index condition; Using where; Using filesort |
+----+-------------+-------+-------+---------------+-----+---------+------+------+----------------------------------------------------+

-- 方案2:引導(dǎo) MySQL 使用我們期望的索引,按b,a排序,優(yōu)化器需要考慮a排序的代價(jià)
mysql> explain select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b,a limit 1;
+----+-------------+-------+-------+---------------+-----+---------+------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra                       |
+----+-------------+-------+-------+---------------+-----+---------+------+------+----------------------------------------------------+
| 1 | SIMPLE   | t   | range | a,b      | a  | 5    | NULL | 999 | Using index condition; Using where; Using filesort |
+----+-------------+-------+-------+---------------+-----+---------+------+------+----------------------------------------------------+

-- 方案3:有些場(chǎng)景下,我們可以新建一個(gè)更合適的索引,來(lái)提供給優(yōu)化器做選擇,或刪掉誤用的索引
ALTER TABLE `t`
DROP INDEX `a`,
DROP INDEX `b`,
ADD INDEX `ab` (`a`,`b`) ;

索引優(yōu)化

索引選擇性

索引選擇性 = 基數(shù) / 總行數(shù)

-- 表t中字段xxx的索引選擇性
select count(distinct xxx)/count(id) from t;

索引的選擇性,指的是不重復(fù)的索引值(基數(shù))和表記錄數(shù)的比值。選擇性是索引篩選能力的一個(gè)指標(biāo),索引的取值范圍是 0~1 ,當(dāng)選擇性越大,索引價(jià)值也就越大。

在使用普通索引查詢時(shí),會(huì)先加載普通索引,通過(guò)普通索引查詢到實(shí)際行的主鍵,再使用主鍵通過(guò)聚集索引查詢相應(yīng)的行,以此循環(huán)查詢所有的行。若直接全量搜索聚集索引,則不需要在普通索引和聚集索引中來(lái)回切換,相比兩種操作的總開(kāi)銷可能掃描全表效率更高。

實(shí)際工作中,還是要看業(yè)務(wù)情況,如果數(shù)據(jù)分布不均衡,實(shí)際查詢條件總是查詢數(shù)據(jù)較少的部分,在索引選擇較低的列上加索引,效果可能也很不錯(cuò)。

覆蓋索引

覆蓋索引可以減少樹(shù)的搜索次數(shù),顯著提升查詢性能,所以使用覆蓋索引是一個(gè)常用的性能優(yōu)化手段

-- 只需要查 ID 的值,而 ID 的值已經(jīng)在 k 索引樹(shù)上了,因此可以直接提供查詢結(jié)果,不需要回表
select ID from T where k between 3 and 5

-- 增加字段V,每次查詢需要返回V,可考慮把k、v做成聯(lián)合索引
select ID,V from T where k between 3 and 5

最左前綴原則+索引下推

-- id、name、age三列,name、age上創(chuàng)建聯(lián)合索引

-- 滿足最左前綴原則,name、age均走索引
select * from T where name='xxx' and age=12

-- Mysql自動(dòng)優(yōu)化,調(diào)整name、age順序,,name、age均走索引
select * from T where age=12 and name='xxx'

-- name滿足最左前綴原則走索引,MySQL5.6引入索引下推優(yōu)化(index condition pushdown),即索引中先過(guò)濾掉不滿足age=12的記錄再回表
select * from T where name like 'xxx%' and age=12

-- 不滿足最左前綴原則,均不走索引
select * from T where name like '%xxx%' and age=12

-- 滿足最左前綴原則,name走索引
select * from T where name='xxx'

-- 不滿足最左前綴原則,不走索引
select * from T where age=12

聯(lián)合索引建立原則:

  • 如果通過(guò)調(diào)整順序,可以少維護(hù)一個(gè)索引,那么這個(gè)順序往往就是需要優(yōu)先考慮采用的
  • 空間:優(yōu)先小字段單獨(dú)建立索引,例如:name、age,可建立(name,age)聯(lián)合索引和(age)單字段索引

前綴索引

mysql> create table SUser(
ID bigint unsigned primary key,
name varchar(64),  
email varchar(64),
...
)engine=innodb;

-- 以下查詢場(chǎng)景
mysql> select name from SUser where email='xxx';

-- 方案1:全文本索引,回表次數(shù)由符合條件的數(shù)據(jù)量決定
mysql> alter table SUser add index index1(email);

-- 方案2:前綴索引,回表次數(shù)由前綴匹配結(jié)果決定
mysql> alter table SUser add index index2(email(6));

前綴索引可以節(jié)省空間,但需要注意前綴長(zhǎng)度的定義,在節(jié)省空間的同時(shí),不能增加太多查詢成本,即減少回表驗(yàn)證次數(shù)

如何設(shè)置合適的前綴長(zhǎng)度?

-- 預(yù)設(shè)一個(gè)可以接受的區(qū)分度損失比,選擇滿足條件中最小的前綴長(zhǎng)度
select count(distinct left(email,n))/count(distinct email) from SUser;

如果合適的前綴長(zhǎng)度較長(zhǎng)?

比如身份證號(hào),如果滿足區(qū)分度要求,可能需要12位以上的前綴索引,節(jié)約的空間有限,又增加了查詢成本,就沒(méi)有必要使用前綴索引。此時(shí),我們可以考慮使用以下方式:

倒序存儲(chǔ)

-- 查詢時(shí)字符串反轉(zhuǎn)查詢
mysql> select field_list from t where id_card = reverse('input_id_card_string');

使用hash字段

-- 創(chuàng)建一個(gè)整數(shù)字段,來(lái)保存身份證的校驗(yàn)碼,同時(shí)在這個(gè)字段上創(chuàng)建索引
mysql> alter table t add id_card_crc int unsigned, add index(id_card_crc);

-- 查詢時(shí)使用hash字段走索引查詢,再使用原字段精度過(guò)濾
mysql> select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'

以上兩種方式的缺點(diǎn):

  • 不支持范圍查詢
  • 使用hash字段需要額外占用空間,新增了一個(gè)字段
  • 讀寫時(shí)需要額外的處理,reverse或者crc32等

前綴索引對(duì)覆蓋索引的影響?

-- 使用前綴索引就用不上覆蓋索引對(duì)查詢性能的優(yōu)化
select id,email from SUser where email='xxx';

唯一索引

建議使用普通索引,唯一索引無(wú)法使用change buffer,內(nèi)存命中率低

索引失效

  • 不做列運(yùn)算,包括函數(shù)的使用,可能破壞索引值的有序性
  • 避免 %xxx 式查詢使索引失效
  • or語(yǔ)句前后沒(méi)有同時(shí)使用索引,當(dāng)or左右查詢字段只有一個(gè)是索引,該索引失效
  • 組合索引ABC問(wèn)題,最左前綴原則
  • 隱式類型轉(zhuǎn)化
  • 隱式字符編碼轉(zhuǎn)換
  • 優(yōu)化器放棄索引,回表、排序成本等因素影響,改走其它索引或者全部掃描

總結(jié)

到此這篇關(guān)于Mysql索引選擇以及優(yōu)化的文章就介紹到這了,更多相關(guān)Mysql索引選擇優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • mysql性能優(yōu)化之索引優(yōu)化
  • MySQL 索引分析和優(yōu)化
  • MySQL中索引優(yōu)化distinct語(yǔ)句及distinct的多字段操作
  • Mysql使用索引實(shí)現(xiàn)查詢優(yōu)化
  • Mysql limit 優(yōu)化,百萬(wàn)至千萬(wàn)級(jí)快速分頁(yè) 復(fù)合索引的引用并應(yīng)用于輕量級(jí)框架
  • MySQL索引背后的之使用策略及優(yōu)化(高性能索引策略)
  • MySQL 聯(lián)合索引與Where子句的優(yōu)化 提高數(shù)據(jù)庫(kù)運(yùn)行效率
  • MySQL Order By索引優(yōu)化方法
  • 探究MySQL優(yōu)化器對(duì)索引和JOIN順序的選擇
  • mysql優(yōu)化之路----hash索引優(yōu)化

標(biāo)簽:資陽(yáng) 甘南 隨州 黑河 吉林 滄州 錦州 荊州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Mysql索引選擇以及優(yōu)化詳解》,本文關(guān)鍵詞  Mysql,索引,選擇,以及,優(yōu)化,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Mysql索引選擇以及優(yōu)化詳解》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于Mysql索引選擇以及優(yōu)化詳解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    主站蜘蛛池模板: 富顺县| 马边| 儋州市| 古交市| 隆子县| 沐川县| 洪湖市| 方正县| 鲁山县| 康保县| 永寿县| 平凉市| 德令哈市| 肇源县| 黄石市| 繁昌县| 桂平市| 抚松县| 张北县| 黄冈市| 西畴县| 德江县| 台南市| 横山县| 深水埗区| 普兰店市| 盈江县| 高安市| 太湖县| 南雄市| 锡林浩特市| 云安县| 徐州市| 澳门| 巴林左旗| 黄浦区| 霍州市| 江北区| 二连浩特市| 嘉兴市| 和平区|