mysql的優化

1.使用命令 

show variables like 'slow_query_log';

查看到當前沒有開啓慢查詢

2.使用命令

show variables like '%log%';

也沒有開啓log_queries_not_using_indexs

3.set global log_queries_not_using_indexes=on;

4.show variables like 'long_query_time';

查看到long_query_time的值爲10,意思是慢查詢日誌中會記錄超過十秒的記錄;

默認情況下,MySQL是不會記錄超過一定執行時間的SQL語句的。要開啓這個功能,我們需要修改MySQL的配置文件,windows下修改my.ini,Linux下修改my.cnf文件,在[mysqld]最後增加如下命令:

複製代碼 代碼如下:

slow_query_log

long_query_time = 1

5.開啓慢查詢日誌

set global slow_query_log=on;

{

導入mysql官方提供的sakila數據庫:

將文件解壓,得到三個文件,

打開cmd:使用命令 mysql -uroot -p < "sakila-schema.sql所在的路徑"

使用命令 mysql -uroot -p < "sakila-data.sql所在的路徑"

}


6.mysql 慢查詢日誌分析工具

*mysqldumpslow

*pt-query-digest

7.如何通過慢查詢日誌發現有問題的SQL

* 查詢次數多且每次查詢所佔用的時間長的SQL

通常爲pt-query-digest分析的前幾個查詢

*IO大的SQL

注意pt-query-digest分析中的Rows exammine項

*未命中索引的SQL

注意pt-query-digest分析中的Rows examine和Rows Send的對比

8.使用explain查詢SQL的執行計劃

explain返回各列的含義

table:顯示這一行的數據是關於哪張表的

type:這是重要的列,顯示連接使用了何種類型。從最好到最差的連續類型爲const,eq_reg,ref,range,index和ALL(,沒有where從句,表掃描)。

possible_keys:顯示可能應用在這張表中的索引。如果爲空,沒有可能的索引

key:實際使用的索引。如果爲NULL,則沒有使用索引

key_len:使用的索引的長度。在不損失精確性的情況下,長度越短越好

ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數

rows:mysql認爲必須檢查的用來返回請求數據的行數

9.Max()的優化方法

*查詢最後支付時間----優化MAX()函數

explain select max(payment_date) from payment;

可以查看到:type:ALL是表掃描操作;沒有任何索引,rows非常大,IO效率非常低。

如何優化這個SQL:通常情況下建立索引:

create index idx_paydate on payment(payment_date);

這樣在次執行explain select max(payment_date) from payment;

可以看到Extra:select tables optimized away;可以通過索引進行操作,大大減少了IO操作

10.Count()的優化方法

*在一條SQL中同時查出2006年和2007年電影的數量----優化count()函數

錯誤方式:

SELECT COUNT(release_year='2006' OR release_year='2007') FROM film;

無法分開計算2006和2007年的電影數量

select count(*) FROM film WHERE release_year='2006' AND release_year='2007';

release_year不可能同時爲2006和2007,因此有邏輯錯誤

正確的方式:

SELECT COUNT(release_year='2006' OR NULL) AS '2006年電影數量',COUNT(release_year='2007' OR NULL) AS '2007年電影數量' FROM film;


{

現在說說count(*)和count(id)的區別:

新建一張表:create table t(id int);

插入數據:insert into t values (1),(2),(null);

當我們使用命令:select count(*),count(id) from t;

顯示出count(*)爲3,而count(id)爲2;

說明count(*)包含了null的,count(id)不包含值爲null的

}

11.子查詢的優化

*通常情況下,需要把子查詢優化爲join查詢,但在優化時要注意關聯鍵是否有一對多的關係,要注意重複數據。

*我們新建一張表t1

create table t1(tid int);

插入一條數據insert into t1 values(1);

進行子查詢:select * from t where t.id in (select * from t1.tid from t1);

返回t表id在t1表中的數據

*優化成join的形式:

select t.id from t join t1 on t.id=t1.tid;

這兩種形式返回的結果是一樣的

*需要注意的是:

如果在t1表中,添加一條數據:insert into t1 values(1);

然後在分別執行這兩種形式的查詢:

發現使用select * from t where t.id in (select * from t1.tid from t1);查詢出來的結果是一條數據。而select t.id from t join t1 on t.id=t1.tid;是兩條數據,說明有重複數據,我們可以使用distinct去重

select distinct t.id from t join t1 on t.id=t1.tid;這樣就返回一條記錄了

12.優化group by查詢

explain SELECT actor.first_name,actor.last_name,count(*) FROM sakila.film_actor INNER JOIN sakila.actor USING(actor_id) GROUP BY film_actor.actor_id;


{

using可用在join語句相同字段連接,起到和ON相同作用,inner join 和left join中都可以使用

示例:LEFT JOIN 正常寫法:

    SELECT t1.id,t2.name FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE ....

其實也可以這麼寫:

    SELECT t1.id,t2.name FROM t1 LEFT JOIN t2 USING(id) WHERE ....

}


