我正在寻找MSSQL数据库中不需要的控制字符。
我目前使用的存储过程是针对我需要搜索的数据库创建的,但这只能在搜索简单字符或字符串时起作用。请参阅下面的步骤(这是第一次从本网站收集)
CREATE PROC SearchAllTables
(
@SearchStr nvarchar(100)
)
AS
BEGIN
-- Creates a Stored Procedure for the database
-- When running the procedure, set the @SearchStr parameter to the character you are searching for
CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110)
SET @TableName = ''
SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')
WHILE @TableName IS NOT NULL
BEGIN
SET @ColumnName = ''
SET @TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName
AND OBJECTPROPERTY(
OBJECT_ID(
QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
), 'IsMSShipped'
) = 0
)
WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)
BEGIN
SET @ColumnName =
(
SELECT MIN(QUOTENAME(COLUMN_NAME))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(@TableName, 2)
AND TABLE_NAME = PARSENAME(@TableName, 1)
AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar')
AND QUOTENAME(COLUMN_NAME) > @ColumnName
)
IF @ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630)
FROM ' + @TableName + ' (NOLOCK) ' +
' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
现在,我需要更改此设置以允许我搜索控制字符列表:
'%['
+ CHAR(0)+CHAR(1)+CHAR(2)+CHAR(3)+CHAR(4)
+ CHAR(5)+CHAR(6)+CHAR(7)+CHAR(8)+CHAR(9)
+ CHAR(10)+CHAR(11)+CHAR(12)+CHAR(13)+CHAR(14)
+ CHAR(15)+CHAR(16)+CHAR(17)+CHAR(18)+CHAR(19)
+ CHAR(20)+CHAR(21)+CHAR(22)+CHAR(23)+CHAR(24)
+ CHAR(25)+CHAR(26)+CHAR(27)+CHAR(28)+CHAR(29)
+ CHAR(30)+CHAR(31)+CHAR(127)
+ ']%',
现在,现有的程序将不允许我将其用作搜索字符串,即使使用单个控制字符也无法正确搜索,例如CHAR(28)
USE [DBNAME]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[SearchAllTables]
@SearchStr = N'CHAR (28)'
SELECT 'Return Value' = @return_value
GO
在上面的示例中从@SearchStr中删除N''
会导致错误消息:
'28'附近的语法不正确
任何人都可以帮助调整此过程以允许搜索控制字符吗?
答案 0 :(得分:2)
我会选择动态CharIndex()。请考虑以下
Declare @ColumnName varchar(25)='[SomeField]'
Declare @SearchFor nvarchar(max) ='CHAR(0),CHAR(1),CHAR(2),CHAR(3),CHAR(4),CHAR(5),CHAR(6),CHAR(7),CHAR(8),CHAR(9),CHAR(10),CHAR(11),CHAR(12),CHAR(13),CHAR(14),CHAR(15),CHAR(16),CHAR(17),CHAR(18),CHAR(19),CHAR(20),CHAR(21),CHAR(22),CHAR(23),CHAR(24),CHAR(25),CHAR(26),CHAR(27),CHAR(28),CHAR(29),CHAR(30),CHAR(31),CHAR(127)'
Set @SearchFor = 'CharIndex('+Replace(@SearchFor,',',','+@ColumnName+')+CharIndex(')+','+@ColumnName+')'
所以你的动态在哪里看起来像这样
' WHERE ' + @SearchFor + '>0'
仅举例说明,@ SearchFor字符串看起来像这样
CharIndex(CHAR(0),[SomeField])+CharIndex(CHAR(1),[SomeField])+...+CharIndex(CHAR(31),[SomeField])+CharIndex(CHAR(127),[SomeField])
答案 1 :(得分:1)
看起来QUOTENAME
正在为你打破一切。当您尝试使用某些字符时 - 例如char(0)
- 它会返回NULL
。因此,您可能最好自己手动输入单引号。
这意味着您需要更改此部分:
INSERT INTO #Results
EXEC
(
'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630)
FROM ' + @TableName + ' (NOLOCK) ' +
' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
)
到此:
INSERT INTO #Results
EXEC
(
'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630)
FROM ' + @TableName + ' (NOLOCK) ' +
' WHERE ' + @ColumnName + ' LIKE ''' + @SearchStr + ''' -- Note the use of @SearchStr (Not @SearchStr2) and the additional quotes to wrap your search string in.
)
应该允许您使用%[...]%
模式匹配语法。
答案 2 :(得分:0)
<强>关注强>:
您可能知道,参数开头和结尾的通配符(%
)会阻止SARG
根本使用任何索引(即使它声称使用INDEX SCAN
)因为SQL Server不知道值将在何处。在最糟糕的情况下,它甚至可能会出现错误的区域!
更严重的是,你发起的最后一个EXEC
语句将使SQL Server运行起来。尽管你可能会想到,SQL Server
在执行时初始化变量。这意味着,当优化器处于执行查询计划的中间时,优化器将继续运行,并且最终可能会多次更改!
我的一个DB上发生的可能释放的示例a 一个月前,一个可怕的新插件运行一个简单的查询寻找 在1的大表上只有两个严重参数化谓词的一行 百万行。然而,优化器吞噬了数以万亿计的
IO
秒 几秒钟的问题(对于州长来说查询来得太快了) 并通过网络发送 20亿行 PER QUERY 。 可悲的是,那天的问题被僵尸,只有500个一排 我的数据库中的结果集反复运行,它降低了我们的 服务器
随意猜测,期望锁定问题并吞噬资源。诸如UPDATES
,REINDEXING
和ALTER
语句等主要操作将被迫等待或将您的查询踢到路边。即使使用READ UNCOMMITTED也无法避免一些阻塞问题。
新方法
您列出的所有字符既不是字母也不是数字,而是从前端应用程序流入的无意义垃圾(到SQL Server)。我注意到你排除了Microsoft System Tables
,那么你的数据流来自何处以及如何在整个数据库中传播?谁有过错?系统,用户和设计师如何在混乱中发挥作用?
此服务器是OLTP
还是READ
重?您的组织是否没有强大的SSIS
,ETL
系统来防止垃圾在您的服务器上造成严重破坏?
确实,您的应用程序在发送数据之前未能预先清理数据的原因是什么?当它确实达到数据库级别时,为什么我们不能同时使用DATA TYPE
和TABLE CONSTRAINTS
?简单的解决方案,例如使用DATE
而不是VARCHAR
来存储日期,添加规范化而不是存储blob以将读取繁重的表与写入密集的表格隔离开来,这可以说明改进的奇迹。
承认,使用CHECK CONSTRAINTS
会导致INSERT
语句的效果呈指数级下降,因此您可能需要考虑更大的影响。
预防性与规定性
表面上看,我可以编写一个可以解决当前问题的查询(在另一个Stored Proc
中封装EXEC语句可以启用正确的参数嗅探),我们需要多写一些并编写更少的代码。 你的程序现在很糟糕,即使我们穿着衣服也一直都是。它掩盖了这些控制角色如何首先到达那里的真正问题,并迫使对你的糟糕系统进行昂贵的查询。
你的表如何工作,规范化,基数的关系应该对你有意义,这样你不仅可以区分表的类型,还可以区分它们拥有的那些特定的列。您当前的麻烦对我的许多数据库来说都是灾难性的,这些数据库的大小可以达到1.5+太字节
您收集的要求越多,答案就越好。哎呀,即使完全为ETL设置数据库也会优于您当前的解决方案。即使你最终仍然运行类似的查询,至少你会将你的列和表的列表缩短到一分钟,可理解的列表,而不是盲目地给你公司的每个人带来痛苦。
祝福!