簡述一下動態sql的執行原理 為什麼需要動態SQL

2021-10-11 02:06:31 字數 3240 閱讀 2231

在使用ef或者寫sql語句時,查詢條件往往是這樣一種非常常見的邏輯:如果客戶填了查詢資訊,則查詢該條件;如果客戶沒填,則返回所有資料。

我常常看到很多人解決這類問題時使用了錯誤的靜態sql的解決辦法,使得資料庫無法利用索引,導致效能急劇下降。

這次我將使用我的某客戶的真實資料來演示(已確認不涉及資訊保安 ),有乙個訂單表foodorder,結構如下:

我在idfoodmenuidorderuserid上建立了非聚集索引,在ordertime上建立了聚集索引。該錶有51652條資料。

在這種邏輯中如果想用一條sql語句搞定所有查詢,那麼**可能長這個樣子:

set statistics io on 

declare @userid int = 506

declare @menuid int = 3176

select * from foodorder where

(@userid is null or orderuserid = @userid) and

(@menuid is null or foodmenuid = @menuid)

這種寫法雖然方便,但基於其sql過於「複雜」,甚至還使用了is nullor,導致語句完全無法使用索引,執行set statistics io on後,顯示資訊如下:

(3 行受影響)

table 'foodorder'. scan count 1, logical reads 337, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.

顯示其進行了一次表掃瞄,並進行了337次邏輯讀,輸出資料只有3行。

然後看看實際的執行計畫:

如圖,顯示了乙個極其簡單的執行計畫,確實進行了一次表掃瞄,讀取了51652行資料,並且完全沒有走索引。

var sql = new stringbuilder();

if (userid != null)

if (menuid != null)

// ...

如果是ef,**可能是這個樣子:

iqueryablequery = db.foodorders;

if (userid != null)

if (menuid != null)

// ...

這樣一來,最終在資料中執行的sql語句就比較簡單了,如果客戶確實傳了useridmenuid兩個引數,sql就應該長這個樣子:

select * from foodorder where 

orderuserid = @userid and

foodmenuid = @menuid

執行的set statistics io on結果如下:

(3 行受影響)

table 'foodorder'. scan count 2, logical reads 11, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.

顯然僅進行了11次邏輯讀(相比靜態sql337次),然後執行計畫如下:

顯示進行了兩次index seek,顯然是走了索引,顯示查詢開銷只佔5%,而之前的開銷佔95%,效能區別高達20倍以上。

就像文中所說的動態sql,我認為理解資料庫、對寫出高效能的應用程式至關重要——這顯而易見,但其實又很容易忽略。忽略的原因不僅是因為新手,很多老手有時因為「網際網路」思維和「設計模式」等原因,也會有意忽略資料庫的理解。

現在很多「網際網路」應用思維認為,資料庫就是乙個倉庫,它應該只負責其最「擅長」的增刪改查功能即可,其它的應該都交由快取來解決。有句話說得好,就是命名和快取失效,是程式設計界最困難的兩個問題。快取有快取的問題,不好好理解資料庫,就必須花大量時間好好理解快取。設計乙個正確的快取往往又比花大量時間設計資料庫要複雜得多。

另外現在流行的「領域驅動設計」(ddd)也主張應用應該先從業務邏輯開始抽象,資料庫和效能往往成為他們首先忽略的物件,最後可能也得加個「快取」來解決,導致原來簡單的系統急劇膨脹,複雜不堪。這種過度設計、人云亦云的做法值得深思。

了解一下SQL注入的原理

sql注入攻擊的危害性很大。在講解其防止辦法之前,資料庫管理員有必要先了解一下其攻擊的原理。這有利於管理員採取有針對性的防治措施。一 sql注入攻擊的簡單示例。statement select from users where value a variable 上面這條語句是很普通的一條sql語句,...

簡述一下索引的匹配原則 mysql索引詳解

這是關於php高階到架構之mysql高階學習的第四篇文章 mysql索引詳解 第一篇 mysql共享鎖及排它鎖第二篇 mysql事務及隔離級別第三篇 mysql底層btree與b tree實現原理第四篇 mysql索引詳解 什麼是列的雜湊性呢?比如user 使用者表 中的username欄位,該列的...

簡單講一下 SpringMVC的執行流程

執行流程 1 使用者向伺服器傳送請求,請求被 spring 前端控制 servelt dispatcherservlet 捕獲 捕獲 2 dispatcherservlet 對請求 url進行解析,得到請求資源識別符號 uri 然後根據該 uri,呼叫 獲得該 handler 配置的所有相關的物件 ...