上面的explain執行結果,可以看到extra爲Using temporary,Using filesort  用到了臨時表,文件排序的方式對錶進行了全表掃描.


我們應該避免這種方式。改寫如下:

Explain SELECT actor.first_name,actor.last_name,c.cnt  FROM sakila.actor INNER JOIN(SELECT actor_id,COUNT(*) AS cnt FROM sakila.film_actor GROUP BY actor_id) AS c USING(actor_id);


13.優化limit查詢

*limit常用於分頁處理,時常會伴隨order by從句使用,因此大多時候會使用Filesorts,這樣會造成大量的IO問題

SELECT film_id,description FROM sakila.film ORDER BY title LIMIT 50,5;

*這個語句進行explain操作,發現會進行全表掃描,並且有文件排序的方式

*優化方式:

步驟1.使用有索引的列或主鍵進行Order By操作

SELECT film_id,description FROM sakila.film ORDER BY film_id LIMIT 50,5

使用這種方式可以得到相同的結果,但是explain執行計劃卻完全不同,type=index,rows=55

這種方式並不是最優的,比如將limit 50,5改爲limit 500,5;rows=505,rows會隨着limit而改變,如果有上萬條數據,那麼響應速度回變慢

步驟2.記錄上次返回的主鍵,在下次查詢時使用主鍵過濾

SELECT film_id,description FROM sakila.film WHERE film_id>55 and film_id<=60 ORDER BY film_id LIMIT 1,5;

這種方式rows=5,並且不會隨着limit的增長而增長

14.索引優化

*在where從句,group by從句,order by 從句,on從句中出現的列

*索引字段越小越好

*離散度越大的列放到聯合索引的前面

SELECT * FROM payment WHERE staff_id=2 AND customer_id =584;

是index(staff_id,customer_id)好?還是index(customer_id,staff_id)好?

首先我們先看一下payment表的數據結構是什麼樣的

desc payment;

然後我們使用語句:select count(distinct customer_id),count(distinct staff_id) from payment;這樣我們可以看出他們的離散程度。他們的唯一值越多,說明他們的離散度越好,他們的可選擇性就越高。

這個查詢可以看出 customer_id=599,而staff_id=2;說明customer_id離散度更高一些,可選擇性更高,因此要建立聯合索引時就把customer_id放在最前面。

所以應該使用index(customer_id,staff_id)

15.如何選擇合適的列建立索引?

索引不是越多越好。

通常情況下建立索引可以優化我們的查詢效率,但是會降低我們的寫入效率,也就是說建立索引會增強查詢,會影響insert,update,delete這種寫入操作。但是往往不是這樣的,過多的索引不但會影響我們的寫入效率,同時也會影響查詢,這是由於數據庫進行查詢分析的時候,首先要選擇哪個索引進行查詢,如果索引越多,分析的過程就越慢,這樣就會影響查詢的效率。因此我們要維護和刪除索引。


*索引的維護及優化---重複及冗餘索引

重複索引是指相同的列以相同的順序建立同類型的索引,如下表primary key 和ID列上的索引就是重複索引(主鍵已經是一個唯一索引了):

create table test(id int not null primary key,name varchar(10) not null,title varchar(50) not null ,unique(id))engine=innodb;

冗餘索引是指多個索引的前綴列相同,或者是在聯合索引中包含了主鍵的索引,下面這個例子中key(name,id)就是一個冗餘索引。

create table test(id int null primary key,name varchar(50) not null,title varchar(50) not null,key(name,id))engine=innodb;

*查找重複及冗餘索引

SELECT a.TABLE_SCHEMA AS '數據庫名',a.table_name as '表名',a.index_name AS '索引1',b.INDEX_NAME AS '索引2',a.COLUMN_NAME AS '重複列名' FROM STATISTICS a JOIN STATISTICS b ON a.TABLE_SCHEMA=b.TABLE_SCHEMA AND a.TABLE_NAME=b.TABLE_NAME AND a.SEQ_IN_INDEX=b.SEQ_IN_INDEX AND a.COLUMN_NAME=b.COLUMN_NAME WHERE a.SEQ_IN_INDEX = 1 AND a.INDEX_NAME <> b.INDEX_NAME;

*工具:使用pt-duplicate-key-checker工具

*刪除不用的索引,目前mysql中只能使用慢查詢日誌配合pt-index-usage工具來進行索引使用情況的分析。

16.數據庫結構優化:

*選擇合適的數據類型

數據類型的選擇,重點在於"合適"二字,如何確定選擇的數據類型是否合適?

a)使用可以存下你的數據的最小的數據類型

b)使用簡單的數據類型。Int要比varchar類型在mysql處理上簡單

c)儘可能的時候not null定義字段

d)儘量少用text類型,非用不可是最好考慮分表

使用bigint來存儲ip地址,利用INET_ATON(),INET_NTOA()兩個函數來進行轉換

CREATE TABLE sessions(id INT AUTO_INCREMENT NOT NULL,ipaddress BIGINT,PRIMARY KEY(id));

INSERT INTO session(ipaddress) VALUES(INET_ATON('192.168.0.1'));

