ANSI_NULLS、QUOTED_IDENTIFIER
数据库服务器重启后,游戏登录提示“您输入的用户名不存在,请重新注册!”
重启前特意登录过平台,基本操作都正常。这之间并没对数据库做任何修改,怀疑是应用程序服务端的问题。开启跟踪监控登录过程,只跟踪到一个过程,手动执行过程也没有报错。将问题反馈给技术:
【2014/02/18 10:17:32】[proc_VerifyUserPWEx] ADO 错误:0x80040e14,INSERT 失败,因为下列 SET 选项的设置不正确: 'ANSI_NULLS, QUOTED_IDENTIFIER'。请确保 SET 选项正确无误,可以用于 计算列上的索引视图和/或索引和/或筛选的索引和/或查询通知和/或 XML 数据类型方法和/或空间索引操作。。
查看存储过程定义(右击->编写存储过程脚本为->CREATE到->新查询编辑器窗口),发现在过程的定义的前面,有SET ANSI_NULLS OFF、SET QUOTED_IDENTIFIER OFF语句。
开启跟踪,监控登录涉及代码,只看到执行proc_VerifyUserPWEx,Profiler的Error事件列(0 - OK),将TextData复制到查询窗口执行没看到错误信息。依据经验登录正常的话会调用其他相关的存储过程,此时应该是在proc_VerifyUserPWEx过程出了异常。查看proc_VerifyUserPWEx过程的定义,发现过程使用了try...catch,但是在catch中直接return。这就解释了在查询窗口没有抛出错误信息的原因。
将过程代码放到测试用的DBA_Troubleshooting存储过程,并去掉try...catch,使用跟踪到的TextData参数,执行测试DBA_Troubleshooting,错误信息如下:
过程核心语句很简单:
SELECT colname FROM table1 WHERE...
IF @@ROWCOUNT=0
BEGIN
INSERT INTO table1...
INSERT INTO table2...
END
按照传入的参数并不会进入insert区域,为什么还要报insert失败呢?别忘了在过程定义的前面有SET ANSI_NULLS OFF、SET QUOTED_IDENTIFIER OFF语句,尝试分别将insert语句注释,定位在insert into table2失败,查看table2发现表上有一筛选索引(create index indexname on table2(col1,col2) include(col3) where col4 is null)。这个索引是春节前添加上去的(DDL数据库触发器记录),当时没出现登录异常的情况。
问题变得清晰,存储过程Proc1定义使用SET ANSI_NULLS OFF、SET QUOTED_IDENTIFIER OFF,中间有insert into table...。后来在table表上创建一个筛选索引(where col is null),程序依旧正常。直到某天重启数据库服务器/数据库服务,Proc1执行出现异常。
测试在查询窗口1按核心语句创建存储过程;在查询窗口2执行过程正常,然后创建筛选索引(ANSI_NULLS, QUOTED_IDENTIFIER需为ON),执行过程正常。查看过程执行情况(dm_exec_procedure_stats),显示重用了之前的执行计划。使用DBCC FREEPROCCACHE(plan_handle)清除原计划,再次执行过程报错!
/********查询窗口1********/
--创建测试表
CREATE TABLE Test_ANSI_NULLS(id INT,NAME VARCHAR(50))
--创建测试过程
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER PROC Pro_ANSI_NULLS
AS
SELECT TOP 1* FROM Test_ANSI_NULLS
IF @@ROWCOUNT=0
BEGIN
INSERT INTO
Test_ANSI_NULLS(id,NAME) SELECT TOP 1 object_id,NAME FROM sys.objects o ORDER BY NEWID()
END
GO /********查询窗口2********/
--执行三次 成功
EXEC Pro_ANSI_NULLS
GO 3
--创建过滤索引
CREATE INDEX idx_name ON Test_ANSI_NULLS(NAME) WHERE NAME IS NOT NULL
--执行两次 成功
EXEC Pro_ANSI_NULLS
GO 2
--过程执行情况
SELECT TOP 20 DB_NAME(a.database_id) DBname
,OBJECT_NAME(OBJECT_ID ,database_id) 'proc name'
,a.cached_time
,a.last_execution_time
,a.execution_count
,a.last_logical_reads
,a.total_logical_reads / a.execution_count avg_logical_reads
,a.total_logical_writes / a.execution_count avg_logical_writes
,a.total_physical_reads / a.execution_count avg_physical_reads
--,a.total_worker_time / a.execution_count AS avg_worker_time
,a.total_elapsed_time / a.execution_count avg_elapsed_time
--,b.text
,c.query_plan
,a.plan_handle
FROM sys.dm_exec_procedure_stats AS a
CROSS APPLY sys.dm_exec_sql_text(a.sql_handle) b
CROSS APPLY sys.dm_exec_query_plan(a.plan_handle) c
where OBJECT_NAME(OBJECT_ID ,database_id) ='Pro_ANSI_NULLS'
ORDER BY
a.total_logical_reads/a.execution_count DESC
--清除过程缓存
DBCC FREEPROCCACHE(0x05000A004468463FB860AB15000000000000000000000000)
--再次执行过程 出错
EXEC Pro_ANSI_NULLS
GO 2 /********解决方案********/
--删除过滤索引
DROP INDEX idx_name ON Test_ANSI_NULLS
--修改过程定义
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC Pro_ANSI_NULLS
...
GO /********删除测试数据********/
DROP PROC Pro_ANSI_NULLS
DROP TABLE Test_ANSI_NULLS
注意,如果过程直接进入到insert into 区域,则在创建索引后,不需清除缓存,执行过程就报错。
解决方案:其一,删除过滤索引;其二,修改过程定义,尝试将其修改为SET ANSI_NULLS ON、SET QUOTED_IDENTIFIER ON。
ANSI_NULLS、QUOTED_IDENTIFIER的一些解释可参考链接。
ANSI_NULLS、QUOTED_IDENTIFIER的更多相关文章
- 关于Ansi_Nulls、Quoted_Identifier、Ansi_Padding的用法
--QUOTED_IDENTIFIER 语法SET QUOTED_IDENTIFIER { ON | OFF } 注释当 SET QUOTED_IDENTIFIER 为 ON 时,标识符可以由双引号 ...
- ANSI_NULLS和QUOTED_IDENTIFIER
这些是 SQL-92 设置语句,使 SQL Server 2000/2005 遵从 SQL-92 规则. 当 SET QUOTED_IDENTIFIER 为 ON 时,标识符可以由双引号分隔,而文字必 ...
- ANSI_NULLS 和 QUOTED_IDENTIFIER
1 ANSI_NULLS 当 SET ANSI_NULLS 为 ON 时,对空值进行等于 (=) 或不等于 (<>) 比较时取值为 FALSE 例如:SELECT * from t ...
- 2019-03-25 SQL SET ANSI_NULLS /SET QUOTED_IDENTIFIER /SET NOCOUNT ON
use database go /**当 SET ANSI_NULLS 为 ON 时,即使 column_name 中包含空值,使用 WHERE column_name = NULL 的 SELECT ...
- sql 试图索引
视图是对数据(一种元数据类型)的一种描述.当创建了一个典型视图时,通过封装一个 SELECT 语句(定义一个结果集来表示为虚拟表)来定义元数据.当在另一个查询的 FROM 子句中引用视图时,将从系统目 ...
- SQL语句-创建索引
语法:CREATE [索引类型] INDEX 索引名称ON 表名(列名)WITH FILLFACTOR = 填充因子值0~100 GO USE 库名GO IF EXISTS (SELECT * FRO ...
- SqlServerProxy的一些资料
SqlServerProxy的一些资料 下载地址:http://files.cnblogs.com/files/lyhabc/SqlServerProxy.rar 1.特性及实现原理 SqlServe ...
- Sql动态添加字段的正确姿势
如何给指定表动态添加字段? 一.创建一张表[Tbl_AutoFileds] (tableName表名,fieldName字段名,dataType数据类型,length长度 isnull 是否允许为n ...
- sql视图学习笔记--视图
视图是为用户对数据多种显示需求而创建的,其主要用在一下几种情况: (1)限制用户只能访问特定表特定条件的内容,提高系统的安全性. (2)隐藏表结构.创建多种形式的数透视,满足不同用户需求. (3)将复 ...
随机推荐
- mongodb新手入门,mongodb命令学习
下面来总结一下mongodb新手入门的常用命令吧.要是您是mongodb新手,可以看下. 1,show dbs 查询mongodb里面的数据库列表 如果想查看当前连接在哪个数据库下面,可以直接输入db ...
- overflow-y:auto
overflow-x:auto; overflow-y:auto; X轴和Y轴自适应:
- 测试Centos硬盘读写速度
yum install hdparm 参数: -a<快取分区> 设定读取文件时,预先存入块区的分区数,若不加上<快取分区>选项,则显示目前的设定. -A<0或1& ...
- UILabel 的属性(用法)方法
Label 中常用的方法属性 UILabel *label =[[UILabel alloc]initWithFrame:CGRectMake(90, 100, 140, 40)];//设置Label ...
- 2001. Counting Sheep
After a long night of coding, Charles Pearson Peterson is having trouble sleeping. This is not onl ...
- 【Eclipse】 Alt+/ 代码提示问题解决方案
一般情况下alt+/有代码提示作用,还有代码提示的快捷代码也不是alt+/,因此要恢复代码提示用alt+/.需要做两件事. 在 Window - Preferences - General - Key ...
- RSA加密算法原理及RES签名算法简介
第一部分:RSA算法原理与加密解密 一.RSA加密过程简述 A和B进行加密通信时,B首先要生成一对密钥.一个是公钥,给A,B自己持有私钥.A使用B的公钥加密要加密发送的内容,然后B在通过自己的私钥解密 ...
- NetDMA
NetDMA provides operating system support for direct memory access (DMA) offload. TCP/IP uses NetDMA ...
- XML参考 :XmlReader 详解、实例
XML参考 :XmlReader 详解.实例-- 详解 转:http://www.cnblogs.com/Dlonghow/archive/2008/07/28/1252191.html XML参考 ...
- 选择Nodejs的N个理由
选择Nodejs的N个理由 作者 马德奎 发布于 2014年9月25日 Caleb Madrigal是 来自美国密尔沃基市的一名软件顾问.四年前,他在听说“将JavaScript用作服务器端语言”这样 ...