最近遇到一個慢sql,在排查過程當中發現和分庫分表後的索引設置有關係,總結了下問題。mysql
在進行應用健康度盤點時,發現有個慢sql 以下sql
select brandgoodid from brandgood_0020
where userid = xxx AND
brandgoodid in("xxx1","xxx2")
複製代碼
表結構,按照userid進行的分表。數據庫
CREATE TABLE`brandgood_0020` (
`brandgoodid` char(30) NOT NULL COMMENT ,
`user_id` int(10) unsigned DEFAULT NULL COMMENT '用戶id',
`created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`last_modified` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted` bit(1) NOT NULL DEFAULT b'0',
PRIMARY KEY (`brandgoodid`),
KEY `idx_userid` (`userid`) USING BTREE,
) ENGINE=InnoDB DEFAULT CHARSET=utf8
複製代碼
explain
一下發現走的是userid這個索引,一個用戶下面有不少商品,也就有了不少brandgoodid,因此有可能會很慢,由於要掃描不少的索引鍵去過濾brandgoodid值。 而寫這個SQL的人指望走的主鍵索引,而不是'userid'的索引。由於用主鍵索引,就是N次主鍵掃描(N表示in中的數量)。bash
IN 這個查詢誤導了mysql的優化器,選錯了索引 IN 查詢經常會影響mysql server的判斷。主要是IN裏面的值數量不一樣,會影響掃描行數的不一樣,因此經常會出現索引選擇不一致。以前也總結過一篇SQL IN 必定走索引嗎分佈式
由於用戶查詢的brandgoodlid是限定在某個group維度下的,一個group對應的brandgood是有限的,在這個業務中,一般小於10。因此這個地方使用主鍵索引,效率更高。解決方法也就是這地方須要force index
強制走PRIMARY index。優化
爲何題目叫分庫分表後的索引問題的,直接緣由和分庫分表並無什麼關係啊? 由於在排查問題時,犯了一個錯誤。覺得路由到具體的brandgood_0020表後,能夠直接根據brandgoodid主鍵索引來查詢了。認爲和一些分佈式數據庫(cassandra)同樣,是clustering key+partition key這種索引數據。能夠根據clustering key到數據的節點的partition塊,而後根據local index 找到對應的數據。ui
但其實mysql的分庫分表不同,分表鍵不是索引,只是客戶端路由。只負責找到對應的表。到表之後,就是和單表同樣查詢邏輯。spa
由於分表鍵不是索引,可是查詢語句是必需要帶着分表鍵,那意味着咱們的分庫分表之後的表索引大部分要建成聯合索引了,分表鍵+索引鍵。.net
要否則咱們的查詢語句 select xx from table where 分表鍵=xxx AND a =xxx,是走不了聯合索引的。只能走單索引。單索引mysql server要面臨着索引選擇的問題。code
固然並非絕對的,好比上面我舉的那個案例。按照這個思路查看了下其餘的分表索引。果真表上的大部分索引都是非聯合索引,仍是直接從單表copy過來的索引。這些索引基本上都是無用的,由於都的是userid索引.
mysql爲何會選錯索引呢,詳細的請看10 | MySQL爲何有時候會選錯索引
咱們這個案例是由於判斷掃描行數的時候出問題了。