需要有关如何改进SQL脚本以获得更好性能的帮助。 dbo.Products
表有一百万行。我对使用动态SQL重写它犹豫不决。谢谢!
DECLARE
@Brand varchar(MAX) = 'Brand 1, Brand 2, Brand 3',
@ItemCategory varchar(MAX) = 'IC1, IC2, IC3, IC4, IC5'
--will return all records if params where set to @Brand = NULL, @ItemCategory = NULL
SELECT
[Brand],
SUM([Amount]) AS [Amount]
FROM dbo.Products (NOLOCK)
LEFT JOIN [dbo].[Split](@Brand, ',') FilterBrand ON Brand = [FilterBrand].[Items]
LEFT JOIN [dbo].[Split](@ItemCategory, ',') FilterItemCategory ON ItemCategory = [FilterItemCategory].[Items]
WHERE
(@Brand IS NULL OR (@Brand IS NOT NULL AND [FilterBrand].[Items] IS NOT NULL)) AND
(@ItemCategory IS NULL OR (@ItemCategory IS NOT NULL AND [FilterItemCategory].[Items] IS NOT NULL))
GROUP BY
[Brand]
下面是我在网上找到的拆分表值函数:
CREATE function [dbo].[Split]
(
@String varchar(8000),
@Delimiter char(1)
)
RETURNS @Results TABLE (Items varchar(4000))
AS
BEGIN
IF (@String IS NULL OR @String = '') RETURN
DECLARE @i int, @j int
SELECT @i = 1
WHILE @i <= LEN(@String)
BEGIN
SELECT @j = CHARINDEX(@Delimiter, @String, @i)
IF @j = 0
BEGIN
SELECT @j = len(@String) + 1
END
INSERT @Results SELECT RTRIM(SUBSTRING(@String, @i, @j - @i))
SELECT @i = @j + LEN(@Delimiter)
END
RETURN
END
答案 0 :(得分:3)
以下解决方案没有使用功能
Declare @IDs Varchar(100)
SET @IDs = '2,4,6'
Select IsNull(STUFF((Select ', '+ CAST([Name] As Varchar(100)) From [TableName]
Where CharIndex(','+Convert(Varchar,[ID])+',', ','+@IDs+',')> 0
For XML Path('')),1,1,''),'') As [ColumnName]
答案 1 :(得分:0)
这是我使用的功能。我还有另一个包装它来返回我觉得有用的数值。
编辑:抱歉,至于如何提高查询的性能,我通常将值拆分为表变量并执行我的连接,但这可能不会改变您的性能,只是您的可读性。在性能方面我唯一能看到的就是你仔细检查你的连接是否产生任何东西。在两个表上有两个条件左连接,你真的无法获得更好的性能。它基本上归结为索引。
(@Brand IS NULL OR [FilterBrand].[Items] IS NOT NULL)
功能:
ALTER FUNCTION [dbo].[fn_SplitDelimittedList]
(
@DelimittedList varchar(8000),
@Delimitter varchar(20)
)
RETURNS
@List TABLE
(
Item varchar(100)
)
AS
BEGIN
DECLARE @DelimitterLength INT
SET @DelimitterLength = LEN(@Delimitter)
-- Tack on another delimitter so we get the last item properly
set @DelimittedList = @DelimittedList + @Delimitter
declare @Position int
declare @Item varchar(500)
set @Position = patindex('%' + @Delimitter + '%' , @DelimittedList)
while (@Position <> 0)
begin
set @Position = @Position - 1
set @Item = LTRIM(RTRIM(left(@DelimittedList, @Position)))
INSERT INTO @List (Item) VALUES (@Item)
set @DelimittedList = stuff(@DelimittedList, 1, @Position + @DelimitterLength, '')
set @Position = patindex('%' + @Delimitter + '%' , @DelimittedList)
end
RETURN
END
答案 2 :(得分:0)
嘿,我只是尝试在不使用任何while循环的情况下创建的split函数。只需使用它代替split函数,并使用col匹配LEFT join。
ALTER function dbo.SplitString(@inputStr varchar(1000),@del varchar(5))
RETURNS @table TABLE(col varchar(100))
As
BEGIN
DECLARE @t table(col1 varchar(100))
INSERT INTO @t
select @inputStr
if CHARINDEX(@del,@inputStr,1) > 0
BEGIN
;WITH CTE as(select ROW_NUMBER() over (order by (select 0)) as id,* from @t)
,CTE1 as (
select id,ltrim(rtrim(LEFT(col1,CHARINDEX(@del,col1,1)-1))) as col,RIGHT(col1,LEN(col1)-CHARINDEX(@del,col1,1)) as rem from CTE
union all
select c.id,ltrim(rtrim(LEFT(rem,CHARINDEX(@del,rem,1)-1))) as col,RIGHT(rem,LEN(rem)-CHARINDEX(@del,rem,1))
from CTE1 c
where CHARINDEX(@del,rem,1)>0
)
INSERT INTO @table
select col from CTE1
union all
select rem from CTE1 where CHARINDEX(@del,rem,1)=0
END
ELSE
BEGIN
INSERT INTO @table
select col1 from @t
END
RETURN
END
DECLARE @Brand varchar(MAX) = 'Brand 1,Brand 2,Brand 3',
@ItemCategory varchar(MAX) = ' IC1 A ,IC2 B , IC3 C, IC4 D' --'IC1, IC2, IC3, IC4, IC5'
select * from dbo.SplitString(@ItemCategory,',')