例如语句:
sql1:
declare @s nvchar(30)
set @s='ss'
select * from table1 where c1=1 and (@s='' or c2=@s)
sql2:
select * from table1 where c1=1 and ('ss'='' or c2='ss')
从结构上来看实际上是一模一样的SQL结构,但是在执行的时候发现两者效率相差极大
无外界影响情况下SQL2在<1秒出结果,SQL2却需要18秒从执行计划看
SQL1使用的clustered index scan,预计行数是表全集
SQL2使用的clustered index seek,预计行数为1条记录请问这个是什么原理导致的,该如何解决呢?
sql1:
declare @s nvchar(30)
set @s='ss'
select * from table1 where c1=1 and (@s='' or c2=@s)
sql2:
select * from table1 where c1=1 and ('ss'='' or c2='ss')
从结构上来看实际上是一模一样的SQL结构,但是在执行的时候发现两者效率相差极大
无外界影响情况下SQL2在<1秒出结果,SQL2却需要18秒从执行计划看
SQL1使用的clustered index scan,预计行数是表全集
SQL2使用的clustered index seek,预计行数为1条记录请问这个是什么原理导致的,该如何解决呢?
解决方案 »
- 一个update语句
- 关于嵌套查询,怎么提示order附近有语法错误?
- 会用pivot和unpivot,但是不能理解,有没有数学分析的模型?
- SQL SERVER中的SSIS怎么入门比较好?
- sql server7.0恢复数据库时报错,怎么办?
- 请问,如何把字段a的数据,复制到字段b?(sql语句)
- [Microsoft][ODBC SQL Server Driver][TCP/IP Sockets]ConnectionCheckForData (CheckforData()).
- SQL查询结果另存为EXCEL时,前导0消失!
- 存在的纪录不允许插入
- 请教:如何将SQL SERVER中的数据导出到MySql中??
- 请问这条SQL语句该怎么写, 根据行号来更新表
- 小梁,看到的话请进来下
exec('select * from table1 where c1=1 and ('''+@s+'''='''' or c2='''+@s+''')')
才和sql2等效.
select * from table1 where c1=1 and (ss='' or c2=@s) sql2:
select * from table1 where c1=1 and ('ss'='' or c2='ss')
这2句的条件不一样,当然效率有差别,虽然说结构一样
select * from table1 where c1=1 and (ss='' or c2=ss) sql2:
select * from table1 where c1=1 and ('ss'='' or c2='ss')
为避免注入,我一般是在拼完的串外再加 select * from (已拼好串)as a
就算对方注入,这样直接语法错误,而无法执行注入sql.
-------------
存在库里也就只有单引号可以截断sql,那么replace成两个单引号不就可以了?
简单的使用索引查找的计划。有两个方法可以参考修改:1)
IF @S=''
SELECT * FROM Table WHERE C1=1
ELSE
SELECT * FROM Table WHERE C1=1 AND C2=@s2)
SELECT * FROM Table WHERE C1=1 AND C2=@s
UNION
SELECT * FROM Table WHERE C1=1 AND @s=''
所以在Complie阶段就可以确定使用索引查找. 但SQL1因为使用了变量而且含有OR 关,所以不能简单的使用静态索引查找。
舉个很简单的例子,(Northwind资料库,Customers表)
有以下SQL:Declare @s nvarchar(30),@t nvarchar(30)
set @s='BONAP'
SET @t=''select * from Customers where CustomerID =@s OR CustomerID =@T--
在编译这条语句时,优化器是没办法知道@s和@t的值的,它们的值是在运行时确定的。
Index Seek(CustomerID='BONAP' OR CustomerID='' )操作的底层实际上是这样子的:先按第一个条件走一次索引,取出匹配的行,然後再按OR後面的条件走一次索引,再取出匹配的行。
如果CustomerID=@s OR CustomerID=@t 强行走Index Seek,万一@s跟@t的值相同,就会可能出同时取出两笔一样的资料,这样的结果不是我们想要的。所以你仔细看这条语句生成的执行计划,它会扫描@s跟@t的值,合并成资料表,然後再去除重复的值,再进行索引查找。这个过程叫叫Dynamic Index Seek.记住一点就够了,执行计划是在编译阶段生成。