Mysql基礎課九 語句操作分析下

2021-10-04 08:59:18 字數 3655 閱讀 4898

mysql 客戶端對於查詢,有兩種策略,一種是,查一行處理一行,另一種是無論處理邏輯,會將查詢結果都快取在本地,通常建議,非大查詢的場景,都使用第二種,但大查詢場景,要考慮記憶體是否能快取太多;

大查詢,如果使用第一種,查一行處理一行,查詢結果首先寫入 net_buffer,net_buffer寫滿,就會呼叫網路介面傳送出去,所以大查詢,不會占用 mysql 服務端太多記憶體,如果客戶端處理慢,會導致查詢執行時間較長;通過 show processlist 命令,可以看到 state 的值一直處於 sending to client 狀態,就表示傳送阻塞在客戶端處理;

客戶端連線 mysql 時,可以新增 -a 引數,表示跳過快取表名到本地的功能,這就無法使用表名自動補全,但會加速連線;如果新增 -quick 引數,不僅跳過快取表名的操作,還使用查一行處理一行的策略,這種方式可以節省本地記憶體;

在 innodb 引擎層,因為 wal 技術,資料大量都是從記憶體中查詢返回的,並且記憶體滿了,會涉及乙個淘汰策略,lru,即淘汰最久未使用的資料,並且還有乙個改進,分成了 young 和 old,避免偶爾大查詢的冷資料,佔滿了記憶體,降低了記憶體的命中率;

select * from t1 straight_join t2 on (t1.a=t2.a),其中 t1 稱為 驅動表,錶行數 m,t2 稱為被驅動表,錶行數 n,如果 t2 表的 a 欄位有索引,mysql 就會使用****** nested-loop join 演算法來查詢資料,如果 t2 的 a 字段沒有索引,會使用 block nested-loop join 演算法查詢資料;

簡單巢狀連線,首先 對錶 t1 做全表掃瞄,對每一行資料取出 a 值,通過 t2 的索引樹,找到匹配記錄,這樣組成結果集,總的掃瞄行數是 2m,時間複雜度是 m + m2*log2n,通常小表作為驅動表,因為 m 越小,時間複雜度越低;

如果是連線條件,無法用到被驅動表的索引,會使用阻塞巢狀連線查詢,首先將驅動表資料,載入到記憶體中,然後將被驅動表資料每一行取到記憶體,判斷連線條件是否成立,這種方式,總的掃瞄行數是 m + n,在記憶體需要判斷 m * n 次,同樣這種方法,也需要小表作為驅動表,因為記憶體大小有限;

建議,大表 join 操作,如果無法用到被驅動表的索引,盡量不使用 join,可以通過 explain 的結果 extra 字段 判斷是否出現 block nested loop 來決定是否使用 join 操作;

join 操作,總是應該使用小表做驅動表,小表是指,連線的表按照各自的條件過濾,過濾完成之後,參與 join 的各個欄位的總資料量小的表;

對於被驅動表的連線欄位上沒有索引,導致查詢效率低,一種方式,可以直接建索引,另一種情況,是大表建索引浪費,且該 sql 比較低頻使用,這種情況可以使用臨時表;

select * from t1 join t2 on (t1.b=t2.b) where t2.b>=

1 and t2.b<=

2000

;// 使用臨時表,並且 engine 可以選擇 memory

create temporary table temp_t

(id int primary key, a int

, b int

,index

(b))engine=innodb;

insert into temp_t select * from t2 where b>=

1 and b<=

2000

; select * from t1 join temp_t on (t1.b=temp_t.b)

;

還有一種方式,在業務應用中,構建雜湊結構存放臨時表,使用雜湊查詢,效率高;

left join 左連線,表示在 join 的基礎上,左表中的資料,即使右表沒有滿足匹配條件的記錄,查詢結果中也會返回一行,並將右表中的各個字段值填成 null;

通常 left join 是用左邊作為驅動表,右邊作為被驅動表,根據右邊連線字段是否有索引,來選擇匹配演算法,但也不絕對,也可能經過優化器之後,left join 優化為 join;

// a 表作為驅動表

select * from a left join b on

(a.f1=b.f1) and (a.f2=b.f2)

;// 使用的是 b 表作為驅動表,因為 null 和 任何值(包括null)做等值或者不等值判斷都是 null,所以 left join 優化為了 join;

