數據類型與索引調優全解析

MySQL架構優化實戰系列1:數據類型與索引調優全解析

 

 

1、數據類型優化mysql

 

數據類型

 

  • 整數sql

 

 

數字類型:整數和實數數據庫

 

tinyint(8)、smallint(16)、mediuint(24)、int(32)、bigint(64) 數字表示對應最大存儲位數,如 tinyint (-127 --- 128),tinyint unsigned 表示不容許負數,則範圍爲 (0 -- 255)。編程

 

常規數據庫中 int(11) 只是表示控制顯示字符的個數是11個,int(1) 和 int(20) 存儲和計算是同樣的,即 int(1) 照樣能夠存儲1111(4位數)。緩存

 

  • 實數數據結構

 

實數有分數部分架構

  • float 和 double 類型支持使用標準的浮點運算近似計算併發

  • float 佔用4個字節 double佔用8個字節app

  • decimal 類型用於保存精確的小數函數

  • decimal(18,9) 18表示小數點先後總位數 9表示小數點後面位數

  • mysql 5.0版本以上 4個字節保存9位數字

  • decimal(18,9) 共佔用9個字節 小數點前4個字節 小數點後佔1個 小數點後4個字節

 

  • 字符串類型

 

varchar和char類型

  • varchar保存可變長度的字符串,比固定長度類型佔用更少的存儲空間,只佔用須要的空間。

    varchar使用額外的1到2字節存儲長度,列小於255使用1字節保存長度,大於255使用2字節保存,varchar保留字符串末尾的空格。

 

  • char是固定長度,保存char值時候 **mysql去掉任何末尾的空格** ,進行比較時 空格會被填充到字符串末尾。

    不少的char列,效率高於varchar,好比 char(1)對於單字節字符集佔用1字節,varchar(1)佔用兩字節,由於1字節保存長度。

慷慨不是明智的,分配真正須要的空間。

 

  • Blob和Text類型

 

blob和text惟一區別就是blob保存二進制數據、沒有字符集和排序規則。

 

選擇優化的數據類型 

 

  • 更小一般越好

 

 

使用更少的磁盤、內存、cpu,確保不會低估保存的值,可是text有字符集和排序規則。mysql不能索引這些數據類型的完整長度,也不能爲排序使用索引。

 

  • 簡單就好

 

比較整數的代價小於比較字符,使用mysql內建類型保存時間和日期,使用整數保存ip。

 

  • 儘可能避免NULL

 

mysql難以優化可空列查詢,使固定索引(整數列上的索引)編程可變大小索引;沒有值可使用 0 或者空字符串代替;把null 列改成not null 帶來的性能提高很小。

 

  • 肯定類型

 

像數字、字符串、時間、直觀類型能夠肯定,可是像 datetime 和timestamp,能保存一樣的類型。timestamp使用空間只有datetime一半。能夠保存時區。

 

  • 使用enum代替字符串類型

 

enum列能夠保存65535不一樣的字符串,存儲在一個 "查找表"中 mysql內部存儲的是列表中的位置。

 

內部存儲的是這個字符串對應的位置,實際表中存儲的仍是字符串。

 

建立一個表fruit category字段爲enum類型,包含4種不一樣水果:

 


 

插入4條數據,即4中不一樣水果。其中,最後一個菠蘿(pineapple) 沒有enum值 則插入了空數據。

 

發現字段category保存的仍是字符串,其實內部已經將這些字符串關聯到enum字符的位置。

 

 

支持字符串搜索和位置搜索

 

 

emu缺點在於插入數據以前,若是沒有對應enum,則須要alter表結構。

 

enum優勢在於佔用更少的存儲空間。

 

聽說 enum 用於聯接查詢性能也比較好。

 

  • 日期和時間類型

 

datetime 保存是1001年到9999年,精度是秒,存儲值爲 2016-05-06 22:39:40。

 

timestamp保存自 1970年1月1日午夜以來的秒數,和unix時間戳相同,提供4字節存儲 只能表示1970年到2038年。默認timestamp值 爲 NOT NULL。

 

mysql中提供 from_unixtime()函數把unix時間戳轉換爲日期

unix_timestamp()把日期轉換爲unix時間戳

 

若是須要秒如下的精度保存日期和時間,可使用bigint類型把它以毫秒的精度保存時間戳格式,或使用double保存秒的分數部分。

 

  • 選擇標識符

 

整數類型一般是標識符最佳選擇,速度快,且能使用auto_increment,避免使用字符串作標識符,佔用不少空間而且比整數類型要慢。

 

  • 特殊類型的數據

 

一般使用varchar(15)保存IP地址,其實IP地址是無符號的32位整數,不是字符串,小數點僅僅爲了可讀性。

 

