Проблема с вашей функцией зависит от того, сколько раз она повторяется.Вы начинаете свой справочный день 1 января 1980 года. Таким образом, чтобы перейти к текущему состоянию, вам нужно выполнить цикл примерно 30 * 365 (11 000 раз).Я ничего не знаю о календаре Джалали, но, просматривая ваш код, кажется, что каждая дата григорианского календаря имеет ровно одно представление в системе календарей Джалали.Таким образом, вы можете заменить свою функцию (которая выполняет много циклов) простой таблицей поиска.
Чтобы построить таблицу поиска:
CREATE TABLE [dbo].[Calendar](
[Gregorian] [datetime] NOT NULL,
[Jalali] [char](10) NOT NULL,
CONSTRAINT [PK_Calendar] PRIMARY KEY CLUSTERED
(
[Gregorian] ASC,
[Jalali] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [idx_Calendar_Jalali_Gregorian] ON [dbo].[Calendar]
(
[Jalali] ASC,
[Gregorian] ASC
) ON [PRIMARY]
GO
Чтобы заполнить таблицу поиска значениями:
Declare @dd datetime
DECLARE @mahs as char(2)
DECLARE @rozs as char(2)
DECLARE @diff As int
DECLARE @i As int
DECLARE @leap As int
DECLARE @roz AS int
DECLARE @mah As int
DECLARE @sal As int
SELECT @roz = 11
SELECT @mah = 10
SELECT @sal = 1358
SELECT @diff = DateDiff("d", cast('1980/01/01' as datetime), @dd) -- leap year
SELECT @i = 1
Set @dd = '19800101'
while @dd <= '22000101'
BEGIN
SELECT @roz = @roz + 1
If @mah = 12 And ((@sal+1) - ((@sal+1)/4)*4) <> 0
If @roz > 29 BEGIN
SELECT @roz = 1
SELECT @mah = @mah + 1
End
If @mah > 12 BEGIN
SELECT @sal = @sal + 1
SELECT @mah = 1
End
If @mah > 6
If @roz > 30 BEGIN
SELECT @roz = 1
SELECT @mah = @mah + 1
End
if @mah <= 6
If @roz > 31 BEGIN
SELECT @roz = 1
SELECT @mah = @mah + 1
End
if @mah < 10
SELECT @mahs = '0' + LTRIM(RTRIM(str(@mah)))
else
SELECT @mahs = LTRIM(RTRIM(str(@mah)))
if @roz < 10
SELECT @rozs = '0' + LTRIM(RTRIM(str(@roz)))
else
SELECT @rozs = LTRIM(RTRIM(str(@roz)))
Insert Into Calendar(Gregorian, Jalali)
Select @dd, LTRIM(RTRIM(str(@sal))) + '/' + LTRIM(RTRIM(@mahs)) + '/' + LTRIM(RTRIM(@rozs))
SELECT @dd = DATEADD(day, 1, @dd)
END
Теперь вы можете упростить свою функцию до этого:
CREATE FUNCTION dbo.MiladiToShamsi
(@dd datetime)
RETURNS char(10)
AS
BEGIN
Return (Select Jalali
From dbo.Calendar
Where Gregorian = DateAdd(Day, DateDiff(Day, 0, @dd), 0)
)
END
Теперь, когда вы выполняете запрос, он должен работать лучше.Однако, если у вас есть пользовательская функция, которая выполняет доступ к таблице, как эта, производительность все равно может снизиться, поскольку SQL Server будет обращаться к таблице один раз для каждого вызова функции.Вместо этого было бы лучше вообще не использовать эту функцию.Теперь, когда есть справочная таблица, вы можете просто присоединиться к ней (3 раза), чтобы получить все конверсии, например:
select Id,
StartDate.Jalali As StartDate,
FinishDate.Jalali As FinishDate,
AlarmDate.Jalali As AlarmDate
From MyTable
Inner Join Calendar As StartDate
On MyTable.StartDate = StartDate.Gregorian
Inner Join Calendar As FinishDate
On MyTable.FinishDate = FinishDate.Greogorian
Inner Join Calendar As AlarmDate
On MyTable.AlarmDate = AlarmDate.Gregorian
В своем исходном сообщении вы сказали, что на это ушло более 2минут, чтобы получить ваши результаты.Если вы решите последовать моему совету, мне было бы интересно узнать, сколько времени займет описанный мною метод.Я абсолютно уверен, что это будет быстрее, чем ваш текущий метод.