MySQL優化那些事兒

MySQL的使用優化主要從優化庫表結構、使用合適的索引、優化查詢等方面考慮。mysql

優化庫表結構

說說數據類型

字符串類型

在MySQL中表示字符串的類型有多種,其中常見的有Char和VarChar,BLOB和TEXT以及能夠實現某些優化的ENUM。咱們要認識到不一樣的數據類型在存儲和使用的區別,而後合理的使用就能實現優化。sql

關於MySQL中數據類型的介紹,能夠參看個人另外一篇博文: MySQL的常見操做數據庫

Char和VarChar緩存

Char是定長類型,MySQL會根據定義的字符串的長度分配足夠的空間,而且MySQL在存儲CHAR值的時候會刪除末尾全部的空格。對於常常變動的數據,通常採用CHAR來進行存儲,由於CHAR類型在變化的時候不容易產生碎片。服務器

VARCHAR是變長類型,它比CHAR更加節省空間,可是VARCHAR在數據變化的時候容易產生碎片,因此通常用於做爲不常常變化的數據的數據類型。VARCHAR須要多使用一個或者兩個額外字節來記錄字符串的長度,若是列的最大長度小於等於255字節就用一個額外的字節來存儲長度,不然使用兩個字節。例如VARCHAR(10)的列須要11個字節的存儲空間,VARCHAR(1000)的列須要1002個字節。併發

注意,在5.0或者更高的版本中,MySQL在存儲或者檢索VARCHAR數據類型時保留末尾空格,可是在4.1或者更老的版本中,MySQL在存儲或者檢索VARCHAR數據類型時和CHAR同樣都是刪除末尾的空格app

BLOB和TEXT函數

BLOB即SMALLBLOB,TEXT即SMALLTEXT。BLOB和TEXT都是爲了存儲很大的數據而設計的字符串數據類型,分別採用二進制和字符串的方式來存儲。性能

使用ENUM來代替字符串類型測試

MySQL在存儲枚舉的時候很是的緊湊,會根據列表值的數量壓縮到一個或者兩個字節中。MySQL在內部會將每一個值在列表中的位置保存爲整數,而且在表的.frm文件中保存"數字-字符串"映射關係的"查找表"。

例如:create table enum_test(e enum('apple','banana','pear'));insert into enum_test(e) values('apple'),('banana'),('pear');而後咱們所插入的數據在表中實際上是存儲爲整數的。

數字類型

MySQL能夠爲整數類型指定寬度,如INT(1),INT(20),可是這對大多數應用是沒有意義的。MySQL所指定的整數類型的寬度只是用於設置一些MySQL客戶端用於顯示字符的個數,對於存儲和計算而言,INT(1)和INT(20)不會限制值的合法範圍,這兩種類型都是相同的。

日期和時間類型

DateTime和TimeStamp

DATETIME和TIMESTAMP是兩種日期類型,兩種類型在MySQL中存儲數據的格式徹底相同(都是yyyy-MM-dd HH:mm:ss),可是二者也有不一樣之處。

DATETIME能保存大範圍的值,從1001年到9999年,精度爲秒。MySQL採用8個字節來存儲DATETIME數據類型所包含的值。默認狀況下,MySQL以一種可排序的、無歧義的格式顯示DATETIME的值。

TIMESTAMP保存了從1970年1月1日午夜(格林尼治標準時間)以來的秒數,它和UNIX的時間戳相同。TIMESTAMP僅僅使用4個字節的存儲空間,因此它能表示的時間範圍也比DATETIME小,只能表示從1970年到2038年。TIMESTAMP也有DATETIME沒有的特殊屬性,默認狀況下,若是插入時沒有指定第一個TIMESTAMP列的值,MySQL則設置該列的值爲當前時間。

採用合適的索引

索引優化

索引優化是一個很大的方面,這裏只是簡單的介紹一些基本使用,事後會推出關於索引優化與設計的專題。

索引基礎

在MySQL中,索引是在存儲引擎層而不是服務器層實現的。Mysql中索引結構有:B-Tree索引、哈希索引、空間數據索引(R-Tree索引)、全文索引等索引結構,不一樣的存儲引擎對於上述索引結構的實現不一樣,並且也不是全部的存儲引擎都有這5種索引結構類型。

索引類型:

MySQL中的索引類型主要有5種:

  1. 普通索引: 最基本的索引、沒有任何限制。MyIASM中默認的BTREE類型的索引。如ALTER TABLE article ADD INDEX index_title_name ON title(100);CREATE INDEX index_name ON table(column(100)),或者直接在建立表的時候定義索引index index_title_name(title(100))
  2. 惟一索引: 索引列的值能夠爲空。與普通索引相似,不一樣之處在於索引列的值必須惟一。如ALTER TABLE article ADD UNIQU index_title_name ON title(100);CREATE UNIQUE INDEX index_name ON table(column(100))或者直接在建立表的時候定義索引UNIQUE index_title_name(title(100))
  3. 全文索引:主要用來查找文本中的關鍵字,而不是直接與索引中的值相比較。僅可用於 MyISAM 表,針對較大的數據,生成全文索引很耗時耗空間。如ALTER TABLE article ADD FULLTEXT index_content(content)CREATE FULLTEXT INDEX index_content ON article(content)FULLTEXT (content)
  4. 主鍵索引:它是一種特殊的惟一索引,不容許有空值。
  5. 最左索引(組合索引): 組合索引能夠更好的提升MySQL效率,最左索引遵循"最左索引"原則。建立複合索引時應該將最經常使用(頻率)做限制條件的列放在最左邊,依次遞減。

