2016-04-03 4 views
0

У меня есть поле, объявленное как NVARCHAR (MAX), которое я вытаскиваю из таблицы. В большинстве случаев длина составляет менее 1000 символов. Однако поле может содержать некоторый текст HTML, поэтому я использую скалярную функцию, которую я написал, чтобы удалить текст HTML. На действительно длинных строках (например, 600 000 символов) вызов для разметки HTML-текста просто сидит там (я предполагаю, потому что это чертовски много данных для прохождения через скалярную функцию). В конце концов он вернется - примерно через 15 минут, потому что требуется много времени для выполнения скалярного вызова.Самое длинное значение NVARCHAR, переданное скалярной функции

Вот таблица:

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

Предположим, таблица содержит данные (шахта имеет 250 миллионов строк в нем). 99,99% экземпляров fldText имеют менее 1000 символов.

Так вызов основной функции скалярной работает как шарм 99,99% время, используя следующий запрос:

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

Вот выборку данных из 23 записей из моих 250 миллионов или около того, где два результата (строки 8 и 18) являются длинными.

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

Итак, мое единственное решение теперь укоротить вызов udf_StripHTML, который является неоптимальным. Далее приведен пример, где я только полоса HTML, когда поле длиной менее 20000 символов):

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

Как я могу передать NVARCHAR, что длиной 600000 символов в скалярной функции без нее занимает много времени.

Боковое замечание. Я работаю на 4-процессорном ящике с 256 ГБ памяти, все выделенное для SQL Server, привязанное к SAN 20 ГБ/с, поэтому у меня нет практических ограничений аппаратного обеспечения.

Я ценю любые мысли. Благодаря!

UPDATE:

Вот функция:

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 
+0

* Передача * аргумента скалярной функции вряд ли будет проблемой (хотя, честно говоря, я только передал строковые значения до пары сотен тысяч байтов в SQL Server). Проблема заключается в базовой обработке функции, поэтому вам нужно включить тело функции в вопрос. –

+0

Если функция является шеей бутылки, вы можете попробовать ее оптимизировать. Вы также можете сохранить разделенную версию текста. – Vincent

+0

Кажется, что все в порядке с 200 000 символов. Около 600 000, все получилось плохо. Я думал о сохранении разделенной версии, но общий объем данных составляет около 190 ГБ. –

ответ

0

, к сожалению, не эквивалентно regexp_replace оракула в MSSQL сервере. поэтому есть два метода обхода. Этот here как было ранее. это не идеально, но я думаю, что производительность улучшится. Или this, который является способом приведения регулярных выражений .net в SQL, который, по моему мнению, прост, а также значительно улучшит производительность, но обслуживание может стать беспорядочным.

+0

Я закончил писать функцию CLR, но спасибо за ссылку на проект регулярного выражения. Хорошая вещь! –

0

У моего друга также есть другое предложение, которое может улучшить ваше текущее решение. он предлагает вам разделить строку с символом «<», а затем удалить первую часть всех записей символу «>», чтобы снова присоединиться к списку.