動態sql 為什麼需要動態SQL

2021-10-14 19:46:16 字數 3240 閱讀 5354

在使用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

在使用ef或者寫sql語句時,查詢條件往往是這樣一種非常常見的邏輯 如果客戶填了查詢資訊,則查詢該條件 如果客戶沒填,則返回所有資料。我常常看到很多人解決這類問題時使用了錯誤的靜態sql的解決辦法,使得資料庫無法利用索引,導致效能急劇下降。這次我將使用我的某客戶的真實資料來演示 已確認不涉及資訊保安...

動態sql語句 動態別名

動態sql語句我們經常會用的到,下面為您介紹的是使用動態sql語句自定義列名的實現方法,如果您之前遇到過類似的問題,不妨一看。create procedure poquery1 supplyid varchar 30 引數 as declare no nvarchar 100 declare seq...

動態SQL入門

動態sql語句的理解 1.動態sql的分類 根據要處理的sql語句的作用不同,可以使用三種不同型別的動態sql方法 1 使用execute immediate語句可以處理包括ddl create alter和drop dcl grant revoke dml insert update delete...