程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQL小技巧

MySQL小技巧

編輯:MySQL綜合教程

MySQL小技巧


簡介篇

存儲引擎

MyISAM是MySQL5.1及之前的版本的默認存儲引擎。MyISAM提供了大量的特性,包括全文索引、壓縮、空間函數(GIS)等,但是MyISAM不支持事務和行級鎖,而且有一個毫無疑問的缺陷就是崩潰後無法安全回復。

MyISAM會將表存儲在兩個文件中:數據文件和索引文件,分別以.MYD和.MYI為擴展名。

InnoDB表是基於聚簇索引建立的。

推薦InnoDB存儲引擎

數據類型

MySQL支持的數據類型非常多,總體上分為:數字、字符、日期、JSON。選擇正確的數據類型對於獲得高性能至關重要。不管存儲那種類型的數據,下面幾個簡單的原則都有助於作出更好的選擇。

1)更小的通常更好

一般情況下,應該盡量使用可以正確存儲數據的最小數據類型。更小的數據類型通常更快,因為他們占用更少的磁盤、內存和CPU緩存,並且處理時需要的CPU周期也更少。

2)簡單就好

簡單的數據類型的操作通常需要更少的CPU周期。例如,整型比字符操作代價更低,因為字符集和校對規則(排序規則)使字符比較比整型比較更復雜。

3)盡量避免NULL

很多表都包含可為NULL的列,即使應用程序並不需要保存NULL也是如此,這是因為可為NULL是列的默認屬性。通常情況下最好指定列為NOT NULL,除非真的需要存儲NULL值。

用NULL會浪費存儲空間,因為InnoDB需要一個額外的字節存儲。

NULL字段的復合索引無效。

如果查詢中包含可為NULL的列,對MySQL來說更難優化,因為可為NULL的列使得索引、索引統計和值比較都更負責。當可為NULL的列被索引時,每個索引記錄需要一個額外的字節,在MyISAM裡甚至還可能導致固定大小的索引(例如只有一個整數列的索引)變成可變大小的索引。

日期類型

DATE類型表示日期的年月日部分,范圍在1000-01-01到9999-12-31之間。

DATETIME類型表示日期的年月日時分秒部分,范圍在1000-01-01 00:00:00到9999-12-31 23:59:59之間。

TIMESTAMP類型表示日期的年月日時分秒部分,范圍在1970-01-01 00:00:01UTC到2038-01-19 03:14:07UTC之間。

可以讓DATETIME和TIMESTAMP自動初始化並且隨其他字段的修改而自動修改。

例如:

