在使用ef
或者寫sql
語句時,查詢條件往往是這樣一種非常常見的邏輯:如果客戶填了查詢資訊,則查詢該條件;如果客戶沒填,則返回所有資料。
我常常看到很多人解決這類問題時使用了錯誤的靜態sql
的解決辦法,使得資料庫無法利用索引,導致效能急劇下降。
這次我將使用我的某客戶的真實資料來演示(已確認不涉及資訊保安 ),有乙個訂單表foodorder
,結構如下:
我在id
、foodmenuid
、orderuserid
上建立了非聚集索引,在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 null
和or
,導致語句完全無法使用索引,執行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
語句就比較簡單了,如果客戶確實傳了userid
和menuid
兩個引數,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
次邏輯讀(相比靜態sql
的337
次),然後執行計畫如下:
顯示進行了兩次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...