性能測試問題_Mysql數據庫服務器的CPU佔用很高

 

MySQl服務器CPU佔用很高mysql

1.  問題描述

一個簡單的接口,根據傳入的號段查詢號碼歸屬地,運行性能測試腳本,20個併發mysql的CPU就很高,監控發現只有一個select語句,且表創建了索引sql

2.  問題緣由

查詢語句索引沒有命中致使服務器

開始時的select併發

SELECT函數

         `province_name`,性能

         `city_name`測試

        FROM `phoneno_section`.net

        WHERE SUBSTRING(號碼,1, phoneno_section_len) = phoneno_section3d

        LIMIT 1;htm

 

諮詢說where中使用SUBSTRING函數不行,修改函數爲LEFT,語句爲

SELECT

         `province_name`,

         `city_name`

        FROM `conf_phoneno_section`

        WHERE LEFT(號碼, phoneno_section_len) = phoneno_section

        LIMIT 1;

 

測試發現CPU佔用仍是很高,LEFT函數中的參數是變量不是常量,再次修改select語句,指定LEFT函數中的phoneno_section_len爲固定值,CPU佔用正常

SELECT

         `province_name`,

         `city_name`

        FROM `conf_phoneno_section`

        WHERE LEFT(號碼, 7) = phoneno_section

        LIMIT 1;

 

3.  MYSQL索引介紹

ü  先舉個例子  

表a, 字段:  id(自增id),user(用戶名),pass(密碼),type(類型 0,1),

索引: user + pass 創建聯合索引 ,user惟一索引,pass普通索引 ,type 普通索引

ü  索引命中說明

(1)SELECT   *   FROM   a  WHERE user = 't'  AND PASS = 'p'會命中user+pass的聯合索引 

(2)SQL:  SELECT   *   FROM   a  WHERE user = 't' OR user= 'f'  不能命中任何索引

(3)SQL:  SELECT   *   FROM   a  WHERE user = 't'會命中user惟一索引

(4)SQL:  SELECT   *   FROM   a  WHERE pass = 'p'   不能命中任何索引

(5)SELECT  *  FROM  a WHERE user = 't'  OR   user= 'f' 相對於SELECT  user,pass  FROM  a  WHERE user = 't'  OR   user= 'f'  會慢

(6)SELECT * FROM a WHERE length(user) = 3 不能命中

(7)user惟一索引 、type索引能夠刪除

索引就是排序,目前的計算機技術和數學理論還不支持一次同時按照兩個關鍵字進行排序,即便是聯合索引,也是先按照最左邊的關鍵字先排,而後在左邊的關鍵字排序基礎上再對其餘的關鍵字排序,是一個屢次排序的結果。 因此,單表查詢,一次最多隻能命中一個索引,而且索引必須遵照最左前綴。因而基於索引的結構和最左前綴,像 OR ,like '%%'都是不能命中索引的,而like 'aa%'則是能夠命中的。 

不管是innodb仍是myisam,索引只記錄被排序的行的主鍵或者地址,其餘的字段仍是須要二次查詢,所以,若是查詢的字段恰好只是包含在索引中,那麼索引覆蓋將是高效的。

若是全部的數據都同樣,或者基本同樣,那麼就沒有排序的必要了。像例子中的type只有1或者0,選擇性是0.5,極低的樣紙,因此能夠忽視,即便創建了,也是浪費空間,mysql在查詢的時候也會選擇丟棄。

相似最左前綴,查詢索引的時候,若是列被應用了函數,那麼在查詢的時候,是不會用到索引的。道理很簡單,函數運算已經改變了列的內容,而原始的索引是對列內容全量排序的。

綜上所述,索引的幾個知識點:最左前綴,索引覆蓋,索引選擇性,列隔離在創建和使用索引的時候須要格外注意。

4.  MySQl索引無效場景補充

ü  WHERE子句的查詢條件裏有不等於號(WHERE column!=...),MYSQL將沒法使用索引

ü  WHERE子句的查詢條件裏使用了函數(如:WHERE DAY(column)=...),MYSQL將沒法使用索引,實驗中LEFT函數是能夠的,可是條件不能是變量,使用LEFT函數且條件是變量,也沒法使用索引,LEFT函數以外是否有其它函數有待驗證

ü  在JOIN操做中(須要從多個數據表提取數據時),MYSQL只有在主鍵和外鍵的數據類型相同時才能使用索引,不然即便創建了索引也不會使用

ü  若是WHERE子句的查詢條件裏使用了比較操做符LIKE和REGEXP,MYSQL只有在搜索模板的第一個字符不是通配符的狀況下才能使用索引。好比說,若是查詢條件是LIKE 'abc%',MYSQL將使用索引;若是條件是LIKE '%abc',MYSQL將不使用索引。

ü  在ORDER BY操做中,MYSQL只有在排序條件不是一個查詢條件表達式的狀況下才使用索引。儘管如此,在涉及多個數據表的查詢裏,即便有索引可用,那些索引在加快ORDER BY操做方面也沒什麼做用。

ü  若是某個數據列裏包含着許多重複的值,就算爲它創建了索引也不會有很好的效果。好比說,若是某個數據列裏包含了淨是些諸如「0/1」或「Y/N」等值,就沒有必要爲它建立一個索引。

只要創建了索引,除了上面提到的索引不會使用的狀況下以外,其餘狀況只要是使用在WHERE條件裏,ORDER BY 字段,聯表字段,索引通常都是有效的。

 

5.  參考資料

http://www.jb51.net/article/37190.htm

http://terry831010.blog.163.com/blog/static/69161171201382011498834/

相關文章
相關標籤/搜索