Хотя цикл занимает много времени в SQL Server - PullRequest
0 голосов
/ 15 октября 2018

У меня есть цикл, который проверяет все имена и даты из столбца descript из таблицы tmp13 и сохраняет их как отдельные строки в другой таблице (tmp14).Проблема в том, что цикл while выполняется долго.Я не знаю, как заставить его работать быстрее.

Вот мой код, проверяющий в столбцах descript имена и дату.Descript является текстовым столбцом и может иметь несколько имен и дат.Я хочу хранить эти имена и даты в отдельных строках.

DECLARE @Id INT
DECLARE @count INT
DECLARE @product_num INT
DECLARE @REQUESTED VARCHAR(50)
DECLARE @FirstDate VARCHAR(255)
DECLARE @RequestedBy VARCHAR(255)

DECLARE @name NVARCHAR(256)
DECLARE @date NVARCHAR(256)
DECLARE @desc NVARCHAR(256)

DECLARE @dateposition INT
DECLARE @nameposition INT
DECLARE @nameend INT

SELECT @count = MAX(id) 
FROM #TMP13

SET @id = 1;

WHILE (@id <= @count)
BEGIN
    SELCET @desc = descript FROM #TMP13 WHERE Id = @Id
    SELECT @product_num = p_Num FROM #TMP13 WHERE Id = @Id
    SELECT @REQUESTED = REQUESTED FROM #TMP13 WHERE Id = @Id
    SELECT @FirstDate = DATE1 FROM #TMP13 WHERE Id = @Id
    SELECT @RequestedBy = BY1 FROM #TMP13 WHERE Id = @Id


while (patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]%',@desc) > 0)
begin
    set @dateposition = patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9]%',@desc)
    set @date = SUBSTRING(@desc,@dateposition,10)

    set @nameposition = CHARINDEX('-', @desc)+2
    set @nameend = CHARINDEX(' ', @desc, @nameposition)+1
    set @name = SUBSTRING(@desc,@nameposition,@nameend-@nameposition)

    insert into #TMP14 
    values (@Id,@product_num,@REQUESTED, @FirstDate ,@RequestedBY, @date, @name)

    set @desc = SUBSTRING(@desc,@nameend,1024)  
end

set @id = @id + 1;

end

select * from #tmp14;

--- таблица образцов

CREATE TABLE #Tmp13(
p_Num             INTEGER  NOT NULL PRIMARY KEY 
REQUESTED          varchar(50),
DATE1            VARCHAR(50),   
BY1              VARCHAR(50),
DESCRIPT         TEXT

);

INSERT INTO #tmp13( p_Num , REQUESTED, DATE1, BY1 , DESCRIPT) VALUES 
(100,'John','5/30/2017','James','05/30/2017 12:25am Eastern Standard Time - 
Mjames reported changes in the pages 05/30/2017 10:35AM JRachael agreed to 
work on the report and report to James 05/30/2017 10:00 AM James reports 
errors in page.',NULL);

INSERT INTO Table_Tasks(WO_NUM,Opendate,ClosedDate,Note) VALUES 
(200,'John','6/1/2017','Rachael','06/1/2017 3:20PM Eastern Standard Time -  
Rsubramaniam reported phone is not functional 06/1/2017 4:00PM Service took 
the phone and replaced it with new one');

OUTPUT

 Id  product_num REQUESTED FirstDate  RequestedBY date         name    date  
                                                                        Name 

 1   100          John      5/30/2017  james      5/30/2017 mjames  5/30/2017 jRachael

Ответы [ 3 ]

0 голосов
/ 15 октября 2018

Хотя циклы будут медленными, потому что это то, что происходит, когда вы используете процедурную логику для разработки на декларативном языке программирования.Для этого вы можете использовать patternSplitCM .Есть проблемы с вашими примерами данных, но это должно дать вам то, что вам нужно.

SELECT t.p_Num,
       t.REQUESTED,
       t.date1,
       t.BY1,
       parsedDate1 = MAX(CASE WHEN s.ItemNumber = 1 THEN s.Item END),
       parsedDate2 = MAX(CASE WHEN s.ItemNumber > 1 THEN s.Item END)
FROM   #Tmp13 AS t
CROSS 
APPLY    dbo.patternSplitCM(t.DESCRIPT, '[0-9/]') AS s
WHERE    s.[Matched] = 1 AND TRY_CAST(s.item AS DATE) IS NOT NULL
GROUP BY t.p_Num,t.REQUESTED, t.date1,t.BY1

Результаты:

p_Num       REQUESTED    date1        BY1       parsedDate1  parsedDate2
----------- ------------ ------------ --------- ------------ ------------
100         John         5/30/2017    James     05/30/2017   05/30/2017
200         John         6/1/2017     Rachael   06/1/2017    06/1/2017

Наконец, для оптимальной производительности вы хотите, чтобы индекс по столбцам p_Num, REQUESTED, DATE1, BY1 поддерживал предложение GROUP BY.Индекс будет выглядеть примерно так:

CREATE UNIQUE NONCLUSTERED INDEX uq_xxx ON #Tmp13(p_Num,REQUESTED,DATE1,BY1) 
--INCLUDE (DESCRIPT); -- if you can change this to VARCHAR(8000) or VARCHAR(max)

Также обратите внимание, что это скорее всего будет работать быстрее при параллельном плане выполнения.Для этого вы можете использовать TRACEFLAG 8649 или make_parallel () Адама Мачаника.

0 голосов
/ 15 октября 2018

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

SELCET @desc = descript,  @product_num = p_Num ,  @REQUESTED = REQUESTED  , @FirstDate = DATE1,  @RequestedBy = BY1  FROM #TMP13 WHERE Id = @Id

Удаление типа данных Text (устарело), ​​используйте varchar (max)

CREATE TABLE #Tmp13(
p_Num             INTEGER  NOT NULL PRIMARY KEY 
REQUESTED          varchar(50),
DATE1            VARCHAR(50),   
BY1              VARCHAR(50),
DESCRIPT        varchar(max) --TEXT
);

Используйте varchar вместоnvarchar, если возможно. (@ desc variable)

Не повторять вызов patindex в цикле

set @dateposition=999999--loop start
while (@dateposition > 0)
begin
    set @dateposition = patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9]%',@desc)
    if(@dateposition>0)begin
    ....
    end
end
0 голосов
/ 15 октября 2018

Преобразуйте вложенные циклы в два CROSS JOINED SELECTS и используйте его для вставки значений.Общая структура будет выглядеть примерно так:

INSERT INTO #TMP14 
    (Id, product_num, REQUESTED, FirstDate , RequestedBY, date, name)
SELECT ...
CROSS JOIN
SELECT ...

Теперь вам нужно превратить внешний цикл, который генерирует последовательность чисел, в один из этих операторов SELECT, и внутренний цикл, который получается в результате разбивки строки надругие операторы SELECT.

Этот вопрос SO имеет несколько ответов на первую проблему: Как создать диапазон чисел между двумя числами? .

Этот вопрос SO имеетответы на вторую проблему: Превращение разделенной запятыми строки в отдельные строки .

SQL-сервер и серверы баз данных в целом являются высокооптимизированными механизмами запросов, но не очень хороши для манипулирования таблицами впетли.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...