CREATE TABLE aaa (

id bigint(11) NOT NULL AUTO_INCREMENT,

ts timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

dt datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

name varchar(20) DEFAULT NULL,

PRIMARY KEY (id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

主鍵

整數通常是主鍵的最好選擇,因為他們很快並且可以使用AUTO_INCREMENT。

如果可能,應該避免使用字符串類型作為主鍵,因為他們很消耗空間,並且通常比數字類型慢。尤其在MyISAM表裡使用字符串作為主鍵要特別小心。MyISAM默認對字符串使用壓縮索引,這會導致查詢慢很多。

對於完全“隨機”的字符串也許多加注意,例如MD5()、SHA1()、或者UUID()產生的字符串。這些函數生成的新值會任意分布在很大的空間內,這回導致INSERT以及一些SELECT語句變得很慢:

因為插入值會隨機地寫到索引的不通位置,所以是的INSERT語句更慢。這回導致頁分裂、磁盤隨機訪問,以及對於聚簇存儲引擎產生聚簇索引碎片。

SELECT語句會變得更慢,因為邏輯上相鄰的行會分布在磁盤和內存的不同地方。

隨機值導致緩存對所有類型的查詢語句效果都很差,因為會使得緩存賴以工作的訪問局部性原理失效。如果整個數據集都一樣的“熱”,那麼緩存任何一部分特定數據到內存都沒有好處;如果工作集比內存大,緩存將會有很多刷新和不命中。

如果存儲UUID值,則應該移除“-”符號;或者更好的做法是,用UNHEX()函數轉換UUID值為16字節的數字,並且存儲在一個BINARY(16)列中。檢索時可以通過HEX()函數來格式化為十六進制格式。

UUID()生成的值與加密散列函數例如SHA1()生成的值有不同的特征:UUID值雖然分布也不均勻,但還是有一定順序的。盡管如此,還是不如遞增的整數好用。

索引

B-Tree索引

B-Tree索引能夠加快訪問數據的速度,因為存儲引擎不再需要進行全表掃描來獲取需要的數據,取而代之的是從索引的根節點開始進行搜索。

B+樹索引並不能找到一個給定鍵值的具體行。B+樹索引能找到的只是被查找數據行所在的頁。然後數據庫通過把頁讀入內存,再在內存中進行查找,最終得到要查找的數據。

限制:

如果不是按照索引的最左列開始查找,則無法使用索引。

不能跳過索引中的列。

如果查詢中有某個列的范圍查詢,則其右邊所有列都無法使用索引優化查找。

Hash索引

高性能索引策略:

分區表

分區功能並不是在存儲引擎層完成的。分區有水平分區和垂直分區兩種,但是MySQL不支持垂直分區。

大多數DBA會有這樣一個誤區:只要啟用了分區,數據庫就會變得更快。這個結論是存在很多問題的。其實,分區對於某些SQL語句性能可能會帶來提高,但是分區主要用語高可用性,利於數據庫的管理。在OLTP應用中,對於分區的使用應該非常小心。如果只是一味使用分區,而不理解分區是如何工作的,也不清楚你的應用如是使用分區,那麼分許極有可能只會對性能產生負面的影響。

MySQL數據庫支持以下幾種分區類型:

RANGE分區:

LIST分區:

HASH分區:

KEY分區:

不論創建哪種類型的分區,如果表中存在主鍵或者是唯一索引時,分區列必須是唯一索引的一個組成部分。

唯一索引可以是允許NULL值的,並且分區列只要是唯一索引的一個組成部分,不需要整個唯一索引列都是分區列。

當建表時沒有指定主鍵和唯一索引時,可以指定任何一列為分區列。

規范篇

規范存在意義

保證線上數據庫schema規范

減少出問題概率

方便自動化管理

規范需要長期堅持,對開發和DBA是一個雙贏的事情

核心規范

不在數據庫做運算:cpu計算務必移至業務層

控制單表數據量:單表記錄控制在1000w

控制列數量:字段數控制在20以內

平衡范式與冗余:為提高效率犧牲范式設計,冗余數據

拒絕3B:拒絕大sql,大事物,大批量

基本命名和約束規范

表字符集選擇UTF8 ,如果需要存儲emoj表情,需要使用UTF8mb4(MySQL 5.5.3以後支持)

存儲引擎使用InnoDB

變長字符串盡量使用varchar varbinary

不在數據庫中存儲圖片、文件等

單表數據量控制在1000w以下

庫名、表名、字段名不使用保留字

庫名、表名、字段名、索引名使用小寫字母,以下劃線分割 ,需要見名知意

庫表名不要設計過長,盡可能用最少的字符表達出表的用途

索引規范

單個索引字段數不超過5,單表索引數量不超過5,索引設計遵循B+ Tree索引最左前綴匹配原則

選擇區分度高的列作為索引

建立的索引能覆蓋80%主要的查詢,不求全,解決問題的主要矛盾

DML和order by和group by字段要建立合適的索引

不在索引做列運算

避免索引的隱式轉換

避免冗余索引

不要用外鍵

關於索引規范,一定要記住索引這個東西是一把雙刃劍,在加速讀的同時也引入了很多額外的寫入和鎖,降低寫入能力,這也是為什麼要控制索引數原因。之前看到過不少人給表裡每個字段都建了索引,其實對查詢可能起不到什麼作用。

冗余索引例子

idx_abc(a,b,c)

idx_a(a) 冗余

idx_ab(a,b) 冗余

隱式轉換例子

字段:remark varchar(50) NOT Null

MySQL>SELECT id, gift_code FROM gift WHERE deal_id = 640 AND remark=115127; 1 row in set (0.14 sec)

MySQL>SELECT id, gift_code FROM pool_gift WHEREdeal_id = 640 AND remark=‘115127’; 1 row in set (0.005 sec)

字段定義為varchar,但傳入的值是個int,就會導致全表掃描,要求程序端要做好類型檢查

字段規范

所有字段均定義為NOT NULL ,除非你真的想存Null

字段類型在滿足需求條件下越小越好,使用UNSIGNED存儲非負整數 ,實際使用時候存儲負數場景不多

使用datetime存儲時間

使用varchar存儲變長字符串 ,當然要注意varchar(M)裡的M指的是字符數不是字節數;使用UNSIGNED INT存儲IPv4 地址而不是CHAR(15) ,這種方式只能存儲IPv4,存儲不了IPv6

使用DECIMAL存儲精確浮點數,用float有的時候會有問題

少用blob text

SQL規范

盡量不使用存儲過程、觸發器、函數等

避免使用大表的JOIN,MySQL優化器對join優化策略過於簡單

避免在數據庫中進行數學運算和其他大量計算任務

SQL合並,主要是指的DML時候多個value合並,減少和數據庫交互

UPDATE、DELETE語句不使用LIMIT,容易造成主從不一致

不用select *

慎用count(*)

避免負向%

請使用同類型比較

sql語句盡可能簡單

一條sql只能在一個cpu運算

大語句拆小語句以減少鎖時間

一條大sql可以堵死整個庫

簡單的事務

事務時間盡可能短

bad case:

上傳圖片事務

OR改寫為IN()

or的效率是n級別

in的消息時log(n)級別

in的個數建議控制在200以內

select id from t where phone=’159′ or phone=’136′;

=>

select id from t where phone in (’159′, ’136′);

OR改寫為UNION

mysql的索引合並很弱智

select id from t where phone = ’159′ or name = ‘john’;

=>

select id from t where phone=’159′

union

select id from t where name=’jonh’

limit高效分頁

limit越大,效率越低

select id from t limit 10000, 10;

=>

select id from t where id > 10000 limit 10;

使用union all替代union

union有去重開銷

使用load data導數據

load data比insert快約20倍;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved