2015-09-08 2 views
-1

Я создал UDF, при выполнении этой функции несколько раз, как это:выполнение функции SQL несколько раз занимают слишком много времени

select 
dbo.ufngetpercentagematch('http://www.booking.com/hotel/au/crowne-plaza-melbourne.en-gb.html','CROWNE PLAZA MELBOURNE'), 
dbo.ufngetpercentagematch('http://www.hotelclub.com/hotels/Australia--VI/Melbourne/Crowne_Plaza_MELBOURNE.h175114/','CROWNE PLAZA MELBOURNE'), 
dbo.ufngetpercentagematch('http://www.orbitz.com/hotel/Australia--VI/Melbourne/Crowne_Plaza_MELBOURNE.h175114/','CROWNE PLAZA MELBOURNE'), 
dbo.ufngetpercentagematch('http://www.tripadvisor.com/Hotel_Review-g255100-d255387-Reviews-Crowne_Plaza_Melbourne-Melbourne_Victoria.html','CROWNE PLAZA MELBOURNE') 

это занимает 7 сек. Принимая во внимание, что каждый из выбранных утверждений занимает по меньшей мере 10-15 микросекунд каждый. Может кто-нибудь сказать, почему это происходит?

Возможно, что-то не в порядке с функцией или некоторым свойством функции, которое мне не хватает?

Таблица

CREATE TABLE [dbo].[NoiseWords](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [Word] [nvarchar](500) NOT NULL, 
    [Deleted] [bit] NULL, 
CONSTRAINT [PK_NoiseWords] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

ALTER TABLE [dbo].[NoiseWords] ADD DEFAULT ((0)) FOR [Deleted] 
GO 


insert into noisewords(word) values('The') 
insert into noisewords(word) values('A') 
insert into noisewords(word) values('Hotel') 
insert into noisewords(word) values('villa') 
insert into noisewords(word) values('villas') 
insert into noisewords(word) values('resort') 
insert into noisewords(word) values('$') 
insert into noisewords(word) values('an') 
insert into noisewords(word) values('and') 
insert into noisewords(word) values('resorts') 
insert into noisewords(word) values('home') 
insert into noisewords(word) values('house') 
insert into noisewords(word) values('homes') 
insert into noisewords(word) values('houses') 
insert into noisewords(word) values('cottage') 
insert into noisewords(word) values('cottages') 
insert into noisewords(word) values('hotels') 
insert into noisewords(word) values('inn') 
insert into noisewords(word) values('inns') 
insert into noisewords(word) values('hoteles') 
insert into noisewords(word) values('guest') 
insert into noisewords(word) values('hostel') 
insert into noisewords(word) values('hostels') 
insert into noisewords(word) values('room') 
insert into noisewords(word) values('rooms') 
insert into noisewords(word) values('apartment') 
insert into noisewords(word) values('apartments') 
insert into noisewords(word) values('housing') 
insert into noisewords(word) values('lodging') 
insert into noisewords(word) values('motel') 
insert into noisewords(word) values('motels') 
insert into noisewords(word) values('roof') 
insert into noisewords(word) values('shelter') 
insert into noisewords(word) values('spa') 
insert into noisewords(word) values('spas') 
insert into noisewords(word) values('tavern') 
insert into noisewords(word) values('taverns') 
insert into noisewords(word) values('saloon') 
insert into noisewords(word) values('dormitory') 
insert into noisewords(word) values('camp') 
insert into noisewords(word) values('camps') 
insert into noisewords(word) values('cabin') 
insert into noisewords(word) values('cabins') 
insert into noisewords(word) values('suites') 
insert into noisewords(word) values('suite') 

ufnGetPercentageMatch

CREATE FUNCTION dbo.ufnGetPercentageMatch  
(@reference nvarchar(1000),  
@input nvarchar(1000))  
RETURNS decimal(6,2)  
AS  
begin  

--declare @reference nvarchar(1000)='764 4th Ave'  
--declare @input nvarchar(1000)='764 4th Ave, Brooklyn, NY, 11232, USA'  

set @input = ' '+ ltrim(rtrim(dbo.ufnRemoveNonAlphaNumericCharacters(dbo.ufnReplaceAccentChars(replace(replace(' ' + @input + ' ',' BW ',' '),' Best Western ',' ')))))+' '  
set @reference = ' '+ ltrim(rtrim(dbo.ufnRemoveNonAlphaNumericCharacters(dbo.ufnReplaceAccentChars(replace(replace(' ' + @reference + ' ' ,' BW ',' '),' Best Western ',' ')))))+' '  
--print @input  
--print @reference  
declare @max int  
declare @counter int =1  
select @max = count(1) from noisewords  
declare @query1 varchar(max)=''  
declare @query2 nvarchar(max)=''  
declare @noiseword varchar(500)=''  
declare @percmatch decimal(6,2)=0  
while @max >= @counter  
begin  
    select @noiseword=' ' + ltrim(rtrim(word)) + ' ' from noisewords where id = @counter and deleted = 0  
    set @input = replace(@input,@noiseword,' ')  
    set @reference = replace(@reference,@noiseword,' ')  
    set @counter = @counter + 1  
end  

--print @reference + '::' + @input  

declare @query nvarchar(max)  
set @query= 'select ' + @query1 + '''' + @input + '''' + @query2  

;with cte1 as  
( 
    select *  
    from  
    splitstring(@input,' ')  
),  
cte2 as  
( 
    select item,@reference as ref, case when @reference like '%'+item+'%' then 1 else 0 end as c  
    from cte1  
    where isnull(item,'')<>''  
),  
cte3 as  
( 
    select @input as inp,@reference as ref,sum(c) as sum,count(1) as total,  
    cast(sum(c) as decimal(6,2))/(cast(count(1) as decimal(6,2))) as avg  
    from cte2  
)  
select @percmatch = isnull(avg,0) from cte3  
--select * from cte2  
--print @percmatch  
RETURN(@percmatch)  
END 

ufnRemoveNonAlphaNumericCharacters

Create Function [dbo].[ufnRemoveNonAlphaNumericCharacters](@Temp VarChar(1000)) 
Returns VarChar(1000) 
AS 
Begin 

    Declare @KeepValues as varchar(50) 
    Set @KeepValues = '%[^a-z0-9 ]%' 
    While PatIndex(@KeepValues, @Temp) > 0 
     Set @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '') 

    Return @Temp 
