最长的NVARCHAR值传递给标量函数

时间:2016-04-03 03:18:39

标签: sql sql-server function scalar nvarchar

我有一个声明为NVARCHAR(MAX)的字段,我从表中提取。在大多数情况下,长度小于1,000个字符。但是,该字段可以包含一些HTML文本,因此我使用我编写的标量函数来删除HTML文本。在非常长的字符串(例如,600,000个字符)上,剥离HTML文本的调用就在那里(我假设因为这是通过标量函数传递的大量数据)。它将最终返回 - 大约15分钟后,因为需要很长时间才能进行标量调用。

这是表:

CREATE TABLE [dbo].[TextHolder](
    [fldClaimTextID] [int] IDENTITY(1,1) NOT NULL,
    [fldText] [nvarchar](max) NULL,
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

假设该表有数据(我的数据有2.5亿行)。 99.99%的fldText实例少于1,000个字符。

因此,使用以下查询,对99,000%的基本标量函数的调用就像魅力一样:

SELECT
    dbo.udf_StripHTML(fldText)
    ,LEN(fldText) AS fldLength
FROM
    TextHolder

以下是我的2.5亿左右记录中23条记录的数据样本,其中两条结果(第8行和第18行)很长。

fldLength
285
459
132
141
137
187
129
619182
173
327
433
643
132
141
136
187
129
690123
465
428
237
243
178

所以,我现在唯一的解决方案是截断对udf_StripHTML的调用,这是次优的。请参阅下面的示例,其中我只在字段长度少于20,000个字符时删除HTML):

SELECT
    CASE WHEN LEN(fldText) > 20000 THEN fldText ELSE dbo.udf_StripHTML(fldText) END
    ,LEN(fldText) AS fldLength
FROM
    TextHolder

如何在不花费很长时间的情况下将600,000个字符长的nvarchar传递给标量函数。

旁注,我正在使用256GB内存的4处理器盒上运行,全部专用于SQL Server,绑定在20GB / s SAN上,因此我没有实际的硬件限制。

我很感激任何想法。谢谢!

更新:

这是功能:

ALTER FUNCTION [dbo].[udf_StripHTML]
(
@HTMLText varchar(MAX)
)
RETURNS varchar(MAX)
AS
BEGIN
DECLARE @Start  int
DECLARE @End    int
DECLARE @strippedString nvarchar(MAX) = N''
DECLARE @currentChar nvarchar
DECLARE @ignoreCharacter bit = 0

-- Replace any <br> tags with a newline characters
SET @Start = 0
SET @End = LEN(@HTMLText)

-- This is an incremental algorithm that traverses the string only once, which means that it should be fast. It basically starts at the 0th character, going through
-- the entire string. When it finds a starting "<", it sets a flag to ignore all characters until it finds a closing ">" (if it never finds one, it truncates the rest
-- of the string. We only add characters to the return string when the ignore flag is turned off.
WHILE @Start < @End
    BEGIN
        SET @currentChar = SUBSTRING(@HTMLText,@Start,1)

        -- Found a starting bracket, so turn on the ignore flag
        IF @currentChar = N'<'
            SET @ignoreCharacter = 1
        -- Found an ending bracket, so turn off the ignore flag
        ELSE IF @currentChar = N'>'
            SET @ignoreCharacter = 0
        ELSE
            -- If we have a non-bracket character and the ignore flag is off, then add the character to our return value
            IF @ignoreCharacter = 0
                SET @strippedString = @strippedString + @currentChar

        SET @Start = @Start + 1
    END

RETURN @strippedString

END

2 个答案:

答案 0 :(得分:0)

遗憾的是,在mssql server中没有与oracle的regexp_replace相同的东西。所以有两种解决方法。 这是here之前的回答。它不理想,但我认为性能会提高。 或者this这是将.net正则表达式带到SQL的一种方法,我认为这很容易,并且还会显着提高性能,但维护可能会变得混乱。

答案 1 :(得分:0)

我的一位朋友还有另一个建议,可能会改善您当前的解决方案。他建议你用字符分割字符串&#39;&lt;&#39;然后删除所有条目的第一部分到字符&#39;&gt;&#39;再次加入列表。