MySQL 8.0索引合并
生活随笔
收集整理的這篇文章主要介紹了
MySQL 8.0索引合并
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
簡(jiǎn)介 參考https://dev.mysql.com/doc/refman/8.0/en/index-merge-optimization.html#index-merge-intersection。 索引合并是通過多個(gè)range類型的掃描并且合并它們的結(jié)果集來檢索行的。僅合并來自單個(gè)表的索引掃描,而不是跨多個(gè)表的索引掃描。合并會(huì)產(chǎn)生底層掃描的三種形式:unions(合并)、intersections(交集)、unions-of-intersections(先取交集再合并)。 以下四個(gè)例子會(huì)產(chǎn)生索引合并: 1、SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20; 2、SELECT * FROM tbl_name WHERE (key1 = 10 OR key2 = 20) AND non_key = 30; 3、SELECT * FROM t1, t2 WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE 'value%') AND t2.key1 = t1.some_col; 4、SELECT * FROM t1, t2 WHERE t1.key1 = 1 AND (t2.key1 = t1.some_col OR t2.key2 = t1.some_col2); 索引合并有以下已知的局限性: 1、如果查詢語句包含一個(gè)帶有嚴(yán)重AND/OR嵌套的復(fù)雜的WHERE子句而MySQL沒有選擇最佳計(jì)劃,那么可以嘗試使用以下的標(biāo)志符轉(zhuǎn)換: (x AND y) OR z => (x OR z) AND (y OR z) (x OR y) AND z => (x AND z) OR (y AND z) 2、索引合并不適用于全文索引。 在 EXPLAIN 語句輸出的信息中,索引合并在type列中表現(xiàn)為“index_merge”,在這種情況下,key列包含使用的索引列表。 索引合并訪問方法有幾種算法,表現(xiàn)在 EXPLAIN 語句輸出的Extra字段中: Using intersect(...) Using union(...) Using sort_union(...) 下面將更詳細(xì)地描述這些算法。優(yōu)化器根據(jù)各種可用選項(xiàng)的成本估計(jì),在不同的索引合并算法和其他訪問方法之間進(jìn)行選擇。 Index Merge Intersection算法 Index Merge Intersection算法對(duì)所有使用的索引執(zhí)行同步掃描,并生成從合并的索引掃描接收到的行序列的交集。 這種算法適用于當(dāng)WHERE子句被轉(zhuǎn)換成多個(gè)使用AND連接的不同索引key上的范圍條件,且條件是以下兩種之一: 一、這種形式的N部分表達(dá)式,索引正好包括N個(gè)字段(所有索引字段都被覆蓋),N>=1,N如果大于1就是復(fù)合索引: key_part1 = const1 AND key_part2 = const2 ... AND key_partN = constN。 二、InnoDB表主鍵上的任何范圍條件。 例子: 1.SELECT * FROM innodb_table WHERE primary_key < 10 AND key_col1 = 20; 2.SELECT * FROM tbl_name WHERE key1_part1 = 1 AND key1_part2 = 2 AND key2 = 2; Index Merge Union算法 該算法類似于Index Merge Intersection算法,適用于當(dāng)WHERE子句被轉(zhuǎn)換成多個(gè)使用OR連接的不同索引key上的范圍條件,且條件是以下三種之一: 一、這種形式的N部分表達(dá)式,索引正好包括N個(gè)字段(所有索引字段都被覆蓋),N>=1,N如果大于1就是復(fù)合索引: key_part1 = const1 AND key_part2 = const2 ... AND key_partN = constN。 二、InnoDB表主鍵上的任何范圍條件。 三、符合Index Merge Intersection算法的條件。 例子: 1.SELECT * FROM t1 WHERE key1 = 1 OR key2 = 2 OR key3 = 3; 2.SELECT * FROM innodb_table WHERE (key1 = 1 AND key2 = 2) OR (key3 = 'foo' AND key4 = 'bar') AND key5 = 5; Index Merge Sort-Union算法 該算法適用于當(dāng)WHERE子句被轉(zhuǎn)換成多個(gè)使用OR連接的不同索引key上的范圍條件,但是不符合 Index Merge Union算法的。Index Merge Sort-Union和Index Merge Union算法的區(qū)別在于,Index Merge Sort-Union必須首先獲取所有行的行id并在返回任何行之前對(duì)它們進(jìn)行排序。 例子: 1.SELECT * FROM tbl_name WHERE key_col1 < 10 OR key_col2 < 20; 2.SELECT * FROM tbl_name WHERE (key_col1 > 10 OR key_col2 = 20) AND nonkey_col = 30; 索引合并引發(fā)的死鎖 索引合并是MySQL優(yōu)化查詢速度的一種方式,但是錯(cuò)誤的使用也會(huì)導(dǎo)致死鎖,處理方式就是將引起索引合并的索引修改為復(fù)合索引。曾經(jīng)就遇到過和以下所講的幾乎一樣的問題,所以這里就直接把別人寫的轉(zhuǎn)載過來,轉(zhuǎn)載自:https://blog.csdn.net/hehehaha1123/article/details/59058067。 ============================================================================= 概述 前幾天排查了一個(gè)死鎖問題,最開始百思不得其解,因?yàn)榘l(fā)生死鎖的兩個(gè)事務(wù)是單語句事務(wù),語句類型相同(where屬性列相同,僅值不同),而且語句都走了相同的索引,但最終確實(shí)發(fā)生了死鎖。通過定位排查發(fā)現(xiàn),問題的源頭就是index_merge,死鎖的原因也很普通,兩個(gè)事務(wù)加鎖順序不同,并存在相互等待的情況。因?yàn)檫@個(gè)案例比較特殊,所以在此分享給大家。 死鎖信息 拿到死鎖問題,首先需要查看幾個(gè)基本信息,包括死鎖等待關(guān)系,表結(jié)構(gòu)定義等。 1.表結(jié)構(gòu)定義 Create Table: CREATE TABLE `t_xxx_customer` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵', `partner_id` bigint(20) unsigned DEFAULT NULL, `customer_id` bigint(20) unsigned DEFAULT NULL, `deleted` tinyint(4) DEFAULT NULL, `partner_user_id` bigint(20) unsigned DEFAULT NULL, `xxx_id` varchar(128) DEFAULT NULL, `xxx_name` varchar(256) DEFAULT NULL, PRIMARY KEY (`id`), KEY `partner_id` (`partner_id`), KEY `customer_id` (`customer_id`), KEY `partner_user_id` (`partner_user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=140249 DEFAULT CHARSET=utf8; 2.死鎖信息提取與分析 通過show engine innodb status;命令可以獲取innodb引擎中最近一次發(fā)生死鎖的信息,信息如下: *** (1) TRANSACTION: UPDATE t_xxx_customer SET xxx_id='101', xxx_name='bbb' where customer_id=235646 and partner_id=1688 and deleted=0; *** (1) HOLDS THE LOCK(S): RECORD LOCKS space id 1640 page no 3947 n bits 432 index partner_id of table xxx.t_xxx_customer trx id 2625291980 lock_mode X locks rec but not gap Record lock, heap no 334 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 8; hex 0000000000000698; asc ;; 1: len 8; hex 0000000000021747; asc G;; *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1640 page no 3395 n bits 160 index PRIMARY of table t_xxx_customer trx id 2625291980 lock_mode X locks rec but not gap waiting Record lock, heap no 89 PHYSICAL RECORD: n_fields 25; compact format; info bits 0 *** (2) TRANSACTION: UPDATE t_xxx_customer SET xxx_id='102', xxx_name='aaa' where customer_id=151069 and partner_id=1688 and deleted=0; *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 1640 page no 3395 n bits 160 index PRIMARY of table xxx.t_xxx_customer trx id 2625291981 lock_mode X locks rec but not gap *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1640 page no 3947 n bits 432 index partner_id of table xxx.t_xxx_customer trx id 2625291981 lock_mode X locks rec but not gap waiting Record lock, heap no 334 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 8; hex 0000000000000698; asc ;; 1: len 8; hex 0000000000021747; asc G;; *** WE ROLL BACK TRANSACTION (2) 從死鎖結(jié)果來看,我們很容易看到事務(wù)1持有 partner_id二級(jí)索引上的鎖,等待PK索引上的鎖;而事務(wù)2持有PK索引鎖,等待partner_id二級(jí)索引上的鎖,兩個(gè)事務(wù)相互持有對(duì)方需要的鎖資源,而無法往前推進(jìn),造成死鎖。單從死鎖信息來看,我們可能會(huì)比較疑惑,每個(gè)事務(wù)只有一個(gè)語句,為什么同樣的語句,對(duì)二級(jí)索引和主鍵的加鎖順序會(huì)不同? 產(chǎn)生死鎖的原因 首先我們來看看語句的執(zhí)行計(jì)劃, 語句的type是index_merge,Extra的信息是Using intersect(customerid,partnerid),從而我們得知語句執(zhí)行計(jì)劃走了index_merge優(yōu)化,單個(gè)語句通過兩個(gè)索引(customerid,partnerid)來提取記錄集合并取交集獲得最終結(jié)果集。index_merge具體算法不在此展開,基本使用場(chǎng)景是語句包含多個(gè)查詢條件,每個(gè)條件都單獨(dú)存在索引,而單個(gè)條件的索引過濾度不高,組合起來過濾度比較高,這個(gè)時(shí)候就可能會(huì)走index_merge優(yōu)化,使得單個(gè)SQL語句可以同時(shí)利用兩個(gè)索引過濾。會(huì)不會(huì)與index_merge有關(guān)呢? 在index_merge的情況下,會(huì)導(dǎo)致二級(jí)索引與主鍵索引順序不一致的情況嗎?結(jié)合上面的死鎖信息,我們得知死鎖兩個(gè)的二級(jí)索引key是0x698,而主鍵索引key是0x21747。我們看看到底是哪條記錄的主鍵和二級(jí)索引發(fā)生了死鎖, 可以看到0x21747對(duì)應(yīng)的customer_id為151069,partner_id為1688,是不是感覺似曾相識(shí),對(duì)的,第二個(gè)事務(wù)的語句查詢條件就是這兩個(gè)條件的組合。這說明,對(duì)于這條記錄,第一個(gè)事務(wù)語句只有partnerid索引(1688)滿足條件;對(duì)于第二個(gè)事務(wù),customer_id和partner_id索引都滿足條件。由于每個(gè)語句執(zhí)行時(shí)都需要利用兩個(gè)二級(jí)索引,假設(shè)先使用customer_id索引掃描,然后使用partner_id索引掃描,那么對(duì)于id為0x21747的記錄,事務(wù)1的partner_id=1688滿足條件,加partner_id鎖,然后對(duì)對(duì)應(yīng)的PK索引加鎖;對(duì)于事務(wù)2,對(duì)customer_id= 151069加鎖,對(duì)對(duì)應(yīng)的PK索引加鎖,然后對(duì)partner_id=1688索引加鎖。那么對(duì)partner_id二級(jí)索引和PK主鍵索引在兩個(gè)事務(wù)的上鎖順序是相反的,所以導(dǎo)致了死鎖。對(duì)于id為0x21747記錄:
表格第2步和第3步,兩個(gè)事務(wù)的加鎖順序是相反的,導(dǎo)致了死鎖發(fā)生。 =============================================================================
| 序號(hào) | 事務(wù)1 | 事務(wù)2 |
| 1 | customer_id 不滿足條件不加鎖 | customer_id= 151069 加鎖 |
| 2 | partner_id=1688加鎖 | PK=0x21747加鎖 |
| 3 | PK=0x21747加鎖 | partner_id=1688加鎖 |
| 4 | ? | PK=0x21747加鎖 |
轉(zhuǎn)載于:https://www.cnblogs.com/gjb724332682/p/11018678.html
總結(jié)
以上是生活随笔為你收集整理的MySQL 8.0索引合并的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: $Poj1952\ $洛谷$1687\
- 下一篇: mysql数据库操作手册