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)将复 ...
随机推荐
- 不刷新改变URL: pushState + Ajax
如果你玩过Google+,看到过YouTube的新界面,便会体验到这个HTML5的新功能.使用pushState + Ajax(pjax),可以实现网页的ajax加载,同时又能完成URL的改变而没有网 ...
- HDU 2222 & ac自动机模板
题意: 求n个模板串在匹配串中出现了几个. SOL: 反正就是模板啦...似乎比KMP都简单----这么说似乎有点不道德...毕竟先看的KMP而他们并没有什么不同... 貌似自己的理解和他们画的图还是 ...
- HDU 3333 & 离线+线段树
题意: 统计一段区间内不同数字之和.如1 1 2 3 1 统计2---5即1+2+3. SOL: 很少打过离线的题目...这种可离线可在线的题不管怎么样一般都是强行在线... 考虑这题,此前做过一个类 ...
- C#中的IComparable 和 IComparer 接口,实现列表中的对象比较和排序
借豆瓣某博主的话先对这两个接口进行一个解释: IComparable在要比较的对象的类中实现,可以比较该对象和另一个对象 IComparer在一个单独的类中实现,可以比较任意两个对象. 如果已经支持 ...
- 用存储过程 将大段的SQL藏起来
在日常工作中,当面对比较复杂的数据库操作时不免要写一些比较长的SQL,由于某系SQL有些长(目前我写的最长的貌似有30多行吧),这时候长会面临这个 方法 优点 缺点 用"+"串 ...
- 你也可以用java的swing可以做出这么炫的mp3播放器_源码下载
I had published the blog : 你用java的swing可以做出这么炫的mp3播放器吗? and to display some screenshots about this M ...
- tomcat、Linux服务器
tomcat.Linux服务器 用到的命令 解压命令: tar -zxvf 文件名 配置 : vi /etc/profile 按 i 进入 ...
- windows开机启动项
原来就一个命令呀:msconfig 1.在开始菜单中输入 msconfig 命令,回车 2.在弹出的对话框中取消不想启动的程序 3.点击应用->确定->不启动
- 给自定义cell赋值
搭建自定义cell-给自定义cell赋值的思路 1 主控制器 1.1导入头文件 #import "LHQInvestmentManagementCell.h" #import &q ...
- hdu Hike on a Graph
此题是道bfs搜索的题目.bfs的精髓就是找到下一步的所有可能然后存储起来,有点暴力的感觉,这题就是每步中 所有的可能都入队,然后一一 判断.这道题的题意是 : 给你一幅完全图,再给你三个盘,目的是把 ...