Prepare的好處
Prepare SQL產生的原因。首先從mysql服務器執行sql的過程開始講起,SQL執行過程包括以下階段 詞法分析->語法分析->語義分析->執行計劃優化->執行。詞法分析->語法分析這兩個階段我們稱之為硬解析。詞法分析識別sql中每個詞,語法分析解析SQL語句是否符合sql語法,并得到一棵語法樹(Lex)。對于只是參數不同,其他均相同的sql,它們執行時間不同但硬解析的時間是相同的。而同一SQL隨著查詢數據的變化,多次查詢執行時間可能不同,但硬解析的時間是不變的。對于sql執行時間較短,sql硬解析的時間占總執行時間的比率越高。而對于淘寶應用的絕大多數事務型SQL,查詢都會走索引,執行時間都比較短。因此淘寶應用db sql硬解析占的比重較大。
Prepare的出現就是為了優化硬解析的問題。Prepare在服務器端的執行過程如下
1) Prepare 接收客戶端帶”?”的sql, 硬解析得到語法樹(stmt->Lex), 緩存在線程所在的preparestatement cache中。此cache是一個HASH MAP. Key為stmt->id. 然后返回客戶端stmt->id等信息。
2) Execute 接收客戶端stmt->id和參數等信息。注意這里客戶端不需要再發sql過來。服務器根據stmt->id在preparestatement cache中查找得到硬解析后的stmt, 并設置參數,就可以繼續后面的優化和執行了。
Prepare在execute階段可以節省硬解析的時間。如果sql只執行一次,且以prepare的方式執行,那么sql執行需兩次與服務器交互(Prepare和execute), 而以普通(非prepare)方式,只需要一次交互。這樣使用prepare帶來額外的網絡開銷,可能得不償失。我們再來看同一sql執行多次的情況,比如以prepare方式執行10次,那么只需要一次硬解析。這時候 額外的網絡開銷就顯得微乎其微了。因此prepare適用于頻繁執行的SQL。
Prepare的另一個作用是防止sql注入,不過這個是在客戶端jdbc通過轉義實現的,跟服務器沒有關系。
硬解析的比重
壓測時通過perf 得到的結果,硬解析相關的函數比重都比較靠前(MYSQLparse 4.93%, lex_one_token 1.79%, lex_start 1.12%)總共接近8%。因此,服務器使用prepare是可以帶來較多的性能提升的。
jdbc與prepare
jdbc服務器端的參數:
useServerPrepStmts:默認為false. 是否使用服務器prepare開關
jdbc客戶端參數:
cachePrepStmts:默認false.是否緩存prepareStatement對象。每個連接都有一個緩存,是以sql為唯一標識的LRU cache. 同一連接下,不同stmt可以不用重新創建prepareStatement對象。
新聞熱點
疑難解答