目錄
2.使用EXPLAIN對慢查詢SQL或者對你剛寫的SQL來進行分析
本來不打算寫了的,但是不寫看了一天覺得第二天可能就忘記了,這一天算是白看了。後面學習知識點的話,不打算以找工作爲驅動點了,而是以寫博客爲驅動點了。
從四個大的方面來說
1.創建數據庫
2.mysql優化
3.分區分表
4.主從複製,讀寫分離
5.加緩存
一.創建數據庫
1.可以創建一些冗餘字段,儘可能的避免連表查詢。
2.對於一些固定的長度的字段或者經常要作爲查詢條件的字段可以使用定長來,例如電話號碼就可以使用char(11)來建立,因爲使用定長的好處在於數據庫存取更加快捷。
char和varchar的不同點
char存儲值是定長的,即使存儲的值沒有達到長度,它也會用空格填充,vachar不是定長的,長度會隨着存儲的字段的長度變化,一般都是存儲的字段加一,這個多出來的一個是記錄字段長度的。
3.儘量用not null,不要用null,因爲null也會佔用空間,需要一個額外字節作爲判斷是否爲NULL的標誌位,它會使索引、索引統計和值更加複雜,count(*)可以統計null的,但是count(phone)統計不到null。NOT IN子查詢在有NULL值的情況下返回結果中帶有NULL。
4.數據庫建立的時候要符合範式要求。第一範式:每個列是原子性的,不可以再分。第二範式:每個列對主鍵是完全依賴,不存在部分依賴。第三範式:列對主鍵不存在傳遞依賴,例如不能存在主鍵A,C依賴B,B依賴A這種情況。
5.建立合適的索引。
二.mysql優化
1.開啓慢日誌
先查詢慢日誌是否開啓
show variables like '%query%'
現實結果
slow_query_log對應的值是ON的話代表慢日誌開啓,OFF代表慢日誌是關閉的
slow_query_log_file就是記錄慢日誌的文件
long_query_time代表語句執行時間超過10秒就會被認定是慢查詢
如果慢查詢沒有開啓的話,可以執行下面這句話,並且將慢查詢時間定義在2秒
set global slow_query_log='ON';
set global long_query_time=2;
例如我在數據庫執行這樣一句話,就會超過十秒,就會被記錄到慢日誌裏面
select sleep(10),n.* from t_novel_main n;
在慢日誌裏面顯示:
Time Id Command Argument
# Time: 2019-11-30T14:20:52.603527Z
# User@Host: root[root] @ localhost [127.0.0.1] Id: 9
# Query_time: 10.002048 Lock_time: 0.000081 Rows_sent: 1 Rows_examined: 1
use test;
SET timestamp=1575123652;
select sleep(10),n.* from t_novel_main n;
當然還可以使用日誌分析工具mysqldumpslow對慢查詢進行分析,分析出出現最多的慢查詢SQL。
2.使用EXPLAIN對慢查詢SQL或者對你剛寫的SQL來進行分析
explain select * from tbl_user_no_part where id >= (select id from tbl_user_no_part limit 4000000 ,1) limit 20
解釋幾個比較重要的字段
id:表示查詢的順序,如果select_type不一樣,id越大越先執行
type:表示用到了什麼類型的索引:
const:表示在where條件中用到了主鍵或者唯一索引在, "主鍵" 或 "唯一" 索引的所有部分與常量值進行比較,只返回一條數據。
eq_ref:用於聯表查詢的情況,按聯表的主鍵或唯一鍵聯合查詢。
ref:表示查詢條件中用到了非唯一索引。
rang:表示查詢條件中用到了索引進行範圍查詢。
index:表示通過掃描整個索引文件就能查詢出結果,如果查詢出的字段就在建立了索引,但不帶where條件的話就是這樣的 (也就是說雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從硬盤讀取的)。
ALL:掃描整個表查詢出來的。
當type是index和ALL的時候就需要注意了,看SQL是否有優化的地方。
possible_keys:可能會被用到的索引。
key:實際用到的索引。
rows:掃描到的行數。
Extra:表示一些額外的信息。
Using index:表示用到了覆蓋索引。
Using where:表示用到了where條件過濾。
Using filesort:表示用到了外部排序,不是通過索引直接返回排序結果的排序。
通過explain我們就知道sql用到了什麼索引,以及掃描了多少行,這樣可以便於我們作出更好的調整。
這個是對explain更詳細的解讀:https://blog.csdn.net/why15732625998/article/details/80388236
3.下面這些操作能讓你的查詢更加快速。
(1) 不要用select * from ;
(2) 如果確定查詢出來的是一條數據的話,就應該在最後面加上limit 1;
(3)儘量用inner join 代替子查詢。
(4)or條件兩邊都是索引的話,所以才能生效,最好是能用union all代替。
(5)注意in 和 exist的使用,in的話先查詢子表,exist的話先查詢外表,所以當子查詢數據較多的時候用exist,當外查詢數據較多的時候用使用in,如果是not in 和not exist 的時候使用not exist ,not in 會使索引失。
(6)如果是分頁的話可以使用
select * from `t_channel_total_every` where id>=(select id from t_channel_total_every limit 500000,1) limit 100;
來代替select * from t_channel_total_every limit 500000,100;
但是上面的確定有提升,但是提升效果不大。如果下面id是連續的話,可以使用select * from t_channel_total_every where id>500000,100 來執行,但是由於有刪除的話,id不連續,這樣查詢也會有問題,在網上找了大半天都沒有找到一個能很好解決大數據分頁的答案的,都是抄來抄去,雖然我也是抄。
4.下面這些操作可能會讓索引失效。
(1).如果在where條件中索引存在類型強轉的,例如明明是字符串類型的,但是沒有加單引號,或者是整數類型的,但是加了單引號,這樣會使索引失效。
(2).使用聯合索引的時候注意最左前綴原則。
(3).使用like查詢的時候注意%不要放在最左邊。
(4).如果用or進行查詢的話,左右兩邊都要使用索引才能生效。
(5).在查詢條件中對查詢條件計算或者使用函數會使索引失效。
(6).在查詢條件上使用!= 或者<>會使索引失效。
(7).如果使用索引的查詢代價太大,會改成全表掃描。
三.分區分表
分區分表這個太有難度了,很難把控,要是使用不當很容易引起其他的問題。
分區有五種分區方式,這裏只介紹四種:rang,list,hash,key,需要注意的是不能使用非主鍵或者唯一索引進行分區,也就是分區字段裏面必須包含主鍵或者唯一索引。
rang分區:按某一個值的的範圍進行分區
partition by range (store_id) (
partition p0 values less than (10),
partition p1 values less than (20),
partition p2 values less than (30)
);
list分區:按值分區,比較適合對一些固定的離散值進行分區
partition by list(category)(
partition p0 values in (3,5),
partition p1 values in (1,10),
partition p2 values in (4,9),
partition p3 values in (2)
);
hash分區:對某列或者幾列進行hash計算,然後取模來分區
partition by hash (store_id) partitions 4;
key區分
PARTITION BY LINEAR Key(email) PARTITIONS 4;
KEY分區和HASH分區相似,但是KEY分區支持除text和BLOB之外的所有數據類型的分區,而HASH分區只支持數字分區,KEY分區不允許使用用戶自定義的表達式進行分區,KEY分區使用系統提供的HASH函數進行分區。當表中存在主鍵或者唯一鍵時,如果創建key分區時沒有指定字段系統默認會首選主鍵列作爲分區字列,如果不存在主鍵列會選擇非空唯一鍵列作爲分區列,注意唯一列作爲分區列唯一列不能爲null。
四.主從複製,讀寫分離。
五.使用緩存。