索引方法:

可使用B樹索引的查詢:

  1. 全值匹配的查詢
  2. 匹配最左前綴的查詢
  3. 匹配列前綴的查詢
  4. 匹配範圍值的查詢
  5. 精確匹配左前列而且範圍匹配另一列
  6. 覆蓋索引(只須要訪問索引而無需查詢數據行)

使用B樹索引的限制

  1. 在多列索引中,必須按照索引的最左列開始查找,不然索引沒法使用
  2. 在多列索引中,不能跳過索引中的列。好比一個三列組成的聯合索引,不能只使用第一列和第三列進行查詢而跳過第二列。
  3. not in和<>操做沒法使用索引
  4. 若是查詢中有某一個列的範圍查詢,則其右邊全部的列都不能使用索引。

Hash索引的特色:

Hash索引是基於Hash表實現的,只有查詢條件精確匹配Hash索引中的全部列時,才能使用Hash索引,Hash索引只適用於等值查詢不適合模糊查詢和範圍查詢。

對於Hash索引中的全部列,存儲引擎都會爲該列的每一行計算一個Hash碼,Hash索引中存儲的就是Hash碼。

使用Hash索引的限制:

  1. Hash索引必須進行二次的查找。
  2. Hash索引沒法進行排序。
  3. Hash索引不支持部分索引查找也不支持範圍查找。
  4. Hash索引中Hash的計算可能存在Hash衝突。

B樹索引與Hash索引在不少地方是不一樣的。B樹索引除了能加快數據的查找速度以外還能夠作到排序和分組,B樹索引的葉子節點存儲了索引關鍵字的值,能夠直接經過索引查找關鍵字的信息從而避免了訪問數據行。可是Hash索引的葉子節點中存儲的是關鍵字信息的Hash碼,咱們須要將查詢信息轉化成Hash在表中找到對應的數據行才能查找到數據的信息。所以Hash索引不能做爲覆蓋索引來使用。

覆蓋索引:

若是一個索引包含全部須要查詢的字段的值(where語句的參數、order by的參數、group by的參數),那麼咱們一般稱這個索引爲覆蓋索引。對於Memory存儲引擎不能使用覆蓋索引,查詢過程當中若是包含了太多的列(如select *)也不適合使用覆蓋索引。 使用覆蓋索引也有不少的優勢。

  • 優化緩存,減小磁盤I/O操做。
  • 減小隨機I/O,變隨機I/O爲順序I/O。
  • 能夠避免對Innodb主鍵索引的二次查詢。

InnoDB存儲引擎中的索引

InnoDB做爲MySQL最爲著名的存儲引擎,這裏要作特別的介紹。InnoDB中存儲引擎支持B+樹索引、全文索引和哈希索引。InnoDB存儲引擎支持的哈希引擎是自適應的,InnoDB存儲引擎會根據表的使用狀況自動爲表生成哈希索引,不能人爲干預是否在一張表中生成哈希索引。

傳統意義上的索引就是指的B+樹索引,這是目前關係型數據庫系統中查找最爲經常使用和有效的索引,其構造就是採用了二叉樹的思想,根據鍵值對快速找到數據。經過B+樹索引找到被查找數據行所在的頁,而後數據庫把頁讀入到內存,再在內存中進行查找,找到對應的數據。

InnoDB使用的是行鎖,只有在修改行時,纔會對行進行加鎖。使用索引可以使得數據在查詢過程當中鎖定更少的行,增長了數據處理的併發性,提升了數據庫的性能。

索引使用的注意事項

  1. 保證在MySQL中查找數據時,表中對應的列數獨立的。獨立的列在於索引列不能是表達式中的一部分,也不能是函數的參數。即不容許select id from article where id+1=5等狀況的出現,不然索引將不能使用。
  2. 索引很長的字符列,會讓索引變得大且慢。這個時候就要採用前綴索引,就是選取列開始的部分字符做爲索引,前綴索引的選擇也要保證合理的索引選擇性(越接近1越好)。
  3. 若是不須要考慮排序和分組的須要,在聯合索引中,應該將選擇性最高的索引放到索引的最前列、將常常會被使用的列放到索引的最前列、寬度較小的列放到索引的最前列。
  4. 使用pt-duplicate-key-checker h=127.0.0.1查找重複和冗餘的索引,而後將重複冗餘的索引刪除。

