这对大大们应该是基本的概念,但最近还是会看到"判断表格是否存在指定的资料,会先查完资料,再判断是否数量大于1"
情况
其实可以少一步count动作,并且借助资料库语法提升效能。
举例
现在有一个使用者资料,想要判断指定名称的使用者存不存在
"会先查完资料,再判断是否数量大于1"
写法
void Main(){using (var conn = this.Connection)//替换成自己的connection{conn.Open();using (var tx = conn.BeginTransaction()) {conn.Execute(@"--测试资料CREATE TABLE #T ([UserID] int, [Name] nvarchar(2)); INSERT INTO #T ([UserID], [Name])VALUES (1, N'阿翰'), (2, N'阿明');", transaction: tx);bool IsUserExist(string name){//先查完资料,再判断资料是不是存在return conn.Query(@"--查询select *from #Twhere name = @name", new { name }, transaction: tx).Count()>0;}var queryExist = IsUserExist("阿明"); var queryNonExist = IsUserExist("阿香"); tx.Rollback();}}}
其实可以改成select top 1 1
方式 (Oracle可以用rownum=1)
优化原理:
select 1
,当返回资料为1的时候,C#指定型态为bool会自动判断if (value = 1) =true else = false
void Main(){ //..略 bool IsUserExist(string name) { //返回类型是bool,结果是1时候,会自动转成true,null或其他状态会返回false return conn.ExecuteScalar<bool>(@" --查询 select top 1 1 from #T where name = @name ", new { name },transaction:tx); } var queryExist = IsUserExist("阿明"); //因为有资料所以返回true var queryNonExist = IsUserExist("阿香"); //因为没有资料返回false //..略}
补充关于效能方面的profiler计画,以下是使用全表扫描情况
先建立二十万笔资料做测试
--测试资料CREATE TABLE T([UserID] int, [Name] nvarchar(2));DECLARE @cnt INT = 0;BEGIN TRANSACTION;WHILE @cnt < 100000BEGININSERT INTO T ([UserID], [Name])VALUES (1, N'阿翰'),(2, N'阿明') ; SET @cnt = @cnt + 1;END;commit;
top 1 1
用法
count方式
用法
可以观察到两个用法,在where扫描的情况下是一样的(资料表扫描)
但是在top用法在select成本,使用top运算式,该成本不到总成本1%
而count用法在select成本,使用资料流彙总,该成本佔总成本13%
IO比较,都没用到IO,因为资料已经从资料表扫描筛选出来了
TOP用法 : 0
count用法 : 0
CPU比较,top胜
TOP用法:0.0000001
count用法:0.0600005
至于select * from table在C#再转count版本就不测试了(这写法有点糟糕 XDD)
补充
使用ORM套件Dapper,.NET版本4.6.1
编辑器LINQPad,资料库:SQL-Server
假如大大们有更好作法,或是错误地方麻烦告知,感恩。