Помогите с медленной UDF в SQL Server 2005 - PullRequest
1 голос
/ 16 мая 2009

У меня есть таблица дат call [BadDates], в ней всего один столбец, в котором каждая запись является датой, которую следует исключить. У меня есть UDF следующим образом:

CREATE FUNCTION [dbo].[udf_GetDateInBusinessDays]
(
  @StartDate datetime,  --Start Date
  @NumberDays int           --Good days ahead
)
RETURNS datetime
AS
BEGIN
-- Declare the return variable here
DECLARE @ReturnDate datetime
SET @ReturnDate = @StartDate
DECLARE @Counter int
SET @Counter = 0
WHILE   @Counter < @NumberDays
BEGIN
    SET @ReturnDate = DateAdd(d,1,@ReturnDate)
    IF ((SELECT COUNT(ID)
        FROM dbo.[BadDates]
        WHERE StartDate = @ReturnDate) = 0)
    BEGIN
        SET @Counter = @Counter + 1
    END
END
RETURN @ReturnDate
END

Этот UDF отлично работает, но он медленно обрабатывается. Хранимая процедура, которая использует это, запускает UDF в каждой записи. Существуют ли другие способы обеспечить такую ​​же функциональность более быстрым способом.

Любая помощь очень ценится!

Ответы [ 5 ]

2 голосов
/ 16 мая 2009

Я не проверял это, но теоретически это должно работать. Я складываю количество дней. Затем я проверяю, были ли в этом диапазоне какие-нибудь плохие даты. Если есть, я добавляю количество плохих дней и проверяю, были ли еще плохие даты в диапазоне, который я только что добавил. Повторяйте до тех пор, пока не наступят плохие даты.

CREATE FUNCTION [dbo].[udf_GetDateInBusinessDays]
(
  @StartDate datetime,  --Start Date
  @NumberDays int           --Good days ahead
)
RETURNS datetime
AS
BEGIN
-- Declare the return variable here
DECLARE @ReturnDate datetime
SET @ReturnDate = dateadd(d, @NumberDays, @StartDate);


DECLARE @d int;
SET @d = (select count(1) from baddates where startdate >= @StartDate and startdate <= @ReturnDate);

declare @t datetime;

WHILE   @d > 0
BEGIN
    set @t = @ReturnDate;
    set @ReturnDate = dateadd(d, @d, @ReturnDate);
    SET @d = (select count(1) from baddates where startdate > @t and startdate <= @ReturnDate);
END

RETURN @ReturnDate
END
2 голосов
/ 16 мая 2009

Я предполагаю, что вы пытаетесь вычислить дату, которая составляет x рабочих дней после данной даты, например. какая дата 10 рабочих дней с сегодняшнего дня. Я также предполагаю, что ваша таблица плохих дат содержит нерабочие дни, например, Выходные и праздничные дни.

В прошлом я сталкивался с аналогичными требованиями и обычно заканчивался таблицей дней, которая содержит все возможные даты вместе с флагом, указывающим, является ли конкретная дата рабочим днем ​​или нет.

Затем я использую эту таблицу, чтобы вычислить, какая дата составляет x рабочих дней от предоставленной даты, выбрав запись, которая составляет x дней после начальной даты.

Так что-то вроде этого

 CREATE TABLE all_days (  
  dated DATETIME,  
  day_state CHAR(1)  
  )

Где day_state - значение
D - Рабочий день
W - выходные
B - банковский выходной

SQL для поиска даты после x рабочих дней становится

SELECT MAX(dated)
FROM (
  SELECT TOP(@number_days) dated
  FROM all_days
  WHERE day_state = 'D'
  AND dated >= @start_date
  ORDER by dated ASC
)

Этот код не проверен, но должен дать вам общее представление. Возможно, вы не захотите проводить различие между выходными и праздничными днями. В этом случае вы можете переименовать day_state в working_day и сделать его полем BIT.

Вам следует создать составной уникальный индекс по датам и состоянию дня.

0 голосов
/ 16 мая 2009

Хорошо, почему вы рассчитываете, когда вы можете использовать ключевое слово EXISTS? Если это потому, что вы можете иметь несколько дат одного и того же типа в Badates, это кажется неправильным. COUNT, вероятно, просмотрит всю таблицу, чтобы сосчитать экземпляры startdate, когда все, что вам нужно, это исключить 1.

Вы смотрели на план запроса, чтобы увидеть, что происходит?

0 голосов
/ 16 мая 2009

Похоже, вы используете этот UDF для расчета разницы между двумя датами. Если я правильно интерпретирую это, я бы порекомендовал вам использовать встроенную функцию datediff.

0 голосов
/ 16 мая 2009

Возможно, вы захотите поместить индекс в BadDates.StartDate, но могут быть и другие, более лучшие решения.

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