Mysql索引優化

索引問題

索引是數據庫優化中最常見也 最重要的手段之一,通過索引通常可以幫助用戶解決大多數的SQL性能問題。

(Mysql的優化很大一部分都集中在索引的優化,因爲現在是信息社會,數據量都不少,所以做索引少不了的,很多學員朋友在面試或者在公司裏面其實面面臨的一個重要的問題往往是突出的問題是查詢過慢或者查詢過久導致服務器的cpu消耗過高,那麼像這種問題咱們最直接最常用的手段是什麼呢? 索引優化,所以今天咱們來把索引優化好好的給大家講解一下包括測試,基本上通過索引優化可以幫助開發者解決大部份的SQL性能問題,以前在三一重工的時候他負責的一個CRM系統查詢經常好慢,然後他跟我講,後來我幫他查了一下啊,它的Mysql裏面的慢查詢日誌srow.log裏面有大量的慢查詢語句,經常查詢到十分鐘以上啊。怎麼解決呢?通過DSC定位看那些地方需要做索引那些地方不需要做索引,咱們一般常見做索引的地方一般是where語句的後面也就是條件語句以及排序Order by 以及group by後面的having,總之這些條件後面的字段或者頻繁的字段都會加索引)

慢查詢日誌查看:

show variables like '%quer%';

其中紅框標註的選項是:

-slow_query_log是否記錄慢查詢。用long_query_time變量的值來確定"慢查詢"。

-slow_query_log_file慢日誌文件路徑

-long_query_time慢日誌執行時長(秒),超過設定的時間纔會記日誌

如何開啓慢查詢日誌查看那功能:

Linux:

在/etc/my.cnf配置文件的[mysqld]選項下增加:

slow_query_log=TRUE

slow_query_log_file=/usr/local/mysql/slow_query_log.txt

long_query_time=3

Windows:

在my.ini配置文件的[mysqld]選項下增加:

slow_query_log=TRUE

slow_query_log_file=c:/slow_query_log.txt

long_query_time=3

索引的存儲分類:

MyISAM存儲引擎的表的數據和索引是自動分開存儲的,各自是一個獨一的一個文件;InnoDB存儲引擎的表的數據和索引是存儲在同一個表空間裏面的,但可以有多個文件組成。

MySQl目前不支持函數索引,但是能對列的面前某一部分進行索引,例如name字段,可以只取name的前4個字符進行索引,這個特性可以大大的縮小索引文件的大小,用戶在設計表結構的時候也可以對文本列根據此特性經行靈活設計。

(其實咱們一般用戶的表存儲到MyISAM引擎裏面的,MyISAM引擎裏面的表不管是在linux還是在weindos下面它其實存儲分爲三個文件,一個是.LOG是日誌文件,另外一個是以.MYI結尾的索引文件,以.MYD的即是數據文件,那麼InnoDB引擎類型的表默認是共性表空間,而且每個表的表結構會單獨的分離開,放到不同的文件裏面去,但是咱們的InnoDB索引和數據會存儲到同一個表空間,MySQL如果使用InnoDB存儲引擎,數據庫文件類型就包括.frm、ibdata1、.ibd,存放位置有兩個,

.frm文件默認存放位置是C:\Documents and Settings\All Users\ApplicationData\MySQL\MySQL Server 5.1\data,ibdata1、.ibd文件默認存放位置是MySQL安裝目錄下的data文件夾)

