慕課網視頻學習筆記
數據庫優化的目的
避免出現頁面訪問錯誤
- 由於數據連接timeout 產生頁面5xx錯誤
- 由於慢查詢造成頁面無法加載
- 由於阻塞造成數據無法提交
增加數據庫的穩定性
- 很多數據庫問題都是由於低效的查詢引起的
優化用戶體驗
- 流暢頁面的訪問速度
- 良好的網站功能體驗
數據庫優化的幾個方面:
1、SQL及索引
2、數據庫表結構
3、系統配置
4、硬件
示例數據庫的安裝:
示例數據庫下載地址:http://downloads.mysql.com/docs/sakila-db.zip
安裝教學地址:https://dev.mysql.com/doc/sakila/en/sakila-installation.html
注意:window下cmd安裝 \ 全部替換成 / 纔可以成功
SQL及索引優化
使用mysql慢查日誌對有效率問題的sql進行監控
#1、查看mysql是否開啓慢查詢日誌
show variables like 'slow_query_log';
#2、設置沒有索引的記錄到慢查詢日誌
set global log_queries_not_using_indexes=on;
#3、查看超過多長時間的sql進行記錄到慢查詢日誌
show variables like 'long_query_time';
#4、開啓慢查詢日誌
set global slow_query_log=on;
#5、設置超過多少秒以後的查詢插入慢查日誌中
set global long_query_time=1;
#6、查看日誌記錄位置
show variables like 'slow%';
#7、查看日誌(退出mysql環境)
tail -50 D:\newphpStudy\MySQL\data\BlueSummer-PC-slow.log;
慢查日誌分析工具:
pt-query-digest
安裝過程:
[root@localhost ~]# wget percona.com/get/pt-query-digest
[root@localhost ~]# chmod u+x pt-query-digest
[root@localhost ~]# mv /root/pt-query-digest /usr/bin/
輸出到文件:pt-query-digest slow-log > slow_log.report
輸出到數據庫表: pt-query-digest slow.log -review \
如何通過慢查日誌發現有問題的SQL:
1、查詢次數多且每次查詢佔用時間長的SQL(通常爲pt-query-digest分析的前幾個查詢)
2、IO大的SQL(注意pt-query-digest分析中的Rows examine項)
3、未命中索引的SQL(注意pt-query-digest分析中的Rows examine和Rows Send的對比)
使用explain查詢SQL的執行計劃:
explain select customer_id,first_name,last_name from customer;
explain返回各列的含義:
- table:顯示這一行的數據是關於哪張表的
- type:這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型爲const、eq_reg、ref、range、index和ALL
- possible_keys:顯示可能應用在這張表中的索引。如果爲空,沒有可能的索引。
- key:實際使用的索引。如果爲NULL,則沒有使用索引。
- key_len:使用的索引的長度。在不損失精確性的情況下,長度越短越好。
- ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數
- rows:MYSQL認爲必須檢查的用來返回請求數據的行數
- extra:using filesort或者using temporary
Using filesort:看到這個的時候,查詢就需要優化了。MYSQL需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行。
Using temporary:看到這個的時候,查詢需要優化了。這裏,MYSQL需要創建一個臨時表來存儲接口,這通常發生在對不同的列表進行ORDER BY上,而不是GROUP BY上。
count()和max()的優化
max()優化:建立覆蓋索引
優化前:
建立索引:
create index inx_paydate on payment(payment_date);
優化後:
count()優化:使用OR NULL
-- 在一條SQL中同時查出2006和2007年電影的數量-優化count()函數
SELECT COUNT(release_year='2006' OR NULL) AS '2006年電影數量',
COUNT(release_year='2007' OR NULL) AS '2007年電影數量'
FROM film;
子查詢的優化
通常情況下,需要把子查詢優化爲join查詢,但在優化時需要注意關聯鍵是否有一對多的關係,因爲此時要注意會有重複數據。(join查詢不需要內建臨時表)
distinct --去除重複值
group by 的優化
優化前:
SELECT actor.first_name,actor.last_name,COUNT(*)
FROM sakila.film_actor
INNER JOIN film_actor USING(actor_id)
GROUP BY film_actor.actor_id;
優化後:
SELECT actor.first_name,actor.last_name,c
FROM sakila.actor INNER JOIN(
SELECT actor_id,COUNT(*) AS cnt FROM sakila.film_actor GROUP BY
actor_id
)AS c USING(actor_id);
Limit查詢的優化:
limit常用於分頁處理,時常會伴隨order by從句使用,因此大多時候會使用Filesorts,這樣造成大量的IO問題。
SELECT film_id,description FROM sakila.film ORDER BY title LIMIT 50,5;
優化LImie查詢:
優化步驟1:使用有索引的列或主鍵進行order by操作
SELECT film_id, descripytion FROM sakila.film ORDER BY film_id LIMIT 50,5;
優化步驟2:記錄上次返回的主鍵,在下次查詢時使用主鍵過濾(避免了數據量大時掃描過多的記錄)
SELECT film_id, description FROM sakila.film WHERE film_id > 55 and film_id <= 60 ORDER BY film_id LIMIT 1,5;
-- 如果不是連續的,可以自己建一列保證其值順序遞增也可以。
*避免數據量大時掃描過多的記錄
使用主鍵或索引來order by是可以減少掃描列:
在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後通過保存在ROWID(相對於頁碼)快速找到表中對應的記錄。索引的建立時表中比較有指向性的字段,相對於目錄,比如說行政區域代碼,同一個地域的行政區域代碼都是相同的,那麼給這一列加上索引,避免讓它重複掃描,從而達到優化的目的。
如何選擇合適的列建立索引: