简体   繁体   English

SQL查询在SQL Server 2012中正常工作,但无法在SQL Server 2008 R2中执行

[英]SQL query working fine in SQL Server 2012, but failed to execute in SQL Server 2008 R2

I have a table called MyTextstable (myTextsTable_id INT, myTextsTable_text VARCHAR(MAX)) . 我有一个名为MyTextstable (myTextsTable_id INT, myTextsTable_text VARCHAR(MAX))的表MyTextstable (myTextsTable_id INT, myTextsTable_text VARCHAR(MAX)) This table has around 4 million records and I am trying to remove any instance of the ASCII characters in the following range(s) the VARCHAR(MAX) column myTextsTable_text . 此表有大约400万条记录,我试图删除VARCHAR(MAX)myTextsTable_text的以下范围内的任何ASCII字符实例。

  • 00 - 08 00 - 08
  • 11 - 12 11 - 12
  • 14 - 31 14 - 31
  • 127 127

I have written the following SQL query, which is taking under 10 minutes on SQL Server 2012, but failed to execute on SQL Server 2008 R2 even after two hours (so I stopped the execution). 我编写了以下SQL查询,在SQL Server 2012上花了不到10分钟,但即使在两个小时之后也无法在SQL Server 2008 R2上执行(因此我停止了执行)。 Please note I have restored the backup of a SQL Server 2008 R2 database on SQL Server 2012 (ie the data is exactly same). 请注意我已经在SQL Server 2012上恢复了SQL Server 2008 R2数据库的备份(即数据完全相同)。

BEGIN TRANSACTION [Tran1]

BEGIN TRY
    UPDATE myTextsTable
    SET myTextsTable_text = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(myTextsTable_text, CHAR(0), ''), CHAR(1), ''), CHAR(2), ''), CHAR(3), ''), CHAR(4), ''), CHAR(5), ''), CHAR(6), ''), CHAR(7), ''), CHAR(8), ''), CHAR(11), ''), CHAR(12), ''), 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), '')
    WHERE myTextsTable_text LIKE '%[' + CHAR(0) + CHAR(1) + CHAR(2) + CHAR(3) + CHAR(4) + CHAR(5) + CHAR(6) + CHAR(7) + CHAR(8) + CHAR(11) + CHAR(12) + 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) + ']%';
    COMMIT TRANSACTION [Tran1];
END TRY

BEGIN CATCH
    ROLLBACK TRANSACTION [Tran1];
    --PRINT ERROR_MESSAGE();
END CATCH;

There are only 135 records affected. 受影响的记录只有135条。 As the single UPDATE query wasn't working in SQL Server 2008, I have tried the following approach with a temp table. 由于单个UPDATE查询在SQL Server 2008中不起作用,我尝试使用临时表的以下方法。

BEGIN TRANSACTION [Tran1]

BEGIN TRY
    IF OBJECT_ID('tempdb..#myTextsTable') IS NOT NULL DROP TABLE #myTextsTable;
    SELECT myTextsTable_id, myTextsTable_text
    INTO #myTextsTable
    FROM myTextsTable
    WHERE myTextsTable_text LIKE '%[' + CHAR(0) + CHAR(1) + CHAR(2) + CHAR(3) + CHAR(4) + CHAR(5) + CHAR(6) + CHAR(7) + CHAR(8) + CHAR(11) + CHAR(12) + 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) + ']%';

    UPDATE #myTextsTable
    SET myTextsTable_text = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(myTextsTable_text, CHAR(0), ''), CHAR(1), ''), CHAR(2), ''), CHAR(3), ''), CHAR(4), ''), CHAR(5), ''), CHAR(6), ''), CHAR(7), ''), CHAR(8), ''), CHAR(11), ''), CHAR(12), ''), 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), '')

    UPDATE myTextsTable
    SET myTextsTable_text = new.myTextsTable_text
    FROM myTextsTable
    INNER JOIN #myTextsTable new ON new.myTextsTable_id=myTextsTable.myTextsTable_id

    DROP TABLE #myTextsTable;

    COMMIT TRANSACTION [Tran1];
END TRY

BEGIN CATCH
    ROLLBACK TRANSACTION [Tran1];
    --PRINT ERROR_MESSAGE();
END CATCH;

