我创建了这个存储过程:
CREATE PROCEDURE [dbo].[GetYearsByMake]
@Make VARCHAR(50)
AS
BEGIN
SELECT DISTINCT [year]
FROM make_model
WHERE active = 1
AND isUnique = 1
AND [dbo].[ReplaceUrlEscapeChars](make) = @Make
ORDER BY [year] DESC
END
和ReplaceUrlEscapeChars是我创建的函数,用于将包含特殊字符的数据替换为单个 -
CREATE FUNCTION [dbo].[ReplaceUrlEscapeChars]
(@MyString AS VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
IF (@MyString LIKE '%[^0-9a-zA-Z\s-]%')
BEGIN
SET @MyString = Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace
(Replace(Replace(Replace(Replace(@MyString,'<','-'),'>','-'),'#','-'),'{','-'),'}','-'),'|','-'),'\','-'),'^','-'),'~','-'),'[','-'),']','-'),';','-')
,':','-'),'@','-'),'&','-'),'$','-'),'/','-'),'.','-');
END
SET @MyString = LTRIM(RTRIM(@MyString));
RETURN @MyString
END
但是当我在查询中用上面的函数替换每个字符串时,检索数据的查询很慢。
如何优化此功能?
还有其他方法可以快速获取数据吗?
答案 0 :(得分:1)
@ lad2025发布了什么是要走的路。也就是说,如果计算/持久列不是一个选项,您可以将标量udf转换为内联表值函数(itvf)。 itvf的表现要比用户定义的标量函数(标量udf)好得多,原因有很多,包括它们不会像标量函数那样杀死并行性。
你可以将你的标量udf重写为像这样的itvf:
CREATE FUNCTION dbo.itvfReplaceUrlEscapeChars(@MyString as varchar(Max))
RETURNS TABLE AS RETURN
SELECT
CASE WHEN @MyString LIKE '%[^0-9a-zA-Z\s-]%'
THEN LTRIM(RTRIM(
Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(
Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(
@MyString,'<','-'),'>','-'),'#','-'),'{','-'),'}','-'),'|','-'),'\','-')
,'^','-'),'~','-'),'[','-'),']','-'),';','-'),':','-'),'@','-'),'&','-')
,'$','-'),'/','-'),'.','-')))
ELSE LTRIM(RTRIM(@MyString))
END AS cleanedString;
GO
然后你会这样称呼:
CREATE PROC dbo.GetYearsByMake @Make VARCHAR(50)
AS
BEGIN
SELECT DISTINCT [year]
FROM make_model
CROSS APPLY dbo.itvfReplaceUrlEscapeChars(make)
WHERE active=1 AND isUnique=1
AND cleanedString = @Make
ORDER BY [year] DESC;
END
值得注意的是,使用varchar(max)数据类型非常昂贵。如果你可以使用varchar(8000)或更少,你会看到很大的性能提升。在make_model上使用过滤的非聚集索引看起来像这样也可能有所帮助:
CREATE NONCLUSTERED INDEX nc_make_model_poc ON make_model(year)
WHERE active = 1 AND isUnique = 1;
答案 1 :(得分:0)
而不是自己的功能和嵌套多个REPLACE
我会内联TRANSLATE - SQL Server 2017+
:
CREATE PROCEDURE [dbo].[GetYearsByMake] @Make VARCHAR(50)
AS
BEGIN
SELECT DISTINCT [year]
FROM make_model
WHERE active=1 AND isUnique=1
AND TRANSLATE(make, '<>#{}|','------') = @Make
ORDER BY [year] DESC;
END
<强> DBFiddle Demo 强>
更好的方法是添加名为normalized_make
的生成的持久列,并在其上创建和索引。
ALTER TABLE make_model
ADD normalized_make AS
(CAST(TRIM(TRANSLATE(make, '<>#{}|','------')) AS VARCHAR(100))) PERSISTED;
CREATE INDEX indx_name ON make_model(normalized_make);
SELECT *
FROM make_model
WHERE normalized_make = @Make;
编辑:
ALTER TABLE make_model
ADD normalized_make AS
(CAST(RTRIM(LTRIM(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace
(Replace(Replace(Replace(Replace(Make,'<','-'),'>','-'),'#','-'),'{','-'),'}','-'),'|','-'),'\','-'),'^','-'),'~','-'),'[','-'),']','-'),';','-')
,':','-'),'@','-'),'&','-'),'$','-'),'/','-'),'.','-'))) AS VARCHAR(100))) PERSISTED;
<强> DBFiddle Demo2 强>