Производительность функции разделения строки MSSQL ужасна

У меня есть два отдельных запроса/метода и функции, поэтому я могу передать две строки в свои хранимые процедуры, которые в основном выглядят так:

1234,12346,12690812,1259081 => UPCList parameter

1234,12346,12690812,1259081 => EANList parameter

Теперь первый метод выглядит следующим образом:

create procedure [dbo].[zsp_selectallupceans_list]
(
@UPCList nvarchar(4000),
@EANList nvarchar(4000),
@Type tinyint
)
as

select DISTINCT dd.UPC,dd.EAN,dd.EBAYID as ItemID
from ThirdPartyData  as dd 
where dd.UPC in (SELECT * FROM dbo.SplitString(@UPCList)) OR
dd.EAN in (SELECT * FROM dbo.SplitString(@EANList)) and dd.Type=@Type

В сочетании с функцией splitstring, созданной в MSSQL:

create FUNCTION [dbo].[splitstring] ( @stringToSplit VARCHAR(MAX) )
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(',', @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(',', @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END

А теперь второй способ:

create procedure [dbo].[zsp_selectallupceans_listProduction]
(
@UPCList nvarchar(4000),
@EANList nvarchar(4000),
@Type tinyint
)
as


SELECT  dd.UPC,dd.EAN,dd.EBAYID as ItemID
from ThirdPartyData  as dd 
WHERE EXISTS (SELECT 1 FROM dbo.SplitStringProduction(@UPCList,',') S1 WHERE dd.UPC=S1.val) 
   OR EXISTS (SELECT 1 FROM dbo.SplitStringProduction(@EANList,',') S2 WHERE dd.EAN=S2.val) and dd.Type=@Type

А теперь второй метод splitstringProduction:

create FUNCTION [dbo].[SplitStringProduction]
(
  @string nvarchar(max),
  @delimiter nvarchar(5)
) RETURNS @t TABLE
(
  val nvarchar(500)
)
AS
BEGIN
  declare @xml xml
  set @xml = N'<root><r>' + replace(@string,@delimiter,'</r><r>') + '</r></root>'

  insert into @t(val)
  select 
    r.value('.','varchar(500)') as item
  from @xml.nodes('//root/r') as records(r)

  RETURN
END

А теперь начинается странная часть... Результаты тестов обоих методов выглядят так:

  var findEans = ctx.zsp_selectallupceans_list(formedList.UPCList, formedList.EANList, 1).ToList();
//Execution time 4.8 seconds

 var findEans = ctx.zsp_selectallupceans_listProduction(formedList.UPCList, formedList.EANList, 1).ToList();
//Execution time: 15 seconds

Насколько я понимаю, второй метод должен выполняться намного быстрее, чем первый... Но это не так... Производительность второго метода не только хуже, но и более чем в 3 раза превышает время выполнения первого. ... И я не могу понять, почему ...

Что здесь происходит, ребята? Каким будет лучший способ сократить время выполнения до ‹1 секунды?

Может кто-нибудь помочь мне здесь, пожалуйста?


person User987    schedule 25.09.2018    source источник
comment
Как выглядела производительность при тестировании исключительно с использованием SQL Server (т. е. в Management Studio, а не в C#)?   -  person mjwills    schedule 25.09.2018
comment
Попробуйте разделитель Джеффа Модена или, если вы используете SQL2016 или более позднюю версию затем попробуйте Split_String — любой из них должен работать лучше   -  person Mazhar    schedule 25.09.2018
comment
Почему вы передаете списки как одну строку и анализируете ее? Рассматривали ли вы альтернативные подходы к разбиению строк?   -  person mjwills    schedule 25.09.2018
comment
Да. Используйте табличные параметры. Разбиение строк на несколько параметров (подобных спискам) — неприятный запах. stackoverflow.com/questions/33772886/   -  person spender    schedule 25.09.2018
comment
У вас есть метод RBAR (Row-by-Agonising-Row), который SQl Server и многие другие СУБД работают очень плохо. SQL Server отлично справляется с операциями с наборами данных. @Mazhar связал 2 очень хороших альтернативы, которые будут работать намного лучше, и если вы используете SQL Server 2012/2014, вы можете использовать DelimitedSplit8K_LEAD.   -  person Larnu    schedule 25.09.2018
comment
как строка может быть там? Вы отправляете его с прикладного уровня? Если вы используете .net (например), у вас есть гораздо лучшие классы для работы со строками, такие как построитель строк - эй, вы можете использовать .net на сервере SQL, хотя я никогда этого не делал.   -  person Cato    schedule 25.09.2018
comment
@Mazhar Я читал, что нельзя использовать string_split ...?   -  person User987    schedule 25.09.2018