首页 »数据库 » sql查询语句:如何编写高效率的SQL查询语句 »正文
sql查询语句:如何编写高效率的SQL查询语句
来源: 发布时间:星期四, 2009年2月12日 浏览:778次 评论:0
先站在应用![](/icons/70514chengxu.gif) 角度说说它们 区别
1、 直接拼SQL
就像大家了解 那样 直接拼SQL带来了SQL注入攻击 带来了拼时些许 性能损失 但是拼不用添加SqlParameter 会少写很多代码——很多人喜欢直接拼 也许就 这点 这种做法会把你拼好 SQL原样直接发送到DB服务器去执行 (注意类似”exec yourproc ‘param1’, 12” 语句不在此范畴 这是 存储过程![](/icons/70514de.gif) 种方式)
2、 参数化SQL
所谓 “参数化SQL”就是在应用 侧设置SqlCommand.CommandText 时候使用参数(如:@param1) 然后通过SqlCommand.Parameters.Add
来设置这些参数 值 这种做法会把你准备好 命令通过sp_executesql系统存储过程来执行 通过参数化SQL 和直接拼SQL相比 最直接 好处就是没有SQL注入攻击了
3、 存储过程
直接 存储过程其实和参数化SQL非常相似 唯![](/icons/70514yi.gif) 本质区别在于你发送到DB服务器 指令不再是sp_executesql 而是直接 存储过程 而已
很多人非常非常厌恶在应用 中使用存储过程 而宁愿使用拼SQL或者参数化SQL 理由是它们提供了更好 灵活性——这个理由其实非常非常 发指(俺现在喜欢上这个词了)
现在做设计![](/icons/70514dou.gif) 般都是从上到下来 重心都在业务逻辑上 传说中 领域模型设计完 测试用例都通过的后 才会考虑数据持久化方式 数据持久化是系统![](/icons/70514de.gif) 部分 但绝对不是最重要 部分 设计应该围绕业务逻辑开展 持久化应该仅仅是个附件 至少 高层应用应该尽可能 不关心处于最底层 物理存储结构(如:表)和数据持久、反持久方式(是拼SQL
还是存储过程) 所以用不用存储过程根本不重要 很多人害怕存储过程 其实是害怕存储过程中包括业务逻辑——真实情况是 如果存储过程中包含了业务逻辑 那 定最初需求分析不够导致用例提取不足 导致测试用例覆盖不够 导致领域模型设计不充分 要不就是偷懒
![](/icons/70514dd.gif) =
站在DB角度讨论它们 区别 主要从cpu、内存方面来考虑 其他诸如安全性 msdn上都有 google也能拿到 堆资料 不再赘述
首先是查询计划
SQL编译完 条SQL的后 会把它缓存Cache起来(可以通过sys.syscacheobjects系统视图查看) 以后再有相同 查询过来(注意sys.syscacheobjects视图中 sql字段 和它存储 东西完全 样才能称为“相同 查询”) 会直接使用缓存Cache 而不再重新编译
Ø 存储过程 伊只编译 遍(如果没有指定with recompile选项 话 如果指定了 根本就不会生成计划缓存Cache)
Ø 参数化SQL 和存储过程基本 样 只要是相同 查询 也都是只编译 次 以后重用(当然 指定了option(recompile) 除外) 这里不得不提.NET SqlClient组件![](/icons/70514de.gif) 个龌龊:如果你 参数中包含varchar或者char类型 参数 你在Parameters.Add 时候又没有指定长度 它都会根据你实际传入![](/icons/70514de.gif) 串长度(假设是n)给你重新定义成nvarchar(n) 如:select * from mytable where col1 = @p1 你设置@p1为’123456’ 实际传到sql这边 命令是:exec sp_executesql N\'select * from mytable where col1 = @p1\',N\'@p1 nvarchar(6)\',@p1=N\'123456\'[Page] 这样 系统缓存Cache中实际存储 sql是:(@p1 nvarchar(6))select * from mytable where col1 = @p1
看到了吧?如果你 输入参数变动比较多 那么看起来同样![](/icons/70514de.gif) 条语句 会被编译很多次 在缓存Cache中存储很多份 cpu和内存都浪费了 这也是在 写有效率 SQL查询IV 中建议 使用最强类型参数匹配 原因的![](/icons/70514yi.gif)
Ø 拼SQL 到这里不说大家也猜 出来 拼SQL要浪费大量 cpu进行编译 浪费大量缓存Cache空间来存储只用 次 查询计划
服务器 物理内存有限 SQLServer 缓存Cache空间也有限 有限 空间应该被充分利用 通过性能计数器SQL Server:Buffer Manager\\Buffer Cache hit ratio来观察缓存Cache命中率 如果它小于百分的90 你就得研究研究了 关注 把诸如sys.dm_os_memory_cache_counters、sys.dm_os_memory_cache_entries、sys.dm_os_memory_cache_hash_tables、sys.syscacheobjects等视图 基本可以确定问题出在哪儿
cpu方面需要关注 3个性能计数器:SQLServer:SQL Statistics\\Batch Requests/Sec、SQLServer:SQL Statistics\\\'; mso-fareast-font-family: 宋体; mso-bidi-font-family: \'Times New Roman\'; mso-font-kerning: 12.0pt\"> SQLCompilations/sec、SQLServer:SQL Statistics\\\'; mso-fareast-font-family: 宋体; mso-bidi-font-family: \'Times New Roman\'; mso-font-kerning: 12.0pt\"> SQL Re-Compilations/sec 如果compilations数目超过batch请求数目 百分的10 或者recompilations数目超过compilations数目 百分的10 那基本可以介绍说明cpu消耗了太多在编译查询计划上面![](/icons/70514dou2.gif)
最后 我 建议是: 1、DB中 所有操作都尽可能 使用存储过程 哪怕只是 句简单 select![](/icons/70514dou2.gif) 2、鄙视拼SQL![](/icons/70514dou2.gif)
btw:MSDN中对拼SQL称为\"ad hoc\" 呵呵![](/icons/70514dou2.gif)
![](/icons/70514dd.gif) ![](/icons/70514dd.gif) ![](/icons/70514dd.gif) ![](/icons/70514dd.gif) ![](/icons/70514dd.gif) ![](/icons/70514dd.gif) ![](/icons/70514dd.gif) ![](/icons/70514dd.gif) ![](/icons/70514dd.gif) 补充 点 介绍说明 下N\'@p1 nvarchar(6)\'换成N\'@p1 nvarchar(30)\'会重新编译:)![](/icons/70514dou2.gif)
代码如下:
1 \" align=top>// \"> 2 \" align=top>SqlCommandcmd= SqlCommand(
\"select*frommytwheredata=@d\",conn); 3 \" align=top>cmd.Parameters.Add( SqlParameter(\"@d\",\"1234567890\")); 4 \" align=top>cmd.ExecuteNonQuery ; 5 \" align=top> 6 \" align=top>cmd= SqlCommand(\"select*frommytwheredata=@d\",conn); 7 \" align=top>cmd.Parameters.Add( SqlParameter(\"@d\",\"123\")); 8 \" align=top>cmd.ExecuteNonQuery ; 9 \" align=top>
执行完这段![](/icons/70514chengxu.gif) 可以观察观察sys.syscacheobjects:
![\"\"](\"/Files/BeyondPic/2007-8/21/070821_1.png\") 上图中 5、6行标记了缓存Cache 查询计划![](/icons/70514dou2.gif)
![](/icons/70514dd.gif) ![](/icons/70514dd.gif) =
另外 再来说个更应该注意 地方:
1 \" align=top>// \"> 2 \" align=top>SqlCommandcmd= SqlCommand(\"select*frommytwheredata=@d\",con); 3 \" align=top>cmd.Parameters.Add( SqlParameter(\"@d\",\"1234567890\")); 4 \" align=top>cmd.ExecuteNonQuery ; 5 \" align=top>
6 \" align=top>cmd= SqlCommand(\"select*frommytwheredata=@d\",con); 7 \" align=top>cmd.Parameters.Add( SqlParameter(\"@d\",\"123\")); 8 \" align=top>cmd.ExecuteNonQuery ; 9 \" align=top> 10 \" align=top>cmd= SqlCommand(\"select*frommytwheredata=@a\",con); 11 \" align=top>cmd.Parameters.Add( SqlParameter(\"@a\",\"123\")); 12 \" align=top>cmd.ExecuteNonQuery ; 13 \" align=top>
注意 上述代码中最后 次操作我把@d参数重命名成了@a 然后再来看看sys.syscacheobjects里面有啥:[Page]
![\"\"](\"/Files/BeyondPic/2007-8/21/070821_2.png\")
注意第 6行![](/icons/70514dou2.gif)
相关文章
读者评论
发表评论
|
|