(Mysql的表空間管理遠遠說不上完善。換句話說,事實上Mysql根本沒有真正意義上的表空間管理。Mysql的Innodb包含兩種表空間文件模式,默認的共享表空間和每個表分離的獨立表空間。只要在my.cnf裏面增加innodb_file_per_table=1就可以從共享表空間切換到獨立表空間。當然對於已經存在的表,則需要執行alter table MY_TABLE engine=innodb命令遷移數據。

共享表空間方式

 

由於是默認的方式,就暫且理解爲Mysql官方推薦的方式。相對而言所有的數據都在一個(或幾個)文件中,比較利於管理,而且在操作的時候只需要open這一個(或幾個)文件即可,相對來說代價很低。

 

但問題是在數據達到以G爲單位來計算的時候優劣逆轉。一個大小驚人的文件很不利於管理,而且對於一個如此巨大的文件來說,讀寫它需要耗費的資源一樣巨大。更加令人費解的是,MySQL竟然將索引和數據保存於同一個文件中,索引和數據之間尚存在資源爭用,不利於性能的提升。你當然可以通過innodb_data_file_path的配置規劃多個表空間文件,但MySQL的邏輯是"用滿後增加",僅僅是一個文件的拆分而已,不能從根本上分離數據和索引。

 

之前曾經遭遇到700G以上的表空間文件,而且更加讓人鬱悶的是對於如此大的文件還在以每天數G的數量增加。由於無法停機,即便是拷貝一下也要花費差不多一夜,只能眼睜睜看着它繼續增大而毫無保守可行的辦法。

 

獨立表空間方式

 

相對而言對立表空間每個表都有獨立的多個數據文件,而且做到了索引和數據的分離。多個小文件之間很方便的完成跨數據庫甚至跨硬件的數據拷貝和遷移。相對來說靈活性很好。

 

這樣做同樣帶來另一個方面的問題。當數據庫中的表數量達到一定級別時,每次操作所涉及的文件過多,如果按照默認Centos的ulimit -n = 1024的話,僅僅只能保證同時打開256個表以內,這在習慣上"拆庫拆表"的MySQL數據結構上很難達到要求。尚且這種數據文件的利用率不算很高,當大量"不高"的文件集中起來,浪費的空間也很驚人,更何況最後可能出現的狀況不是"一堆K級別的小文件"而是"一堆G級別的大文件",有點適得其反的意思。你自然可以聯想到分區表,又是一個"僅僅做文件拆分而已",多個分區文件缺一不可。

 

之前同樣遇到過這個問題,MySQL連接大的狀況下大量的timeout,但主機負載還算可以,查了一圈才知道是open files限制的問題,限制一修改,負載變得驚人,但連接數卻又提升的不多。

 

總之,兩種方法各有所長,部分互補,但都不是解決問題的終極方案。期待MySQL能夠出現真正意義上表空間的概念,更加自由的規劃數據文件。)

例子:

create index ind_company_name on company(name(4))

其中company表明

ind_company_name 索引名

 

看下我們數據庫下面有多少數據庫啊

show databases;

use test;

鍵一個表;

CREATE TABLE t1(

id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

NAME VARCHAR(30)

);

//插入數據

INSERT INTO t1(NAME) VALUES("admin1"),("admin2"),("admin3"),("admin4"),("admin5")

比較這三個語句的耗時:

SELECT * FROM t1

SELECT * FROM t1 WHERE id=4;

SELECT * FROM t1 WHERE NAME="admin4";

解析這條語句:

DESC SELECT * FROM t1 WHERE id=4

解釋: 它是一個簡單的單表查詢SIMPLE,而且查詢的表是t1,裏面搜索的結果是1行,所以類型是const.possible_keys: PRIMARY可能應用到的索引是主鍵,實際應用索引key:PRIMARY,影響的行數rows 是1行,

使用索引長度ken_len: 4

執行解釋:DESC SELECT * FROM t1 WHERE NAME="admin4";

解釋:單表查詢 查詢表t1 索引沒用到,影響行數是5行 type:all 效率較低

 

咱們給它加索引吧:

ALTER TABLE t1 ADD INDEX in_name(NAME)

查看t1表下面的字段信息

DESC t1;

 

打上索引後咱們再來查看一下執行過程:

DESC SELECT * FROM t1 WHERE NAME="admin4";

最後印象行數rows 變成了1 ,現在是5行 如果生產線上是5000萬條數據了,這就是別人效率筆記快5000萬倍的原因了。一定要看影響行數啊 這個決定了你查詢時間啊,能不能在生產線上使用就看它了

查找了多少行就代表影響了多少行

 

所以:索引的使用是提高select操作性能的最佳途徑啊

