數據庫調優,就好比蓋樓打地基,地基打得不穩,樓層一高,就會塌方。數據庫也是如此,數據少,并發小,隱藏的問題是發現不了的,只要達到一定規模后,所有的問題就會全部曝露出來了,所以前期的設計階段尤為重要。
硬件、網絡取決于公司的經濟實力。
軟件再分為表設計(字段類型、存儲引擎)、SQL語句優化與索引、配置文件參數、體系架構等方面的優化。
一個好的數據庫設計對于數據庫的性能優化常常會起到事半功倍的效果。合理的數據庫結構不僅可以使數據庫占用更小的磁盤空間,而且能夠使查詢速度更快。
將字段很多的表分解成多個表
對于字段較多的表,如果有些字段的使用頻率很低,可以將這些字段分離出來形成新表。因為當一個表的數據量很大的時候,會由于使用頻率低的字段的存在而變慢。
增加冗余字段,適度冗余
設計數據庫表時應盡量遵守范式理論的約定,盡可能減少冗余字段。但是合理地加入冗余字段也可以提高查詢速度。這就是以空間換時間。
總結:在開發應用程序時,設計的數據庫要最大程度地遵守三范式。但是,三范式最大的問題在于通常需要join很多表,而這個會導致查詢效率很低。所以有時候基于查詢性能考慮,我們需要有意違反三范式,適度的冗余,以達到提高查詢效率的目的。
原則:選擇字段的一般原則是保小不保大,能用占用字節少的字段就不用大字段。
數字類型
tinyint類型最大存儲是255。
create table tmp(id tinyint);insert into tmp(id) values(256);//溢出int(11) vs int(21) 存儲空間還是存儲范圍有區別? int(11)與int(21)的存儲空間與存儲范圍是一樣的。區別是:如果你選擇是int(11),那么你存放了一個1,那么結果是1前面有10個0,int(21)前面有20個零
實驗: create table t(a int(11) zerofill,b int(21) zerofill);//zerofill 是補全零的 insert into t values(1,1); select * from t; +-------------+-----------------------+ | a | b | +-------------+-----------------------+ | 00000000001 | 000000000000000000001 | +-------------+-----------------------+ 1 row in set (0.00 sec)字符串類型 * char
char存儲空間定長,容易造成空間的浪費。char數據類型存儲大小最大為255字符。最大255個字符的意思是最大只能存放255個字母或者255個漢字varchar
varchar存儲變長,節省存儲空間,varchar需要一位來存儲長度。varchar是使用多少,就使用多少空間。所以通常都是選擇varchar。
varchar數據類型可以存儲超過255個字符
注意:char和varchar存儲單位為字符。字符與字節需要換算。
實驗: //char最大長度255字符,所以報錯 MySQL> create table c(a char(256));
ERROR 1074 (42000): Column length too big for column 'a' (max = 255); use BLOB or TEXT instead//varchar存儲長度可以超過255create table c(a varchar(256));Query OK, 0 rows affected (0.16 sec)字符與字節的關系
如果是utf8字符集,因為utf8存放中文占用三個字節大小,所以存放兩個中文需要6個字節大小。
一個英語字母無論什么情況下都是占用一個字節的,所以varchar(6)就可以存放github這個英語單詞了
date
date三個字節,如2015-05-01只能存儲到天數。date精確到年月日
time
time三個字節,只能存小時分鐘,time精確到小時分鐘秒
datetime
datetime八字節,可以存儲年月日時分秒
timestamp
timestamp四字節,可以存儲年月日時分秒。
事務處理支持與否
InnoDB是支持事務,MyISAM不支持事務。
查詢速度不一樣
一般認為MyISAM查詢速度快。一般一些小型項目使用myisam引擎也是可以的。
鎖機制不一樣
InnoDB支持行鎖、表鎖,MyISAM只有表鎖。
文件存放方式不一樣
MyISAM產生三個文件,.frm是存放表定義,.MYD存放數據,.MYI存放表的索引
InnoDb的數據與索引一般是在一起存放的。
myisam: 讀 => 表鎖 =》 讀鎖:不會阻塞其他的讀,但是阻塞寫 一個人正在讀,其他人可以讀。但是不能寫。
可以同時進行讀操作。寫 =》 表鎖 =》 寫鎖: 阻塞讀、寫
一個人正在寫,然后其他人不能讀,也不能寫innodb: 行鎖:影響的是一行。
MyISAM存儲引擎只支持表鎖,所以對MyISAM表進行操作,會存在以下情況:
對MyISAM表的讀操作,不會阻塞其他進程對同一個表的讀請求,但會阻塞對同一個表寫請求。只有當讀鎖釋放后,才會執行其他進程的寫操作。對MyISAM表的寫操作,會阻塞其他進程對同一個表的讀和寫操作,只有當寫鎖釋放后,才會執行其他進程的讀寫操作。準備一個千萬級的數據表
create table t2(id int PRimary key auto_increment,name varchar(20))engine=myisam;insert into t2(name) values('a'),('b'),('c');insert into t2(name) select name from t2;//這條語句重復n次后就有很多數據當正在讀myisam,同時不能寫
select * from t2;
update t2 set name= ‘liangzhi’ where id = 1;
更新語句,只有等查詢語句執行結束后才可以執行,也就是說讀鎖釋放后,才能進行寫操作。否則一直在等待狀態。
InnoDB存儲引擎是通過索引上的索引項加鎖來實現的,這就意味著:只有通過索引操作數據,InnoDB才會使用行鎖。否則,InnoDB將使用表鎖。
A連接:create table t3(a int ,b int,key(a),key(b) )engine=innodb default charset=utf8;create table t3(a int ,b int )engine=innodb default charset=utf8;insert into tt3 values(1,1);insert into tt3 values(1,6);insert into tt3 values(1,10);begin;select * from t3 where a= 1 and b =6 for udpate;//for update 給a = 1 b =6那一行加鎖B連接:begin;//發現也無法查詢,因為a中沒有索引,所以只有條件走索引才能實現行級鎖,否則加表鎖select * from t3 where a= 1 and b = 10 for update;事務支持
MyISAM是非事務安全型的,而InnoDB是事務安全型的,也就是支持事務
鎖機制
MyISAM鎖是表鎖,鎖開銷最小,而InnoDB支持行鎖,鎖管理開銷大,支持更好的并發寫操作。
文件保存形式
每張MyISAM表存放在3個文件中:frm文件存放表格存放,數據文件是MYD,索引文件是MYI
數據安全性 InnoDB表比MyISAM表更安全,因為InnoDB具有崩潰恢復能力。
InnoDB支持行鎖、事務。如果應用中需要執行大量的讀寫操作,應該選擇InnoDB,這樣可以提高多用戶并發操作的性能。在MySQL5.5之后版本,Oracle已經很少支持MyISAM了,所以建議優先選擇InnoDB引擎。
系統優化中一個很重要的方面就是SQL語句的優化。對于海量數據,劣質SQL語句和高效SQL語句之間的速度差別可以達到上百倍。
開啟慢查詢日志的好處是可以通過記錄、分析慢SQL語句來優化SQL語句
開啟慢查詢日志,在my.cnf配置文件中,加入以下參數:
slow_query_log = 1slow_query_log_file = mysql.slowlong_query_time = 1 # 超過1秒的SQL會記錄下來limit分頁優化
傳統的分頁:select SQL_NO_CACHE * from t2 order by id limit 99999,10;
傳統的的分頁,雖然用上了id索引,但要從第一行開始起定位到99999行,然后再掃描出后10行,相當于進行一個全表掃描,顯然效率不高。
優化方法:
select SQL_NO_CACHE * from t2 where id >= 100000 order by id limit 10;
優化方法利用id索引直接定位100000行,然后再掃描出后10行。速度相當快。
避免使用*號,只查需要的字段
多使用limit,減少數據傳輸
用戶查看所有的數據。 Ajax異步請求。可以使用冗余來減少關聯表查詢
給常在where條件后的字段添加索引,并且合理使用索引分類:主鍵索引、唯一索引、普通索引、全文索引
適當的索引對應用的性能來說相當重要,而且也建議在MySQL中使用索引,它的速度是很快的。
但是索引也是有成本的。每次向表中寫入時,如果帶有一個或多個索引,那么MySQL也要更新各個索引。索引還增加了數據庫的規模,也就是說索引也是占據空間的。
只有當某列被用于where子句時,才能享受索引性能提升的好處。如果不使用索引,它就沒有價值,而且會帶來維護上的開銷。
依據where查詢條件建立索引
select a,b from tab a where c = ? //應該給c建立索引使用聯合索引,而不是多個單列索引
select * from tab where a = ? and b =?//給(a,b)建立聯合索引,而不是分別給a,b建立索引alter table tab add index in_ab(a,b);聯合索引中索引字段的順序根據區分度排,區分度大的放在前面
//(name,sex);//將name放前面,因為name的區分度更大。因為sex只有0 1 2 這個三個值。合理創建聯合索引,避免冗余
//(a),(a,b),(a,b,c)只要給(a,b,c)建立索引就行order by 、group by 、 distrinct字段添加索引字段使用函數,將不能用到索引
select createtime from aa where date(createtime) = curdate();//where后面的字段(createtime)使用函數,將不會使用到索引。用數字當字符類型,數字一定要加引號
select * from user where name = 123 //這SQL語句用不到name索引select * from user where name = '123' //這樣寫才會用到name字段上的索引在使用like關鍵字進行查詢的語句中,如果匹配字符串的第一個字符為”%”,索引不會起作用。
//用不到索引的 desc select * from t where name like "%j%"/G;//用到索引 desc select * from t where name like "j%"/G;聯合索引,只有查詢條件中使用了這些字段中第一個字段時,索引才會被使用
create index in_name on user(name,email)explain select * from user where name = 'jack'; //用到索引explain select * from user where email = 'jack@QQ.com'; //用不到索引使用OR關鍵字的查詢語句
查詢語句的查詢條件中只有OR關鍵字,且OR前后的兩個條件中的列都是索引時,查詢中才使用索引。否則查詢將不使用索引。order by 的字段混合使用asc和desc用不到索引
select * from user order by id desc,name asc;where 子句使用的字段和order by 的字段不一致
select * from user where name = 'jack' order by id;對不同關鍵字使用order by 排序
select * from user order by name,id;新聞熱點
疑難解答