End 

ufnReplaceAccentChars

create function [dbo].[ufnReplaceAccentChars] (@p_OriginalString varchar(max)) 
returns varchar(max) as 
begin 
    declare @ModifiedString varchar(100) = @p_OriginalString Collate SQL_Latin1_General_CP1253_CI_AI; 
    return @ModifiedString 
end 

SplitString

create FUNCTION [dbo].[SplitString] 
(  
     @Input VARCHAR(8000), 
     @Character CHAR(1) 
) 
RETURNS @Output TABLE ( 
     Item VARCHAR(1000) 
) 
AS 
BEGIN 
     DECLARE @StartIndex INT, @EndIndex INT 

     SET @StartIndex = 1 
     IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character 
     BEGIN 
      SET @Input = @Input + @Character 
     END 

     WHILE CHARINDEX(@Character, @Input) > 0 
     BEGIN 
      SET @EndIndex = CHARINDEX(@Character, @Input) 

      INSERT INTO @Output(Item) 
      SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1) 

      SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input)) 
     END 

     RETURN 
END 
+0

Проблема с производительностью связана с тем, что скалярные функции, подобные этому, являются ужасными для производительности. И когда вы вызываете скалярный udf для каждого столбца, он будет деградировать очень быстро. Возможно, вы можете преобразовать эту функцию в встроенную функцию с табличной оценкой? Просто убедитесь, что если вы выполняете функцию таблицы, то это один и только один оператор, или вы не достигнете какой-либо производительности. –

+3

Кроме того, вы не сказали нам, что 'ufngetpercentagematch' * делает *! – Jamiec

+0

@Jamiec ** ufngetpercentagematch ** получает процентное совпадение между первым и вторым входами, т. Е. Сколько из вторых входных слов присутствует на первом входе. Есть ли другой способ, которым я могу это сделать в sql? –

ответ

0

Это не полный ответ, как это было бы немного больше, чем форум может обеспечить, но вот пример конвертирования скалярных функций ufnReplaceAccentChars к значной функции инлайн таблицы. Одна логическая проблема, которую я вижу со старой функцией, заключается в том, что она получает varchar (max) и обрезает ее до 100 символов.

create function [dbo].[ufnReplaceAccentChars] 
( 
    @p_OriginalString varchar(max) 
) 
returns table as 
    return select left(@p_OriginalString, 100) Collate SQL_Latin1_General_CP1253_CI_AI as ReplacedValue; 

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

Смежные вопросы