select * from a left join b on

(a.f1=b.f1) where (a.f2=b.f2)

;

join 語句中,匹配條件放在 where 子句和 on 子句中是沒有區別的,如果想要 left join 的語意,匹配條件要放在 on 裡面,不能放在 wherer 子句中,在示例中,第二個語句不會得到 a 表有,而 b 表沒有的資料;

臨時表是指,只能被建立它的 session 訪問,在 session 結束時,會自動刪除的表,建表語句是 create temporary table …,注意,臨時表不一定是記憶體表,也可以選擇不同的儲存引擎,臨時表可以和普通表重名,重名會優先操作臨時表;

臨時表,可以應用在 join 優化 和 分庫分表的跨庫查詢的使用場景中;

join 優化,是通過將被驅動表按條件過濾後的資料,插入到乙個臨時表,在臨時表關聯欄位上建立索引,這樣就可以用到簡單巢狀連線演算法;

分庫分表的跨庫查詢,因為無法在單庫上使用 join,group by,order by 等操作,所以有兩種解決方案,一種是,每個分庫取到資料後,在記憶體中進行計算,另一種是,每個分庫取到資料後,彙總到乙個臨時表中,在臨時表中完成操作;

在 binlog_format='row』的時候,臨時表的操作是不記錄到 binlog 中,省去了主備同步的一些麻煩;

mysql 在執行某些 sql 語句,如果無法在讀資料的過程中直接得到結果,需要使用額外記憶體來儲存中間結果,就會建立內部臨時表,如,union,group by,distinct 等語句;

union 操作,是取兩個子查結果的並集,並且重複的行只保留一行,union all 就不需要去重,因為 union 是無法在讀資料時直接去重,所以需要用到臨時表,而 union all 就不需要臨時表了;

group by 操作,如果分組字段有序,即建立了索引,就可以邊讀資料邊得到結果,不需要使用臨時表,如果分組字段無序,就需要用到臨時表,通過乙個欄位來累加計數,且需要排序,因為 group by 操作,預設是按照分組結果有序返回的,如果不需要有序,新增 order by null,可以提高查詢效率;

explain 命令,如果顯示 using temporary,就表示使用了臨時表,using filesort,就表示使用了排序;

memory 引擎,資料和索引是單獨存放,支援雜湊索引,每個索引值儲存資料的位置,innodb 引擎,資料是存放在主鍵索引的葉子節點,其他索引上儲存的是主鍵的值;所以 memory 引擎的資料是按照插入順序存放的,而 innodb 引擎的資料是有序存放的;

memory 引擎的表,稱為記憶體表,資料儲存在記憶體中,資料是陣列存放,每個字段固定長度存放,雜湊索引是無法用到範圍查詢的,需要全表掃瞄,不過記憶體表也支援建立 b-tree 索引;

記憶體表,不支援行鎖,只支援表鎖,所以其對併發訪問不太友好;另外記憶體表,在資料庫重啟後,資料會丟失,不太適合生產上作為普通資料表來使用,所以一般用作臨時表中,作為臨時記憶體表;

演算法基礎課一 複雜度分析

資料結構,是指一組資料的儲存結構,演算法,是指運算元據的一組方法 資料結構,是為演算法服務的,演算法,作用在特定的資料結構之上 資料結構和演算法,解決的是如何更省,更快地儲存和處理資料,而考量效率和資源消耗的方法,就是複雜度分析 假設每行 執行的時間都一樣,為 unit time,那麼下面 執行時間...

Mysql基礎課三 日誌

保證 如果客戶端收到事務成功的訊息,事務就一定持久化了 保證 如果客戶端收到事務失敗 比如主鍵衝突 回滾等 的訊息,事務就一定失敗了 保證 如果客戶端收到,執行異常的訊息,應該通過查詢當前狀態來繼續後續的邏輯,此時資料庫只需要保證內部一致 資料和日誌之間,主庫和備庫之間 通俗的來說,crash sa...

mysql基礎操作語句 Mysql基礎操作語句

比如乙個學生表student有三個欄位id,name,資料型別分別為int varchar varchar 增加資料 語法 insert into 表名 values val1,val2.例 insert into student values 1516,張三 男 部分字段插入 insert int...