在使用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注入攻擊的危害性很大。在講解其防止辦法之前,資料庫管理員有必要先了解一下其攻擊的原理。這有利於管理員採取有針對性的防治措施。一 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 配置的所有相關的物件 ...