本系列文章旨在收集在開發過程中遇到的一些常用的SQL語句,然后整理歸檔,本系列文章基於SQLServer系列,且版本為SQLServer2005及以上……
文章系列目錄
- SQL開發技巧(一)
- SQL開發技巧(二)
本文內容簡介
這篇文章主要介紹以下內容:
- 快速查詢表的總記錄數
- 非遞歸查詢樹形結構表的所有子節點
- 清除查詢緩存
- 編程中構建Where語句的小技巧
- 如何進行跨服務器的數據庫查詢
快速查詢表的總記錄數
什么,你還在用select count(*) from xxx
?難道沒有園友告訴你用select count(col)
,select count(0)
或者select count(1)
性能會更好嗎?
等等,你難道就只告訴我這個嗎,我早知道了,就算是用了select count(0)
查詢1000w的記錄還是慢吶,你不會接着告訴我去升級服務器吧?
當然不是,我要告訴你的是下面的這個語句:
SELECT rows FROM sysindexes WHERE id= OBJECT_ID('rpt2014' ) AND indid< 2
無論查詢多少記錄數的表,都能立即返回總記錄數。為什么它能夠這么快,這原理其實跟Length
屬性和Count()
方法一樣的,自己體會啦。此外,要注意這個條件:indid< 2
。indid
為1就是最后提交之后的總記錄數,其他值可能表示索引的記錄或者其他,具體就自己search了吧。
非遞歸查詢樹形結構表的所有子節點
首先,普及一個概念,怎么設計表結構為樹形結構的:要設計一個樹形結構的表,必須包含兩個必要字段:
Id
,ParentId
那么樹形結構的表要查詢子節點是非常容易的:select * from table where ParentId=xxx
。但是,如何查詢所有的子節點呢(包括子節點的子節點,遞歸查詢)?
原來我采用的方法:
- 把所有記錄查詢出來,在程序中做遞歸查詢
- 采用存儲,在數據庫中做遞歸查詢
- 修改表結構,增加字段
ParentIdPath
。比如有節點3,父節點為2,而2的父節點為1。那節點3的ParentIdPath
就是:2,1.這樣查詢所有的子節點就可以用like操作了:select * from table where ParentIdPath like '2,%'
上面的方法都不太優美:我不希望在程序中查詢、不希望增加額外的存儲過程(我也隨時隨地能用)、不希望增加字段,那么到底該怎么辦,需要問下藍翔嗎?
要解決這個問題,需要使用SQLServer中的with
關鍵字,相應創建一個臨時表保存每次查詢的記錄:
WITH Tree AS (
SELECT * FROM dbo .MgrObjType WHERE Id='00000000-A001-0000-0000-000000000000'
UNION ALL
SELECT MgrObjType.* FROM dbo .MgrObjType, Tree WHERE Tree.Id= dbo.MgrObjType .ParentId
)
SELECT * FROM Tree
結果如下:
清除查詢緩存
為什么要清除緩存,有一定開發經驗的程序員都知道,把一條耗時的語句在SQLServer中查詢,第一次可能很慢,第二次就很快了。這樣非常影響測試的效率,甚至有些程序員竟然認為第二次查詢跟第一次查詢不一樣,這是一種不可靠的測試,沒法重現問題,把責任歸咎於SQLServer,巨硬那是真真正正的躺槍。
其實,上述問題的產生,主要是因為SQLServer每次查詢,都會把結果緩存下來,遇到相同的SQL語句或者類似的,會從已有的緩存中查詢,緩存中不存在的,才實際訪問數據庫。到底內存緩存多少,你可以設置:
沒錯,就是它了。有經驗的同學還會發現,如果你不設置,可能會耗光你的內存。記得有次我在一台128G內存的電腦上使用,沒有限制,內存直接利用到了70多G,搞得運維的同學如臨大敵,好像我們的軟件有什么天大的問題似的!
這個語句是這么寫的:
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
編程中構建Where語句的小技巧
這真是一個小技巧,我記得我最先學編程的時候,判斷條件是這么判斷的:
var sql=new StringBuilder();
if(age.HasValue||nickName.HasValue){
sql.AppendFormat(" where ");
}
if(age.HasValue){
sql.AppendFormat("Age={0}",age.Value);
}
if(nickName.HasValue)……
如果條件多了的話,寫得那是更加的痛苦
其實上面的條件完全可以這么寫:
var sql=new StringBuilder(" where 1=1");
if(age.HasValue){
sql.AppendFormat("Age={0}",age.Value);
}
if(nickName.HasValue)……
多了一個1=1,少了多少的條件判斷。為什么會醬紫?拜托自己動一下腦筋好不,什么都要我說出來,你給我發薪水啊!
如何進行跨服務器的數據庫查詢
要查詢另外一個數據庫的表,好的,不就是DatabaseName.dbo.Table
嗎,這個簡單
神馬,這個數據庫在另外一個服務器,尼瑪啊,這是什么需求,你tmd為什么要訪問另外一個數據庫啊。能在代碼中實現嗎?不行!!!???
好吧,那我們怎么實現,請看:
SELECT * FROM
OPENDATASOURCE('SQLOLEDB' , 'Data Source=172.18.24.245;User ID=sa;Password=aaa*'). CenterObj_xx.dbo .TableLog AS A
你真的沒看錯,只需增加這么一句OPENDATASOURCE('SQLOLEDB' , 'Data Source=172.18.24.245;User ID=sa;Password=aaa*')
即可。這句就是幫你訪問遠程數據庫的。
往期內容回顧
- 使用Row_Number分頁
- 事務
- 根據條件刷選記錄的技巧