一、MySQL數據庫優化技術mysql
1)表的設計合理化(符合3NF)
sql
2)添加適當的索引(index):普通索引、主鍵索引、惟一索引、全文索引、複合索引
shell
3)分表技術(水平分割、垂直分割)
數據庫
4)讀寫分離(讀:select,寫:insert、update、delete)
編程
5)存儲過程、觸發器(模塊化編程,提早編譯sql語句,提交執行速度)
緩存
6)對mysql配置文件進行優化(最大併發數、緩存大小)
服務器
7)mysql服務器升級
session
8)定時清理不須要的數據,定時進行碎片整理(MyISAM)
併發
二、3NF(範式)模塊化
1)1NF:列具備原子性,不可分割,數據庫是關係型數據庫就符合1NF
2)2NF:表的行記錄是惟一的,符合2NF,設置主鍵
3)3NF:表中沒有冗餘數據
三、反3NF:沒有冗餘的數據庫未必是最好的數據庫,有時爲了提升運行效率,就必須下降範式標準,適當保留冗餘數據。具體作法是: 在概念數據模型設計時遵照第三範式,下降範式標準的工做放到物理數據模型設計時考慮。下降範式就是增長字段,容許冗餘。
四、Sql語句優化
1)定位慢查詢
a、獲取mysql的一些運行狀態(如:當前鏈接數、select次數、update次數、insert次數、delete次數等)
show [global|session] status like '' 查詢相關運行狀態
netstat –anb 查詢端口
SHOW STATUS; #顯示參數信息列表 SHOW STATUS LIKE '%quer%'; #模糊匹配 SHOW STATUS LIKE 'uptime'; #顯示MySQL運行時間 SHOW GLOBAL STATUS LIKE 'com_select'; #顯示select次數 SHOW GLOBAL STATUS LIKE 'com_update'; #顯示update次數 SHOW GLOBAL STATUS LIKE 'com_insert'; #顯示insert次數 SHOW GLOBAL STATUS LIKE 'com_delete'; #顯示delete次數 SHOW STATUS LIKE 'connections'; #顯示當前併發鏈接數 SHOW GLOBAL STATUS LIKE 'slow_queries'; #查詢慢查詢次數
b、開啓慢查詢日誌:
SHOW VARIABLES LIKE 'long_query_time'; #慢查詢記錄最短期 SET long_query_time = 1; #設置慢查詢時間 SET GLOBAL slow_query_log = ON; #開啓慢查詢日誌 SHOW VARIABLES LIKE 'slow_query_log'; #顯示慢查詢日誌狀態 SHOW VARIABLES LIKE 'slow_query_log_file'; #顯示慢查詢日誌文件路徑
日誌記錄:
# Time: 151007 12:01:37 # User@Host: root[root] @ localhost [127.0.0.1] Id: 5 # Query_time: 15.434343 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 13000000 use hsp_mysql; SET timestamp=1444190497; select * from emp where empno = 12321312312 LIMIT 0, 1000;
2)添加索引
建立索引
主鍵索引:當設置表的主鍵時,該主鍵字段即爲主鍵索引字段
1)建立表的時候添加:primary key
CREATE TABLE t_aaa( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, aname VARCHAR(32) NOT NULL, isvalid TINYINT DEFAULT 1 );
2)語句添加:alter table 表名 add primary key(列名)
CREATE TABLE t_bbb( id INT UNSIGNED, bname VARCHAR(32) NOT NULL, isvalid TINYINT DEFAULT 1 ); ALTER TABLE t_bbb ADD PRIMARY KEY(id); ALTER TABLE t_bbb MODIFY id INT UNSIGNED AUTO_INCREMENT; DESC t_bbb; SHOW INDEXES FROM t_bbb; SHOW KEYS FROM t_bbb;
普通索引:建立表以後在列上添加索引
create [fulltext|unique] index 索引名稱 on 表名(列名1, 列名2....)
CREATE TABLE t_ccc( id INT UNSIGNED, cname VARCHAR(32) NOT NULL, isvalid TINYINT DEFAULT 1 ); CREATE INDEX i_ccc_id ON t_ccc(id); DESC t_ccc; SHOW INDEXES FROM t_ccc; CREATE INDEX i_emp_no ON emp(empno); SHOW INDEXES FROM emp;
全文索引:針對文件的檢索,好比文章,全文索引只針對MyISAM有效
create fulltext index 索引名 on 表名(列名, 列名....)
CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, title VARCHAR(32) NOT NULL, body TEXT, FULLTEXT KEY full_text_articles (title, body) #建立全文索引 ) ENGINE=MYISAM DEFAULT 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 ...'); CREATE FULLTEXT INDEX ft_body ON articles(body);
mysql> SELECT * FROM articles WHERE MATCH(title, body) AGAINST ('DataBase'); #全文搜索 +----+-------------------+------------------------------------------+ | id | title | body | +----+-------------------+------------------------------------------+ | 5 | MySQL vs. YourSQL | In the following database comparison ... | | 1 | MySQL Tutorial | DBMS stands for DataBase ... | +----+-------------------+------------------------------------------+ 2 rows in set (0.00 sec) #被查詢出來的機率 mysql> select match(title, body) against('DataBase') from articles; +----------------------------------------+ | match(title, body) against('DataBase') | +----------------------------------------+ | 0.6554583311080933 | | 0 | | 0 | | 0 | | 0.6626645922660828 | | 0 | +----------------------------------------+ 6 rows in set (0.00 sec)
注意:一、全文索引只有MyISAM有效;二、只支持英文;三、使用match...against('關鍵字');四、全文索引中有一個詞叫中止詞,若是全文索引每個單詞及其組合都要建立索引,則很是龐大,因此對於一些經常使用詞和字符,全文索引不會建立,而這些詞稱爲中止詞
惟一索引:列惟一
惟一索引值能夠爲null,而且能夠爲多個null,其餘值不能重複,主鍵索引不能爲null
1)若是建立表時字段添加unique約束時,則自動爲惟一索引
CREATE TABLE t_ddd ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, task_id SMALLINT NOT NULL, user_id SMALLINT NOT NULL, orderno VARCHAR(32) UNIQUE -- 建立惟一索引 ); SHOW INDEXES FROM t_ddd;
2)建立表後在建立惟一索引:create unique index 索引名 on 表名(列名, 列名....)
CREATE UNIQUE INDEX i_ddd_userid ON t_ddd(user_id, task_id); INSERT INTO t_ddd(task_id, user_id, orderno) VALUES (1, 2, NULL); INSERT INTO t_ddd(task_id, user_id, orderno) VALUES (2, 2, NULL); INSERT INTO t_ddd(task_id, user_id, orderno) VALUES (2, 1, ''); mysql> select * from t_ddd; +----+---------+---------+---------+ | id | task_id | user_id | orderno | +----+---------+---------+---------+ | 1 | 1 | 2 | NULL | | 3 | 2 | 2 | NULL | | 4 | 2 | 1 | | +----+---------+---------+---------+ 3 rows in set (0.00 sec)
查詢索引
1)desc 表名:沒法獲取索引名稱
mysql> desc t_aaa; +---------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | aname | varchar(32) | NO | | NULL | | | isvalid | tinyint(4) | YES | | 1 | | +---------+------------------+------+-----+---------+----------------+ 3 rows in set (0.03 sec)
2)show index(es) from 表名
建立的索引以二叉樹的形式保存索引id,對應的存儲物理地址
mysql> SHOW INDEXES FROM t_ccc\G; *************************** 1. row *************************** Table: t_ccc Non_unique: 1 Key_name: i_ccc_id Seq_in_index: 1 Column_name: id Collation: A Cardinality: 0 Sub_part: NULL Packed: NULL Null: YES Index_type: BTREE Comment: Index_comment: 1 row in set (0.00 sec)
3)show keys from 表名
刪除索引
alter table 表名 drop index 索引名
drop index 索引名 on table 表名
刪除主鍵:alter table 表名 drop primary key
DROP INDEX i_ddd_userid ON t_ddd -- 刪除索引; ALTER TABLE t_ddd DROP INDEX orderno; -- 刪除索引 ALTER TABLE t_ddd MODIFY id INT UNSIGNED; alert TABLE t_ddd ADD PRIMARY KEY; ALTER TABLE t_ddd DROP PRIMARY KEY; -- 刪除主鍵,必須去掉自增
修改索引
修改索引先刪除再建立
索引原理分析
索引代價:
1)建立的索引文件佔用磁盤空間
2)對DML操做語句有影響,影響其性能
何時使用索引:
比較頻繁的查詢的列(where條件後)適合爲該列建立索引
惟一性太差的字段列不適合建立索引
更新頻繁的字段列不適合建立索引
使用索引注意事項:
對於建立的多列複合索引,只有最左邊的列被使用的狀況下,這個複合索引纔會被使用,若是最左邊列沒有被使用,則索引無效
ALTER TABLE t_ddd ADD PRIMARY KEY(id); CREATE UNIQUE INDEX i_unique ON t_ddd(task_id, user_id); -- 建立複合索引,task_id爲最左邊的列 mysql> EXPLAIN SELECT * FROM t_ddd WHERE task_id = 1\G -- 條件語句包含最task_id *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: ref possible_keys: i_unique key: i_unique key_len: 2 ref: const rows: 1 Extra: NULL 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM t_ddd WHERE user_id = 1 AND task_id = 2\G -- 條件語句包含最task_id *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: const possible_keys: i_unique key: i_unique key_len: 4 ref: const,const rows: 1 Extra: NULL 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM t_ddd WHERE user_id = 1\G -- 不包含task_id *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 3 Extra: Using where 1 row in set (0.00 sec)
使用like模糊匹配,若是規則爲'%'或者'_'開始,則不會使用索引
mysql> explain select * from t_ddd where orderno like '%aaa'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 3 Extra: Using where 1 row in set (0.00 sec) mysql> explain select * from t_ddd where orderno like 'aa%_a'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: range possible_keys: t_orderno key: t_orderno key_len: 35 ref: NULL rows: 1 Extra: Using index condition 1 row in set (0.00 sec)
若是where中帶or,則全部的條件字段都必須建立索引,不然只要有一個沒有建立索引,則索引都會無效
若是列類型是字符串,則必定要用單引號引發來,不然索引失效
mysql> explain select * from t_ddd where orderno = 12345\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: ALL possible_keys: t_orderno key: NULL key_len: NULL ref: NULL rows: 3 Extra: Using where 1 row in set (0.00 sec) mysql> explain select * from t_ddd where orderno = '12345'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: const possible_keys: t_orderno key: t_orderno key_len: 35 ref: const rows: 1 Extra: NULL 1 row in set (0.00 sec)
若是mysql全表掃描比索引快,則會不實用索引
查看索引使用狀況:show status like 'Handler_read%'
Handler_read_key:越高越好,越高表示索引查詢的次數越多
Handler_read_rnd_next:越低越好,越高查詢低效
mysql> show status like 'Handler_read%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | Handler_read_first | 0 | | Handler_read_key | 5 | | Handler_read_last | 0 | | Handler_read_next | 0 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 8 | +-----------------------+-------+ 7 rows in set (0.00 sec)
3)explain分析:能夠幫助咱們在不真正執行某個sql語句時,就執行mysql怎樣執行,這樣利用咱們去分析sql指令
4)優化策略
一、在使用group by 分組查詢是,默認分組後,還會排序,可能會下降速度,在group by 後面增長 order by null 就能夠防止排序
mysql> explain SELECT user_id from t_ddd group by user_id\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: index possible_keys: i_unique key: i_unique key_len: 4 ref: NULL rows: 3 Extra: Using index; Using temporary; Using filesort 1 row in set (0.00 sec) mysql> explain SELECT user_id from t_ddd group by user_id order by null\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_ddd type: index possible_keys: i_unique key: i_unique key_len: 4 ref: NULL rows: 3 Extra: Using index; Using temporary 1 row in set (0.00 sec)
二、有些狀況下,可使用鏈接來替代子查詢。由於使用join,MySQL不須要在內存中建立臨時表
select * from dept, emp where dept.deptno=emp.deptno; -- 簡單處理方式 select * from dept left join emp on dept.deptno=emp.deptno; -- 左外鏈接,更ok!
五、MySQL存儲引擎
MyISAM:若是對錶的事務要求不高,以查詢和增長爲主,考慮使用MyIASM
INNODB:對事務要求高,保存重要的數據,建議使用INNODB,好比訂單表、新手任務完成記錄表
Memory:存儲在內存中,並不實際存儲文件中,當重啓mysql時,數據清除,適用於數據變化頻繁,不須要入庫的數據,好比用戶狀態表,速度極快,相似於內存緩存
MyISAM與INNODB區別:
MyISAM不支持事務,INNODB支持事務
MyISAM支持全文索引,INNODB不支持全文索引
MyISAM添加和查詢速度要比INNODB快
MyISAM是表級鎖,INNODB是行級鎖
若是數據庫表使用MyISAM存儲引擎,必定要記得定時清理碎片:optimize table 表名
#建立MyISAM引擎數據庫表 CREATE TABLE t_eee ( id INT PRIMARY KEY, NAME VARCHAR(32) NOT NULL ) ENGINE=MYISAM; #建立INNODB引擎數據庫表 CREATE TABLE t_fff ( id INT PRIMARY KEY, NAME VARCHAR(32) NOT NULL ) ENGINE=INNODB; #建立Memory引擎數據庫表 CREATE TABLE t_fff ( id INT PRIMARY KEY, NAME VARCHAR(32) NOT NULL ) ENGINE=MEMORY; INSERT INTO t_fff VALUES (1, 'AAA'); INSERT INTO t_fff VALUES(2, 'BBB'); DELETE FROM t_fff; OPTIMIZE TABLE t_fff; -- 碎片整理