摘要:最近遇到一個慢sql,在排查過程中發現和分庫分表後的索引設置有關係,總結了下問題。爲什麼題目叫分庫分表後的索引問題的,直接原因和分庫分表並沒有什麼關係啊。

摘要

最近遇到一個慢sql,在排查過程中發現和分庫分表後的索引設置有關係,總結了下問題。

問題

在進行應用健康度盤點時,發現有個慢sql 如下

表結構, 按照userid進行的分表

explain 一下發現走的是userid這個索引,一個用戶下面有很多商品,也就有了很多brandgoodid,所以有可能會很慢,因爲要掃描很多的索引鍵去過濾brandgoodid值。而寫這個SQL的人期望走的主鍵索引,而不是'userid'的索引。因爲用主鍵索引,就是N次主鍵掃描(N表示in中的數量)。

分析

直接原因很明顯

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 找到對應的數據。

但其實mysql的分庫分表不一樣,分表鍵不是索引,只是客戶端路由。只負責找到對應的表。到表以後,就是和單表一樣查詢邏輯。

因爲分表鍵不是索引,但是查詢語句是必須要帶着分表鍵,那意味着我們的分庫分表以後的表索引大部分要建成聯合索引了, 分表鍵+索引鍵

要不然我們的查詢語句 select xx from table where 分表鍵=xxx AND a =xxx,是走不了聯合索引的。只能走單索引。單索引mysql server要面臨着索引選擇的問題。

當然並不是絕對的,比如上面我舉的那個案例。按照這個思路查看了下其他的分表索引。果然表上的大部分索引都是非聯合索引,還是直接從單表copy過來的索引。這些索引基本上都是無用的,因爲都的是userid索引.

索引選擇的問題

mysql爲什麼會選錯索引呢,詳細的請看10 | MySQL爲什麼有時候會選錯索引

我們這個案例是因爲判斷掃描行數的時候出問題了。

相關文章