u Mysql數據庫的優化技術mysql
對mysql優化時一個綜合性的技術,主要包括linux
a: 表的設計合理化(符合3NF)sql
b: 添加適當索引(index) [四種: 普通索引、主鍵索引、惟一索引unique、全文索引]數據庫
c: 分表技術(水平分割、垂直分割)編程
d: 讀寫[寫: update/delete/add]分離緩存
e: 存儲過程 [模塊化編程,能夠提升速度]安全
f: 對mysql配置優化 [配置最大併發數my.ini, 調整緩存大小 ]服務器
g: mysql服務器硬件升級session
h: 定時的去清除不須要的數據,定時進行碎片整理(MyISAM)mysql優化
u 什麼樣的表纔是符合3NF (範式)
表的範式,是首先符合1NF, 才能知足2NF , 進一步知足3NF
1NF: 即表的列的具備原子性,不可再分解,即列的信息,不能分解, 只有數據庫是關係型數據庫(mysql/oracle/db2/informix/sysbase/sql server),就自動的知足1NF
數據庫的分類
關係型數據庫: mysql/oracle/db2/informix/sysbase/sql server
非關係型數據庫: (特色: 面向對象或者集合)
NoSql數據庫: MongoDB(特色是面向文檔)
2NF: 表中的記錄是惟一的, 就知足2NF, 一般咱們設計一個主鍵來實現
3NF: 即表中不要有冗餘數據, 就是說,表的信息,若是可以被推導出來,就不該該單獨的設計一個字段來存放. 好比下面的設計就是不知足3NF:
反3NF : 可是,沒有冗餘的數據庫未必是最好的數據庫,有時爲了提升運行效率,就必須下降範式標準,適當保留冗餘數據。具體作法是: 在概念數據模型設計時遵照第三範式,下降範式標準的工做放到物理數據模型設計時考慮。下降範式就是增長字段,容許冗餘 。
u Sql語句自己的優化
問題是: 如何從一個大項目中,迅速的定位執行速度慢的語句. (定位慢查詢)
① 首先咱們瞭解mysql數據庫的一些運行狀態如何查詢(好比想知道當前mysql運行的時間/一共執行了多少次select/update/delete.. / 當前鏈接)
show status
經常使用的:
show status like ‘uptime’ ;
show stauts like ‘com_select’ show stauts like ‘com_insert’ ...類推 update delete
show [session|global] status like .... 若是你不寫 [session|global] 默認是session 會話,指取出當前窗口的執行,若是你想看全部(從mysql 啓動到如今,則應該 global)
show status like ‘connections’;
//顯示慢查詢次數
show status like ‘slow_queries’;
② 如何去定位慢查詢
構建一個大表(400 萬)-> 存儲過程構建
默認狀況下,mysql認爲10秒纔是一個慢查詢.
l 修改mysql的慢查詢.
show variables like ‘long_query_time’ ; //能夠顯示當前慢查詢時間
set long_query_time=1 ;//能夠修改慢查詢時間
構建大表->大表中記錄有要求, 記錄是不一樣纔有用,不然測試效果和真實的相差大.
建立:
CREATE TABLE dept( /*部門表*/
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*編號*/
dname VARCHAR(20) NOT NULL DEFAULT "", /*名稱*/
loc VARCHAR(13) NOT NULL DEFAULT "" /*地點*/
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
CREATE TABLE emp
(empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*編號*/
ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/
job VARCHAR(9) NOT NULL DEFAULT "",/*工做*/
mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上級編號*/
hiredate DATE NOT NULL,/*入職時間*/
sal DECIMAL(7,2) NOT NULL,/*薪水*/
comm DECIMAL(7,2) NOT NULL,/*紅利*/
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部門編號*/
)ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
CREATE TABLE salgrade
(
grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
losal DECIMAL(17,2) NOT NULL,
hisal DECIMAL(17,2) NOT NULL
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
測試數據
INSERT INTO salgrade VALUES (1,700,1200);
INSERT INTO salgrade VALUES (2,1201,1400);
INSERT INTO salgrade VALUES (3,1401,2000);
INSERT INTO salgrade VALUES (4,2001,3000);
INSERT INTO salgrade VALUES (5,3001,9999);
爲了存儲過程可以正常執行,咱們須要把命令執行結束符修改
delimiter $$
create function rand_string(n INT)
returns varchar(255) #該函數會返回一個字符串
begin
#chars_str定義一個變量 chars_str,類型是 varchar(100),默認值'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
declare chars_str varchar(100) default
'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
declare return_str varchar(255) default '';
declare i int default 0;
while i < n do
set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));
set i = i + 1;
end while;
return return_str;
end $$
若是但願在程序中使用,是Ok!
建立一個存儲過程
create procedure insert_emp(in start int(10),in max_num int(10))
begin
declare i int default 0;
#set autocommit =0 把autocommit設置成0
set autocommit = 0;
repeat
set i = i + 1;
insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());
until i = max_num
end repeat;
commit;
end $$
#調用剛剛寫好的函數, 1800000條記錄,從100001號開始
call insert_emp(100001,4000000);
③ 這時咱們若是出現一條語句執行時間超過1秒中,就會統計到.
④ 若是把慢查詢的sql記錄到咱們的一個日誌中
在默認狀況下,咱們的mysql不會記錄慢查詢,須要在啓動mysql時候,指定記錄慢查詢才能夠
bin\mysqld.exe - -safe-mode - -slow-query-log [mysql5.5 能夠在my.ini指定]
bin\mysqld.exe –log-slow-queries=d:/abc.log [低版本mysql5.0能夠在my.ini指定]
先關閉mysql,再啓動, 若是啓用了慢查詢日誌,默認把這個文件放在
my.ini 文件中記錄的位置
#Path to the database root
datadir="C:/Documents and Settings/All Users/Application Data/MySQL/MySQL Server 5.5/Data/"
⑤ 測試,能夠看到在日誌中就記錄下咱們的mysql慢sql語句.
優化問題.
經過 explain 語句能夠分析,mysql如何執行你的sql語句, 這個工具的使用放一下,一會說.
添加索引 【小建議: 】
u 四種索引(主鍵索引/惟一索引/全文索引/普通索引)
添加
1.1主鍵索引添加
當一張表,把某個列設爲主鍵的時候,則該列就是主鍵索引
create table aaa
(id int unsigned primary key auto_increment ,
name varchar(32) not null defaul ‘’);
這是id 列就是主鍵索引.
若是你建立表時,沒有指定主鍵索引,也能夠在建立表後,在添加, 指令:
alter table 表名 add primary key (列名);
舉例:
create table bbb (id int , name varchar(32) not null default ‘’);
alter table bbb add primary key (id);
1.2普通索引
通常來講,普通索引的建立,是先建立表,而後在建立普通索引
好比:
create table ccc(
id int unsigned,
name varchar(32)
)
create index 索引名 on 表 (列1,列名2);
1.3建立全文索引
全文索引,主要是針對對文件,文本的檢索, 好比文章, 全文索引針對MyISAM有用.
建立 :
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT (title,body)
)engine=myisam charset utf8;
INSERT INTO articles (title,body) VALUES
('MySQL Tutorial','DBMS stands for DataBase ...'),
('How To Use MySQL Well','After you went through a ...'),
('Optimizing MySQL','In this tutorial we will show ...'),
('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
('MySQL vs. YourSQL','In the following database comparison ...'),
('MySQL Security','When configured properly, MySQL ...');
如何使用全文索引:
錯誤用法:
select * from articles where body like ‘%mysql%’; 【不會使用到全文索引】
證實:
explain select * from articles where body like ‘%mysql%’
正確的用法是:
select * from articles where match(title,body) against(‘database’); 【能夠】
說明:
在mysql中fulltext 索引只針對 myisam生效
mysql本身提供的fulltext針對英文生效->sphinx (coreseek) 技術處理中文
使用方法是 match(字段名..) against(‘關鍵字’)
全文索引一個 叫 中止詞, 由於在一個文本中,建立索引是一個無窮大的數,所以,對一些經常使用詞和字符,就不會建立,這些詞,稱爲中止詞.
1.4惟一索引
①當表的某列被指定爲unique約束時,這列就是一個惟一索引
create table ddd(id int primary key auto_increment , name varchar(32) unique);
這時, name 列就是一個惟一索引.
unique字段能夠爲NULL,並能夠有多NULL, 可是若是是具體內容,則不能重複.
主鍵字段,不能爲NULL,也不能重複.
②在建立表後,再去建立惟一索引
create table eee(id int primary key auto_increment, name varchar(32));
create unique index 索引名 on 表名 (列表..);
查詢索引
desc 表名 【該方法的缺點是: 不可以顯示索引名.】
show index(es) from 表名
show keys from 表名
刪除
alter table 表名 drop index 索引名;
若是刪除主鍵索引。
alter table 表名 drop primary key [這裏有一個小問題]
修改
先刪除,再從新建立.
u 索引使用的注意事項
索引的代價:
佔用磁盤空間
對dml操做有影響,變慢
u 在哪些列上適合添加索引?
總結: 知足如下條件的字段,才應該建立索引.
a: 確定在where條常用 b: 該字段的內容不是惟一的幾個值(sex) c: 字段內容不是頻繁變化.
u 使用索引的注意事項
把dept表中,我增長几個部門:
alter table dept add index my_ind (dname,loc); // dname 左邊的列,loc就是右邊的列
說明,若是咱們的表中有複合索引(索引做用在多列上), 此時咱們注意:
1, 對於建立的多列索引,只要查詢條件使用了最左邊的列,索引通常就會被使用。
explain select * from dept where loc='aaa'\G
就不會使用到索引
2,對於使用like的查詢,查詢若是是 ‘%aaa’ 不會使用到索引
‘aaa%’ 會使用到索引。
好比: explain select * from dept where dname like '%aaa'\G
不能使用索引,即,在like查詢時,關鍵的 ‘關鍵字’ , 最前面,不能使用 % 或者 _這樣的字符., 若是必定要前面有變化的值,則考慮使用 全文索引->sphinx.
若是條件中有or,即便其中有條件帶索引也不會使用。換言之,就是要求使用的全部字段,都必須創建索引, 咱們建議你們儘可能避免使用or 關鍵字
select * from dept where dname=’xxx’ or loc=’xx’ or deptno=45
若是列類型是字符串,那必定要在條件中將數據使用引號引用起來。不然不使用索引。(添加時,字符串必須’’), 也就是,若是列是字符串類型,就必定要用 ‘’ 把他包括起來.
若是mysql估計使用全表掃描要比使用索引快,則不使用索引。
explain 能夠幫助咱們在不真正執行某個sql語句時,就執行mysql怎樣執行,這樣利用咱們去分析sql指令.
u 如何查看索引使用的狀況:
show status like ‘Handler_read%’;
你們能夠注意:handler_read_key:這個值越高越好,越高表示使用索引查詢到的次數。
handler_read_rnd_next:這個值越高,說明查詢低效。
u sql語句的小技巧
在使用group by 分組查詢是,默認分組後,還會排序,可能會下降速度.
好比:
在group by 後面增長 order by null 就能夠防止排序.
有些狀況下,可使用鏈接來替代子查詢。由於使用join,MySQL不須要在內存中建立臨時表。
select * from dept, emp where dept.deptno=emp.deptno; [簡單處理方式]
select * from dept left join emp on dept.deptno=emp.deptno; [左外鏈接,更ok!]
u 如何選擇mysql的存儲引擎
在開發中,咱們常用的存儲引擎 myisam / innodb/ memory
myisam 存儲: 若是表對事務要求不高,同時是以查詢和添加爲主的,咱們考慮使用myisam存儲引擎. ,好比 bbs 中的 發帖表,回覆表.
INNODB 存儲: 對事務要求高,保存的數據都是重要數據,咱們建議使用INNODB,好比訂單表,帳號表.
問 MyISAM 和 INNODB的區別
1. 事務安全
2. 查詢和添加速度
3. 支持全文索引
4. 鎖機制
5. 外鍵 MyISAM 不支持外鍵, INNODB支持外鍵. (在PHP開發中,一般不設置外鍵,一般是在程序中保證數據的一致)
Memory 存儲,好比咱們數據變化頻繁,不須要入庫,同時又頻繁的查詢和修改,咱們考慮使用memory, 速度極快.
u 若是你的數據庫的存儲引擎是myisam,請必定記住要定時進行碎片整理
舉例說明:
create table test100(id int unsigned ,name varchar(32))engine=myisam;
insert into test100 values(1,’aaaaa’);
insert into test100 values(2,’bbbb’);
insert into test100 values(3,’ccccc’);
咱們應該定義對myisam進行整理
optimize table test100;
mysql_query(「optimize tables $表名」);
本文來自:Linux教程網