改造SQL查詢語句

MySQL鏈接過程與狀態

MySQL鏈接狀態

MySQL客戶端和服務器之間的通訊協議是"半雙工"的,在任何一個時刻,要麼是由服務器向客戶端發送數據,要麼是由客戶端向服務器端發送數據,兩個動做不能同時發生。對於每個時刻,能夠經過命令show full processlist來查看mysql當前鏈接的狀態(Command列就表明當前的狀態)。

MySQL的狀態以下:

Sleep: 線程正在等待客戶端發送新的請求

Query: 線程正在執行查詢或者正在將結果發送給客戶端。

Locked: 在MySQL服務器層,該線程正在等待表鎖.

Sorting result: 線程正在對結果集進行排序。

Copying to tmp table [on disk]: 線程正在執行查詢,而且將其結果集都複製到一個臨時表中,這種狀態要麼是在作GROUP BY操做,要麼是文件排序操做,或者是UNION操做。若是狀態上有on disk的標記,那麼表示MySQL正在將一個內存臨時表放到磁盤上。

Analyzing and statistics: 線程正在收集存儲引擎的統計信息,並生成查詢的執行計劃。

Sending data: 這表示線程或者在多個狀態之間傳送數據,或者在生成結果集,或者在向客戶端返回數據。

MySQL鏈接過程

  1. MySQL客戶端發送一條查詢給服務器
  2. MySQL若是開啓了查詢緩存,那麼MySQL服務器會優先檢查查詢緩存。檢查的過程是經過一個對大小敏感的哈希查找實現的,若是緩存命中,那麼在返回查詢結果以前MySQL會檢查一次用戶權限,若是權限合適,那麼直接返回緩存中的結果信息,查詢完成,不然執行下一步。
  3. 服務器進行SQL解析、預處理,而後再由優化器生成對應的執行計劃。
  4. MySQL根據優化器生成的執行計劃,調用存儲引擎的API來執行查詢。
  5. 將查詢的結果返回給客戶端。

查詢優化

在上面MySQL執行查詢的過程當中,服務器已經提供了一些SQL的優化措施,咱們也須要正確理解並使用這些個優化措施

  1. 使用explain+sql查詢語句能夠查看SQL查詢的效率。
  2. mysql使用基於成本的優化器。使用show status like 'last_query_cost'能夠查詢當前會話的last_query_cost值來得知mysql計算的當前查詢的成本,mysql會進行評估並獲得成本最小的執行計劃。
  3. MySQL自帶一種"嵌套循環"可以對咱們的大多數查詢進行優化操做,調整關聯表的關聯順訊以達到高效的查詢。

優化數據訪問

優化數據訪問的關鍵在於:減小數據訪問量,只檢索必要訪問的數據,保證向數據庫發出的查詢數據量只是實際須要的數據量。

爲了實現數據訪問量的優化,可使用:

  1. 在SQL的查詢語句中,合理的使用limit控制行數。
  2. 在多表關聯的SQL查詢中,只查詢須要的表的列,儘可能不要用"select *"
  3. 藉助第三方的緩存系統,將常常查詢的數據緩存起來。
  4. 若是查詢是須要掃描大量的數據但只是返回少許的行,那麼可使用索引覆蓋掃描,把須要數據的行放到索引中。

重構查詢

  1. 將大的查詢分解成小的查詢。特別是對於刪除不須要的數據,通常來講就是分批刪除少許的數據,這樣能夠大大減小數據庫鎖的持有時間。
  2. 合理的分解關聯查詢。關聯查詢分解成單表查詢能夠減小鎖的競爭;同時單表查詢的結果在應用層作關聯,能夠實現數據庫的拆分,作到高性能和可擴展。此外,經過將重複查詢的數據作緩存能夠提升效率。
  3. MySQL的某些子查詢效率很低(如使用in的子查詢),咱們應該使用explain語句測試當前查詢的成本,而後決定是否應該使用內鏈接或者左(右)外鏈接改寫mysql的in()子查詢。但當咱們須要返回一個表中的某些列時,多表關聯查詢咱們可使用exists關鍵字的子查詢,這樣效率也會更高。——在MySQL5.6版本之前需注意
  4. 在使用union關鍵字進行sql查詢時,若是有限制數據量和排序等操做,應在每一條sql語句中使用這些限制。
  5. 使用主鍵自帶的排序效果和limit關鍵字來代替max和min關鍵字實現最大和最小值。
  6. MySQL在須要進行分頁時,經過使用limit外加偏移量來實現,同時加上合適的order by子句,這樣能夠充分的利用具備索引的列。此外,在分頁中,偏移量若是相差數據量過大,應該採用索引覆蓋掃描。
  7. 進行關聯查詢時,在on和using子句的列上添加索引,而且注意在關聯順序上,應該在第二章表中添加索引,提升效率。
  8. 確保group by和order by子句的表達式上只涉及一個表中的列,只有這樣纔有可能使用索引優化這個過程。
相關文章
相關標籤/搜索