У меня огромная разница во времени выполнения между 1-минутным и тем же запросом в табличной функции.
Но самое утомительное - это запуск UDF с другим (действительным) аргументом company_id.
дает мне результат через ~ 40 секунд, и как только я изменяю этот company_id на 12 (снова действует), он никогда не останавливается. Планы выполнения этих двух запросов абсолютно не совпадают и, конечно, длинный является наиболее сложным. НО план выполнения между пакетной версией и версией UDF одинаков И И пакетная версия быстрая ...!
Если я выполняю следующий запрос «вручную», время выполнения составляет 1 мин 36 с 306 строками:
SELECT
dbo.date_only(Call.date) AS date,
count(DISTINCT customer_id) AS new_customers
FROM
Call
LEFT OUTER JOIN
dbo.company_new_customers(12, 2009, 2009) new_customers
ON dbo.date_only(new_customers.date) = dbo.date_only(Call.date)
WHERE
company_id = 12
AND year(Call.date) >= 2009
AND year(Call.date) <= 2009
GROUP BY
dbo.date_only(Call.date)
Я сохранил этот же запрос в функции и запустил его так:
SELECT * FROM company_new_customers_count(12, 2009, 2009)
13 минут пока он работает ... И я уверен, что он никогда не даст мне никакого результата.
Вчера у меня было такое же поведение, похожее на бесконечный цикл, в течение более 4 часов (поэтому я остановил его).
Вот определение функции:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION company_new_customers_count
(
@company_id int,
@start_year int,
@end_year int
)
RETURNS TABLE
AS
RETURN
(
SELECT
dbo.date_only(Call.date) AS date,
count(DISTINCT customer_id) AS new_customers
FROM
Call
LEFT OUTER JOIN
dbo.company_new_customers(@company_id, @start_year, @end_year) new_customers
ON dbo.date_only(new_customers.date) = dbo.date_only(Call.date)
WHERE
company_id = @company_id
AND year(Call.date) >= @start_year
AND year(Call.date) <= @end_year
GROUP BY
dbo.date_only(Call.date)
)
GO
Я был бы очень рад понять, что происходит.
Спасибо
Дополнительно:
Определение company_new_customers:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Description: Create the list of new customers of @company_id
-- in the given period.
-- =============================================
CREATE FUNCTION company_new_customers
(
@company_id int,
@start_year int,
@end_year int
)
RETURNS TABLE
AS
RETURN
(
SELECT
customer_id,
date
FROM
( -- select apparition dates of cutomers before @end_year
SELECT
min(date) AS date,
customer_id
FROM
Call
JOIN
Call_Customer ON Call_Customer.call_id = Call.call_id
WHERE
company_id = @company_id
AND year(date) <= @end_year
GROUP BY
customer_id
) new_customers
WHERE
year(date) >= @start_year -- select apparition dates of cutomers after @start_year
)
GO
Определение даты только:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Julio Guerra
-- Create date: 14/10/2010
-- Description: Return only the date part of a datetime value
-- Example: date_only('2010-10-25 13:00:12') returns 2010-10-25
-- =============================================
CREATE FUNCTION date_only
(
@datetime datetime
)
RETURNS datetime
AS
BEGIN
RETURN dateadd(dd, 0, datediff(dd, 0, @datetime))
END
GO
План выполнения SELECT * ИЗ company_new_customers_count (8, 2009, 2009)
План выполнения SELECT * ОТ company_new_customers_count (12, 2009, 2009)