下面介紹如何使用索引:

  1. 對於創建多列索引,只要查詢的條件中用到最左邊的列,索引一般會使用,如下創建一個符合索引

    create index ind_salescom_onsales (company_id,moneys);

    然後按company_id進行查詢就使用到了索引,

    explain select * from sales2 where company_id =20006

    使用moneys進行查詢就沒有到了索引,

    explain select * from sales2 where moneys =10

     

    (ysql 搜索有三種啊 第一種是like 第二種是正則查詢,第三種是sphinx(斯芬克斯)搜索加速,中文分詞,高能顯示,1000萬都只要001秒的耗時,很接近百度搜索引擎

     

  2. 使用like查詢的時候,如果%符號在第一個位置的時候,索引可能用不上啊

    建議按照人的習慣思維走啊 一般你記憶那個人的名字是吧 知道他姓什麼 名字可能記得不全是吧,類似於這樣

     

    DESC SELECT * FROM t1 WHERE NAME LIKE "admin%";

    DESC SELECT * FROM t1 WHERE NAME LIKE "%5";

  3. 如果那一列爲空null 搜索哪一行爲空也將用到索引

    下面我們給t1表新插入一條name爲空的行

    INSERT INTO t1(NAME) VALUES(NULL)

    然後執行查詢

    DESC SELECT * FROM t1 WHERE NAME IS NULL;

    查詢非空也用到了索引啊

    DESC SELECT * FROM t1 WHERE NAME IS NOT NULL;

     

    這些測試是告訴大家 你用了索引 在寫查詢語句的時候要注意 別搞了半天的索引用的時候又沒用上,查詢變慢對資源消耗很大啊,別一條sql語句執行了到第二天還沒搞完啊,這就尷尬了啊!當然開個玩笑

    二:存在索引但不使用索引的介紹

    1. 如果Mysql使用索引比全部掃描更慢,則不宜用索引,例如如果key_part1均勻分佈在1-100之間,查詢時使用索引就不太好。這個是mysql自己估計的。
    2. 如果在使用查詢時 用到 where or的組合方式 那麼 or或者是件列必須都是索引列啊索引才生效

      測試:DESC SELECT * FROM t1 WHERE id =1 or name="admin1

      這裏name上面的索引:

      ALTER TABLE t1 DROP INDEX in_name;

      測試:DESC SELECT * FROM t1 WHERE id =1 or name="admin1

    3. 如果某個列是字符串類型 而你查詢的時候將這個列的條件給了一個字符型,那麼該列上的索引頁用不到,這個在InnoDB和高版本5.5以上將優化

      加上索引:ALTER TABLE t1 ADD INDEX in_name(NAME);

      DESC t1; 查詢有沒有索引啊

      插入一條數據:INSERT INTO t1(NAME) VALUES("777")

      查詢語句:DESC SELECT * FROM t1 WHERE id =1 OR NAME="777"

       

三、查看索引使用情況

如果索引正在工作,Handler_read_key的值將很高,這個值代表一行被索引讀到的次數

Handler_read_rnd_next的值高則意味着查詢運行效率低,並且應該建立索引補救

查看索引參數使用情況 :SHOW STATUS LIKE 'Handler_read%'

這裏就要結合咱們的慢查詢 和DSC去建立索引啊

 

四:常用的表優化手段

建立一個t1表的視圖:

CREATE VIEW v_t1 AS SELECT * FROM t1 WHERE id>2 AND id<5

查看視圖是否存在:

SELECT * FROM v_t1

我打算把t1 表刪除 ,刪除之前先複製表啊

CREATE TABLE t2 LIKE t1; 複製表結構

INSERT INTO t2 SELECT * FROM t1; 複製數據

SELECT * FROM t2 查詢t2表

刪除t1表:

DROP TABLE t1;

SHOW TABLES

檢查視圖v_t1;

CHECK v_t1;

報錯:

查詢:CHECK TABLE v_t1;

這個是對咱們排錯是非常實用的,檢查一個或者多個表是否有錯誤,具體語法如下:

CHECK TABLE tbl_name[,tbl_name] ... [option] ...

option= {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}

 

類型意義

QUICK

不掃描行,不檢查錯誤的鏈接。

FAST

只檢查沒有被正確關閉的表。

CHANGED

只檢查上次檢查後被更改的表,和沒有被正確關閉的表。

MEDIUM

掃描行,以驗證被刪除的鏈接是有效的。也可以計算各行的關鍵字校驗和,並使用計算出的校驗和驗證這一點。

EXTENDED

對每行的所有關鍵字進行一個全面的關鍵字查找。這可以確保表是100%一致的,但是花的時間較長。

 

接着 咱們在表改回來:

RENAME TABLE t2 TO t1;

查詢是否含有t1表:

SHOW TABLES

在檢查視圖:

CHECK TABLE v_t1;

查詢視圖裏面的值:

SELECT * FROM v_t1

所以我們的check 可以檢查一個表,但是我們的InnoDB和MYISAM經常中間刪除或者修改大量的表,尤其是刪除,導致表的大小不會自動收索,另外一個手段,優化表空間,這個重點是把表空間進行整理,把產生的碎片和空洞剔除。

優化表空間:

OPTIMIZE TABLE t1

表不支持優化,做重建+分析

但是這裏提醒一下啊:一個大的表可能在被訪問的表不要隨隨便便的在工作時間來優化啊。

其他數據的導入導出

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章