SELECT INET_NTOAA(ipaddress) FROM sessions;

表的範式化和反範式化

範式化是指數據庫設計的規範,目前說到範式化一般是指第三範式,也就是要求數據庫中不存在非關鍵字段對任意候選關鍵字段的傳遞函數依賴則符合第三範式

反範式化是指爲了查詢效率的考慮把原本符合第三範式的表適當的增加冗餘,已達到優化查詢效率的目的,反範式化是一種以空間來換取時間的操作。

表的垂直拆分

所謂的垂直拆分,就是把原來一個有很多列的表拆分成多個表,這解決了表的寬度問題。通常垂直拆分可以按以下原則進行:

a)把不常用的字段單獨存放到一個表中。

b)把大字段獨立存放到一個表中。

c)把經常一起使用的字段放到一起。

表的水平拆分

表的水平拆分是爲了解決單表的數據量過大的問題,水平拆分的表每一個表的結構都是完整一致的。

常用的水平拆分方法爲:

1.對id進行hash運算,如果要拆分成5個表則使用mod(id,5)取出0-4個值

2.針對不同的hashID把數據存到不同的表中。


挑戰:1.快分區表進行數據查詢2.統計及後臺報表操作

17.操作系統配置優化

數據庫是基於操作系統的,目前大多數Mysql都是安裝在Linux系統之上,所以對於操作系統的一些參數配置也會影響到Mysql的性能,下面就列出一些常用的系統配置

網絡方面的配置,要修改/etc/sysctl.conf

#增加tcp支持的隊列數

net.ipv4.tcp_max_syn_backlog = 65535

#減少斷開連接時,資源回收

net.ipv4.tcp_max_tw_buckets = 8000

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_fin_timeout = 10

#打開文件數的限制,可以使用ulimit -a查看目錄的各位限制,可以修改/etc/security/limits.conf文件,增加以下內容以修改打開文件數量的限制

*soft nofile 65535

*hard nofile 65535

除此之外最好在Mysql服務器上關閉iptable,selinux等防火牆軟件

18.mysql配置文件

Mysql可以通過啓動時指定配置文件參數和使用配置文件兩種方法進行配置,在大多數情況下配置文件位於/etc/my.cnf或是/etc/mysql/my.cnf,在windows系統配置文件可以是位於C:/windows/my.ini文件,Mysql查找配置文件的順序可以通過以下方法獲得

$/usr/sbin/mysqld --verbose --help|grep -A l 'Default option'

注意:如果存在多個位置存在配置文件,則後面的會覆蓋前面的


Mysql配置文件--常用參數說明

innodb_buffer_pool-size:非常重要的一個參數,用於配置Innodb的緩衝池,如果數據庫中個只有Innodb表,則推薦配置量爲總內存的75%.

innodb_buffer_pool_instances:Mysql5.5中新增加參數,可以控制緩衝池的個數,默認情況下只有一個緩衝池

Innodb_log_buffer_size:innodb log 緩衝的大小,由於日誌最長每秒鐘就會刷新所以一般不用太大

innodb_flush_log_at_trx_commit:關鍵參數,對innodb的IO效率影響很大。默認值爲1,可以取0,1,2三個值,一般建議設爲2,但如果數據安全性要求比較高則使用默認值1.

innodb_read_io_threads,innodb_write_io_threads:決定了Innodb讀寫的IO進程數,默認爲4

innodb_file_per_table:關鍵參數,控制Innodb每一個表使用獨立的表空間,默認爲off,也就是所有表都會建立在共享表空間中

innodb_stats_on_metadata:決定了Mysql在什麼情況下會刷新innodb表的統計信息

19.第三方工具:Percon Configuration Wizard

20.服務器硬件優化:

如何選擇CPU:是選擇單核更快的CPU還是選擇核數更多的cup?

1.MySQL有一些工作只能用到單核CPU

2.Mysql對CPU核數的支持並不是越多越快

mysql5.5使用的服務器不要超過32核

磁盤IO優化:

常用RAID級別介紹:

RAID0:也稱爲條帶,就是把多個磁盤鏈接成一個硬盤使用,這個級別的IO最好,缺點就是一個磁盤壞掉那麼所有數據就會丟失

RAID1:也稱爲鏡像,要求至少有兩個磁盤,每組磁盤存儲的數據相同,IO效果不如RAID0,安全性好

RAID5:也是把多個(最少3個)硬盤合併成一個邏輯盤使用,數據讀寫時會建立奇偶校驗信息,並且奇偶校驗信息和相對應的數據分別存儲於不同的磁盤上。當RAID5的一個磁盤數據發生損壞後,利用剩下的數據和相應的奇偶校驗信息去恢復被損壞的數據。

一般的OLTP型的數據庫使用RAID1+0:就是RAID1和RAID0的結合。同時具有兩個級別的優缺點。一般建議數據庫使用這個級別。

SNA和NAT是否合適數據庫:

1.常用於高可用解決方案

2.順序讀寫效率高,但是隨即讀寫不如人意

3.數據庫隨即讀寫比率很高。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章