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)将复 ...
随机推荐
- ACM: Copying Data 线段树-成段更新-解题报告
Copying Data Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description W ...
- [知识点]SPFA算法
// 此博文为迁移而来,写于2015年4月9日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vx93.html 1.前言 ...
- HDU 4431 Mahjong(模拟题)
题目链接 写了俩小时+把....有一种情况写的时候漏了...代码还算清晰把,想了很久才开写的. #include <cstdio> #include <cstring> #in ...
- POJ 1329 Circle Through Three Points(三角形外心)
题目链接 抄的外心模版.然后,输出认真一点.1Y. #include <cstdio> #include <cstring> #include <string> # ...
- Android -- ImageView通过Bitmap得到网上的图片资源
1. 效果图
- insert into select 与select into from -- sql 批量插入
参考资料:http://www.w3school.com.cn/sql/sql_union.asp UNION:操作符用于合并两个或多个select语句的结果集. ...
- XCode编译文件过多导致内存吃紧解决方法
XCode编译文件过多导致内存吃紧解决方法 /Users/~~/Library/Developer/Xcode/DerivedData 1) 然后 找到编译文件 删除 就好了哦 快去试试看吧
- Java 仿迅雷多线程下载
package net.webjoy.jackluo.android_json; /** * 1.http Range "bytes="+ start+end * 2.Random ...
- GO语言练习:switch基本用法
1.代码 2.运行 1.代码 package main import "fmt" func switch_1(i int){ switch i { : fmt.Println(&q ...
- Oracle 新手问答
存储过程中,return后,如果没有写明提交(commit)或回滚(rollback),会默认提交吗?答:不会.如果修改了数据,又没有写明,则会将数据锁定在那里! 存储过程中,调用子存储过程异常时,在 ...