Database
 sql >> Base de Dados >  >> RDS >> Database

Separando Strings:Um Acompanhamento


Houve muitos comentários após meu post na semana passada sobre divisão de strings. Acho que o ponto do artigo não era tão óbvio quanto poderia ter sido:gastar muito tempo e esforço tentando "aperfeiçoar" uma função de divisão inerentemente lenta baseada em T-SQL não seria benéfico. Desde então, coletei a versão mais recente da função de divisão de strings de Jeff Moden e a coloquei contra as outras:
ALTER FUNCTION [dbo].[DelimitedSplitN4K]
(@pString NVARCHAR(4000), @pDelimiter NCHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
  WITH E1(N) AS (
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
  ),
  E2(N) AS (SELECT 1 FROM E1 a, E1 b),
  E4(N) AS (SELECT 1 FROM E2 a, E2 b), 
  cteTally(N) AS (SELECT TOP (ISNULL(DATALENGTH(@pString)/2,0)) 
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4),
  cteStart(N1) AS (SELECT 1 UNION ALL 
    SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
  ),
cteLen(N1,L1) AS(SELECT s.N1,
    ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,4000)
    FROM cteStart s
  )
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
        Item       = SUBSTRING(@pString, l.N1, l.L1)
   FROM cteLen l;
GO

(As únicas alterações que fiz:formatei para exibição e removi os comentários. Você pode recuperar a fonte original aqui.)

Eu tive que fazer alguns ajustes em meus testes para representar de maneira justa a função de Jeff. Mais importante:tive que descartar todas as amostras que envolviam strings> 4.000 caracteres. Então, alterei as strings de 5.000 caracteres na tabela dbo.strings para 4.000 caracteres e foquei apenas nos três primeiros cenários não MAX (mantendo os resultados anteriores para os dois primeiros e executando os terceiros testes novamente para o novo comprimentos de cadeia de 4.000 caracteres). Eu também eliminei a tabela de números de todos os testes, exceto um, porque ficou claro que o desempenho sempre foi pior por um fator de pelo menos 10. O gráfico a seguir mostra o desempenho das funções em cada um dos quatro testes, novamente média de mais de 10 execuções e sempre com um cache frio e buffers limpos.

Então, aqui estão meus métodos preferidos ligeiramente revisados, para cada tipo de tarefa:

Você notará que o CLR permaneceu meu método de escolha, exceto no caso em que a divisão não faz sentido. E nos casos em que CLR não é uma opção, os métodos XML e CTE são geralmente mais eficientes, exceto no caso de divisão de variável única, onde a função de Jeff pode muito bem ser a melhor opção. Mas, considerando que talvez eu precise dar suporte a mais de 4.000 caracteres, a solução da tabela Numbers pode voltar à minha lista em situações específicas em que não tenho permissão para usar o CLR.

Prometo que meu próximo post envolvendo listas não falará sobre divisão, via T-SQL ou CLR, e demonstrará como simplificar esse problema independentemente do tipo de dados.
Como aparte, notei este comentário em uma das versões das funções de Jeff que foi postado nos comentários:Agradeço também a quem escreveu o primeiro artigo que vi sobre “tabelas de números” que está localizado no seguinte URL e a Adam Machanic por me levar a isso há muitos anos.
http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an -auxiliary-numbers-table.html

Esse artigo foi escrito por mim em 2004. Então, quem adicionou o comentário à função, seja bem-vindo. :-)