mysql提供了 inet_aton() inet_ntoa() ,用於 ip地址和整數以前轉換。

 

2、索引優化

 

索引基礎知識

 

索引幫助mysql高效獲取數據的數據結構,索引(mysql中叫"鍵(key)") 數據越大越重要。索引比如一本書,爲了找到書中特定的話題,查看目錄,得到頁碼。

 

select fruit_name from fruit where id = 5 索引列位於id列,索引按值查找而且返回任何包含該值的行。

若是索引了多列數據,那麼列的順序很是重要。

 

存儲引擎說明

 

  • myisam 存儲引擎

  • 表鎖:myisam 表級鎖

  • 不支持自動恢復數據:斷電以後 使用以前檢查和執行可能的修復

  • 不支持事務:不保證單個命令會完成, 多行update 有錯誤 只有一些行會被更新

  • 只有索引緩存在內存中:mysiam只緩存進程內部的索引

  • 緊密存儲:行被僅僅保存在一塊兒

 

  • Innodb存儲引擎

  • 事務性:Innodb支持事務和四種事務隔離級別

  • 外鍵:Innodb惟一支持外鍵的存儲引擎 create table 命令接受外鍵

  • 行級鎖:鎖設定於行一級 有很好的併發性

  • 多版本:多版本併發控制

  • 按照主鍵彙集:索引按照主鍵彙集

  • 全部的索引包含主鍵列:索引按照主鍵引用行 若是不把主鍵維持很短 索引就增加很大

  • 優化的緩存:Innodb把數據和內存緩存到緩衝池 自動構建哈希索引

  • 未壓縮的索引:索引沒有使用前綴壓縮,阻塞auto_increment:Innodb使用表級鎖產生新的auto_increment

  • 沒有緩存的count():myisam 會把行數保存在表中 Innodb中的count()會全表或索引掃描

索引類型

 

索引在存儲引擎實現的,而不是服務層。

 

  • B-tree 索引

 

大多數談及的索引類型就是B-tree類型, 能夠在create table 和其餘命令使用它 myisam使用前綴壓縮以減少索引,Innodb不會壓縮索引,myiam索引按照行存儲物理位置引用被索引的行,Innodb按照主鍵值引用行,B-tree數據存儲是有序的,按照順序保存了索引的列,加速了數據訪問,存儲引擎不會掃描整個表獲得須要的數據。

 

  • B-tree 索引實例

 

使用B-tree索引的查詢類型,很好用於全鍵值、鍵值範圍或鍵前綴查找,只有在超找使用了索引的最左前綴的時候纔有用。

 

匹配全名:全鍵值匹配和索引中的全部列匹配

查找叫Tang Kang 出生於 1991-09-23 的人

 

匹配最左前綴:B-tree找到姓爲tang的人

 

匹配列前綴: 匹配某列的值的開頭部分 查找姓氏以T開頭的人        

 

匹配範圍值:索引查找姓大於Tang小於zhu的人

 

精確匹配一部分而且匹配某個範圍的另一部分:

查找姓爲Tang而且名字以字母K開頭的人 精確匹配last_name列而且對

first_name進行範圍查詢

 

只訪問索引的查詢:B-tree支持只訪問索引的查詢,不會訪問行

 

  • B-tree侷限性

B-tree侷限性:(案例中索引順序:last_name first_name dob )

 

若是查找沒有送索引列的最左邊開始,沒有什麼用處,即不能查找全部叫Kang 的人,也不能找到全部出生在某天的人,由於這些列再也不索引最左邊,也不能使用該索引超找某個姓氏以特定字符結尾的人。

 

不能跳過索引的列,即不能找到全部姓氏爲Tang而且出生在某個特定日期的人,若是不定義first_name列的值,Mysql只能使用索引的第一列。

 

存儲引擎不能優化任何在第一個範圍條件右邊的列,好比查詢是where last_name = 'Tang' AND first_name like 'K%' AND dob='1993-09-23' 訪問只能使用索引頭兩列。

 

由此可知 索引列順序的重要性!

 

  • 哈希索引

 

目前只有Memory存儲引擎支持顯示的哈希索引,並且Memory引擎對我來講不經常使用,因此咱們就輕描淡寫的過了吧。

 

 

  • R-tree(空間索引)

 

Myisam支持空間索引,可使用geometry空間數據類型。

 

空間索引不會要求where子句使用索引最左前綴能夠全方位索引數據,能夠高效使用任何數據組合查找 配合使用mercontains()函數使用。

 

  • 全文索引

 

fulltext是Myisam表特殊索引,從文本中找關鍵字不是直接和索引中的值進行比較。

 

全文索引能夠和B-Tree索引混用,索引價值互不影響。

 

全文索引用於match against操做 而不是普通的where子句。

 

  • 前綴索引和索引選擇性

 