However, the result is same. 但是,结果是一样的。 Works perfectly fine in SQL Server 2012, but not in SQL Server 2008 R2. 在SQL Server 2012中工作得很好,但在SQL Server 2008 R2中却没有。 I found that the UPDATE query was still executing even after two hours (the records were saved into the temp table ( #myTextsTable ) in a few minutes, I checked this later to make sure which part is taking longer). 我发现即使在两个小时后UPDATE查询仍在执行(记录在几分钟内保存到临时表( #myTextsTable )中,我稍后检查以确保哪个部分花费的时间更长)。

As the aforementioned two ways weren't working, I have tried using this using TABLE variables just to check if it makes any difference, but the result was same (ie works fine in SQL Server 2012 but not in SQL Server 2008 R2) 由于前面提到的两种方法都不起作用,我尝试使用TABLE变量来检查它是否有任何区别,但结果是相同的(即在SQL Server 2012中正常工作但在SQL Server 2008 R2中没有)

BEGIN TRANSACTION [Tran1]

BEGIN TRY
    DECLARE @myTextsTable TABLE (myTextsTable_id INT, myTextsTable_text VARCHAR(MAX))
    INSERT INTO @myTextsTable(myTextsTable_id, myTextsTable_text)
    SELECT myTextsTable_id, myTextsTable_text
    FROM myTextsTable
    WHERE myTextsTable_text LIKE '%[' + CHAR(0) + CHAR(1) + CHAR(2) + CHAR(3) + CHAR(4) + CHAR(5) + CHAR(6) + CHAR(7) + CHAR(8) + CHAR(11) + CHAR(12) + 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) + ']%';

    UPDATE @myTextsTable
    SET myTextsTable_text = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(myTextsTable_text, CHAR(0), ''), CHAR(1), ''), CHAR(2), ''), CHAR(3), ''), CHAR(4), ''), CHAR(5), ''), CHAR(6), ''), CHAR(7), ''), CHAR(8), ''), CHAR(11), ''), CHAR(12), ''), 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), '')

    UPDATE myTextsTable
    SET myTextsTable_updated = GETDATE()
        ,myTextsTable_updatedby = 'As per V87058'
        ,myTextsTable_text = new.myTextsTable_text
    FROM myTextsTable
    INNER JOIN @myTextsTable new ON new.myTextsTable_id=myTextsTable.myTextsTable_id

    COMMIT TRANSACTION [Tran1];
END TRY

BEGIN CATCH
    ROLLBACK TRANSACTION [Tran1];
    --PRINT ERROR_MESSAGE();
END CATCH;

Could anyone explain why this would happen? 谁能解释为什么会这样呢? How to make this SQL query work in SQL Server 2008 R2? 如何使SQL查询在SQL Server 2008 R2中工作?

Note: I know that the string manipulations in database server/layer are not ideal and it would be recommended to do string manipulations in application layer and then save it in DB. 注意:我知道数据库服务器/层中的字符串操作并不理想,建议在应用程序层中进行字符串操作,然后将其保存在DB中。 But, I am trying to understand why this would be a problem in one version and why not in another version. 但是,我试图理解为什么这将是一个版本中的问题,为什么不在另一个版本中。

SQL Server 2012 SQL Server 2012
Microsoft SQL Server 2012 - 11.0.5058.0 (X64) Microsoft SQL Server 2012 - 11.0.5058.0(X64)
Standard Edition (64-bit) on Windows NT 6.3 (Build 9600: ) (Hypervisor) Windows NT 6.3上的标准版(64位)(Build 9600:)(管理程序)

SQL Server 2008 R2 SQL Server 2008 R2
Microsoft SQL Server 2012 - 11.0.5058.0 (X64) Microsoft SQL Server 2012 - 11.0.5058.0(X64)
Standard Edition (64-bit) on Windows NT 6.3 (Build 9600: ) (Hypervisor) Windows NT 6.3上的标准版(64位)(Build 9600:)(管理程序)

This is a known issue on SQL Server 2008 with LOB datatypes and certain collations. 这是SQL Server 2008上的已知问题 ,具有LOB数据类型和某些排序规则。

It is easy to reproduce 它很容易重现

/*Hangs on 2008*/

DECLARE @VcMax varchar(max)= char(0) + 'a'

SELECT REPLACE(@VcMax COLLATE Latin1_General_CS_AS, char(0), '')

Whilst hung it is CPU bound and seems to be in an infinite loop through these functions. 虽然挂起它是CPU绑定的,并且似乎在这些函数中处于无限循环中。

在此输入图像描述

And the fix is easy too. 修复很容易。 Either use a non MAX datatype... 要么使用非MAX数据类型......

... or a binary collation ......或二进制整理

/*Doesn't Hang*/
DECLARE @VcMax varchar(max)= char(0) + 'a'

SELECT REPLACE(@VcMax COLLATE Latin1_General_100_BIN2, char(0), '')

For anyone reading this in future, the following ways worked fine. 对于将来阅读此内容的人来说,以下方法运行良好。

