1. 程式人生 > >mysql 中prepare statement(預處理)

mysql 中prepare statement(預處理)

今天前同事問了一個sql語法優化問題,後來查資料的過程中,發現了一個prepare statement 這玩意。使用並測試了下效能,感覺未來能用上。記錄下。

當時我在解決一個大表,分頁問題。目前的分頁sql一般有這幾種(原文):

--方法1: 直接使用資料庫提供的SQL語句

---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N
---適應場景: 適用於資料量較少的情況(元組百/千級)
---原因/缺點: 全表掃描,速度會很慢。

---方法2: 基於索引再排序
---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 WHERE id_pk > (pageNum*10) ORDER BY id_pk ASC LIMIT M
---適應場景: 適用於資料量多的情況(元組數上萬). 最好ORDER BY後的列物件是主鍵或唯一所以,使得ORDERBY操作能利用索引被消除但結果集是穩定的(穩定的含義,參見方法1)
---原因: 索引掃描,速度會很快. 但MySQL的排序操作,只有ASC沒有DESC(DESC是假的,未來會做真正的DESC,期待...).

---方法3: 基於索引使用prepare(第一個問號表示pageNum,第二個?表示每頁元組數)
---語句樣式: MySQL中,可用如下方法: PREPARE stmt_name FROM SELECT * FROM 表名稱 WHERE id_pk > (?* ?) ORDER BY id_pk ASC LIMIT M
---適應場景: 大資料量
---原因: 索引掃描,速度會很快. prepare語句又比一般的查詢語句快一點。

那麼為啥prepare會快一點呢?先不急,我們先了解下,sql執行的過程,mysql伺服器都做了哪些事?

SQL執行過程包括以下階段 詞法分析->語法分析->語義分析->執行計劃優化->執行

。詞法分析->語法分析這兩個階段我們稱之為硬解析。

詞法分析識別sql中每個詞,語法分析解析SQL語句是否符合sql語法,並得到一棵語法樹(Lex)。對於只是引數不同,其他均相同的sql,它們執行時間不同但硬解析的時間是相同的。

Prepare的出現就是為了優化硬解析的問題。

本來執行兩條sql查詢:

select * from a where id>1
select * from a where id>10

按執行順序:詞法分析->語法分析->語義分析->執行計劃優化->執行 。執行兩遍。

如果使用Prepare,節約硬解析時間。那麼同樣執行上面的sql

prepare first_ prepare from 'select * from a where id>(?)';
其中?可以傳入不同引數

按執行順序:第一次:詞法分析->語法分析->語義分析->執行計劃優化->執行 。

 第二次:語義分析->執行計劃優化->執行

節約了一次硬解析時間。

Prepare在execute階段可以節省硬解析的時間。如果sql只執行一次,且以prepare的方式執行,那麼sql執行需兩次與伺服器互動(Prepare和execute), 而以普通(非prepare)方式,只需要一次互動。這樣使用prepare帶來額外的網路開銷,可能得不償失。我們再來看同一sql執行多次的情況,比如以prepare方式執行10次,那麼只需要一次硬解析。這時候  額外的網路開銷就顯得微乎其微了。因此prepare適用於頻繁執行的SQL。

除了適用月需要頻繁執行的SQL,還有一點也是需要注意的。

sql越簡單硬解析的時間就越少,prepare的提升就越少。

綜上,prepare 語法適用頻繁執行且複雜的SQL。

參考文章1