一般索引幾個字符,而不是所有值,以節約空間並獲得好的性能,同時也下降選擇性。

 

索引選擇性是不重複的索引值和所有行數的比值。高選擇性的索引有好處,查找匹配過濾更多的行,惟一索引選擇率爲1最佳狀態。

 

blob列、text列及很長的varchar列,必須定義前綴索引,mysql不容許索引他們的全文。

 

  • 前綴索引和索引選擇性實例

造數據

 

#複製一份與cs_area表結構

 

#插入1600數據

#模擬真實數據

 

#表area有name列 須要對name列前綴索引

 

#計算得比值接近0.9350就行了

 

#分別取 3 4 5位name值計算

 

#可知name列添加5位前綴索引就能夠了

 

#Mysql不能在order by 或 group by查詢使用前綴索引 也不能將其用做覆蓋索引

 

  • 彙集索引

 

彙集索引不是一種單獨的索引類型,而是一種存儲數據的方式。

 

Innodb 的彙集索引實際上一樣的結構保存了B-tree索引和數據行,"彙集" 是指實際的數據行和相關的鍵值保存在一塊兒,每一個表只能有一個彙集索引,所以不能一次把行保存在兩個地方。 (因爲彙集索引對我來講不經常使用,咱們就略過啦~)

 

  • 覆蓋索引

 

 

索引支持高效查找行,mysql也能使用索引來接收列的數據。這樣不用讀取行數據,當發起一個被索引覆蓋的查詢,explain解釋器的extra列看到 using index。

#知足條件:#

# select 查詢的字段必須 有索引全覆蓋

select last_name,first_name 其中 last_name 和first_name 必須都有索引

#不能在索引執行like操做

 

  • 爲排序使用索引掃描

mysql排序結果的方式:使用文件排序 、 掃描有序的索引

 

explain中的type列若爲 "索引(Index)" 說明mysql掃描索引。單純掃描索引很快,若是mysql沒有使用索引覆蓋查詢 就不得不查找索引中發現的每一行。

 

mysql能有爲排序和查找行使用一樣的索引,如表 user 索引 (uid,birthday ) 。

 

使用排序索引:

 

  • 避免多餘和重複索引

重複索引:類型相同,以一樣的順序在一樣的列建立索引,好比在表user id列 添加 unique(id)約束 、id not null。


primary key 約束 index(id),其實這些是相同的索引 !

 

多餘索引:如存在(A)索引 應該擴展它 知足 (A,B)索引 
(A,B)索引 <==> (B) 
(A,B)索引 <==> (A) 
(A,B) A最左前綴 (B,A) B最左前綴

 

  • 索引實例研究

設計user表 字段:country、 state/region 、city 、sex 、age 、eye 、color  功能:支持組合條件搜索用戶 支持用戶排序 用戶上次在線時間

 

  • 支持多種過濾條件

 

不在選擇性不好的列添加索引

 

  • 優化排序

 

 

索引和表維護

 

表維護三個目標:查找和修復損壞、維護精確的索引統計,並減小碎片

 

  • 查找並修復表損壞

check table 命令:肯定表是否損壞,能抓到大部分表和索引錯誤 

repair table 命令:修復損壞的表

myisamchk :離線修復工具

 

  • 更新索引統計

analyze table cs_area 更新索引統計信息,便於優化器優化sql

show index 命令檢查索引的基數性

 

  • 減小索引和數據碎片

myisam引擎 使用 optimize table 清除碎片 Innodb 引擎 使用 alter table .. engine = .. 從新建立索引

 

正則化和非正則化

 

  • 正則化和非正則化

  • 正則化數據庫:每一個因素只會表達一次,教師表teacher (id,school_id), 學校表school 
    (school_id,school_name) 優勢:更新信息只變更一張表 缺點:簡單的學校名稱查詢 須要關聯表
    非正則化數據庫:信息是重複的 或者 保存在多個地方

     

  • 教師表teacher (id,school_id,school_name) 學校表school 
    (school_id,school_name)

     

  • 優勢:便於直接統計對應學校名稱的老師

    缺點:更新須要變更的表多一張

     

  • 正則化和非正則化並用:好比須要統計用戶的發帖數 能夠在user表添加字段num_message 保存發帖總數 避免高密度查詢統計

 

  • 緩存和彙總表

 

實例:統計過去24小時發佈的信息精確的數量

 

  • 表週期性建立

 

週期建立能夠獲得沒有碎片和全排序索引的高效表

 

 

 

注意:此法會將數據清除,只是獲得一個沒有碎片和高效的索引表。

 

計數表:好比緩存用戶朋友數量、文件下載次數 一般創建一個單獨的表,以保持快速維護計數器。

計劃任務按期聚合函數查詢,更新對應的字段。

相關文章
相關標籤/搜索