Way 1. Changing the COLLATION on the VARCHAR(MAX) column in the UPDATE SQL query to BINARY COLLATION as Martin Smith suggested (please see the accepted answer). 方法1.将UPDATE SQL查询中VARCHAR(MAX)列上的COLLATION更改为BINARY COLLATION如Martin Smith所建议的那样(请参阅接受的答案)。

REPLACE(myTextsTable_text COLLATE Latin1_General_100_BIN2, CHAR(0),... REPLACE(myTextsTable_text COLLATE Latin1_General_100_BIN2,CHAR(0),...

The solution will be as below: 解决方案如下:

GO
BEGIN TRANSACTION [Tran1]

BEGIN TRY
    IF OBJECT_ID('tempdb..#myTextsTable') IS NOT NULL DROP TABLE #myTextsTable;
    SELECT myTextsTable_id, myTextsTable_text
    INTO #myTextsTable
    FROM myTextsTable
    WHERE myTextsTable_text LIKE '%[' + CHAR(0) + CHAR(1) + CHAR(2) + CHAR(3) + CHAR(4) + CHAR(5) + CHAR(6) + CHAR(7) + CHAR(8) + CHAR(11) + CHAR(12) + 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) + ']%';

    UPDATE #myTextsTable
    SET myTextsTable_text = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(myTextsTable_text COLLATE Latin1_General_100_BIN2, CHAR(0), ''), CHAR(1), ''), CHAR(2), ''), CHAR(3), ''), CHAR(4), ''), CHAR(5), ''), CHAR(6), ''), CHAR(7), ''), CHAR(8), ''), CHAR(11), ''), CHAR(12), ''), 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), '')

    UPDATE myTextsTable
    SET myTextsTable_updated = GETDATE()
        ,myTextsTable_updatedby = 'As per V87058'
        ,myTextsTable_text = new.myTextsTable_text
    FROM myTextsTable
    INNER JOIN #myTextsTable new ON new.myTextsTable_id=myTextsTable.myTextsTable_id

    DROP TABLE #myTextsTable;

    COMMIT TRANSACTION [Tran1];
END TRY

Way 2: I have created a SQL function to replace these characters with STUFF instead of using REPLACE function. 方式2:我创建了一个SQL function来用STUFF替换这些字符而不是使用REPLACE函数。

Note: Please note the SQL function is written to my specific requirement. 注意:请注意SQL函数是根据我的特定要求编写的。 As such, it only replaces characters in the following range. 因此,它只替换以下范围内的字符。

  • 00 - 08 00 - 08
  • 11 - 12 11 - 12
  • 14 - 31 14 - 31
  • 127 127

-- -

Go
CREATE FUNCTION [dbo].RemoveASCIICharactersInRange(@InputString VARCHAR(MAX))
    RETURNS VARCHAR(MAX)
    AS
    BEGIN
        IF @InputString IS NOT NULL
        BEGIN
          DECLARE @Counter INT, @TestString NVARCHAR(40)

          SET @TestString = '%[' + NCHAR(0) + NCHAR(1) + NCHAR(2) + NCHAR(3) + NCHAR(4) + NCHAR(5) + NCHAR(6) + NCHAR(7) + NCHAR(8) + NCHAR(11) + NCHAR(12) + NCHAR(14) + NCHAR(15) + NCHAR(16) + NCHAR(17) + NCHAR(18) + NCHAR(19) + NCHAR(20) + NCHAR(21) + NCHAR(22) + NCHAR(23) + NCHAR(24) + NCHAR(25) + NCHAR(26) + NCHAR(27) + NCHAR(28) + NCHAR(29) + NCHAR(30) + NCHAR(31) + NCHAR(127)+ ']%'

          SELECT @Counter = PATINDEX (@TestString, @InputString COLLATE Latin1_General_BIN)

          WHILE @Counter <> 0
          BEGIN
            SELECT @InputString = STUFF(@InputString, @Counter, 1, '')
            SELECT @Counter = PATINDEX (@TestString, @InputString COLLATE Latin1_General_BIN)
          END
        END
        RETURN(@InputString)
    END

    GO

Then, the UPDATE SQL query (in my temp table approach) will be something like below: 然后, UPDATE SQL查询(在我的临时表方法中)将如下所示:

UPDATE #myTextsTable 
SET myTextsTable_text = [dbo].RemoveASCIICharactersInRange(#myTextsTable_text)
Go

My personal preferred way would be the first one. 我个人喜欢的方式是第一个。

Probably the problem is the nesting in the replace and it is reported on the execution and not the compilación check @@nestlevel function. 可能问题是替换中的嵌套并且在执行时报告,而不是compilación检查@@ nestlevel函数。 https://technet.microsoft.com/en-us/library/ms190607(v=sql.105).aspx https://technet.microsoft.com/en-us/library/ms190607(v=sql.105).aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM