使用多个“LIKE”优化存储过程

时间:2013-02-27 13:52:31

标签: sql sql-server sql-server-2008 tsql stored-procedures

我传入了一个以逗号分隔的值列表,我需要与数据库进行比较

以下是我传递的值的示例:

@orgList = "1123, 223%, 54%"

要使用通配符我认为我必须做LIKE但是查询运行很长时间并且只返回14行(结果是正确的,但它只是永远消失,可能是因为我正在使用连接不正确地)

我可以做得更好吗?

这就是我现在所做的:

declare @tempTable Table (SearchOrg nvarchar(max) )

insert  into @tempTable
   select * from dbo.udf_split(@orgList) as split 

-- this splits the values at the comma and puts them in a temp table

-- then I do a join on the main table and the temp table to do a like on it.... 
-- but I think it's not right because it's too long. 

select something 
from maintable gt
join @tempTable tt on gt.org like tt.SearchOrg
where
    AYEAR= ISNULL(@year, ayear)
    and (AYEAR >= ISNULL(@yearR1, ayear) and ayear <= ISNULL(@yearr2, ayear))
    and  adate = ISNULL(@Date, adate)
    and (adate  >= ISNULL(@dateR1, adate) and adate <= ISNULL(@DateR2 , adate))

最终结果将是maintable.org为1123,或以223开头或以554开头的所有行

我日期疯狂的原因是因为有时候存储过程只检查一年,有时是一年的范围,有时是特定日期,有时是日期范围......所有未使用的内容都是以null为单位

也许问题存在?

3 个答案:

答案 0 :(得分:1)

尝试这样的事情:

Declare @tempTable Table
(
   -- Since the column is a varchar(10), you don't want to use nvarchar here.
   SearchOrg varchar(20)
);

INSERT INTO @tempTable
SELECT * FROM dbo.udf_split(@orgList);

SELECT 
   something
FROM 
   maintable gt
WHERE
   some where statements go here
And
   Exists
   (
      SELECT 1
      FROM @tempTable tt
      WHERE gt.org Like tt.SearchOrg
   )

答案 1 :(得分:1)

您的查询可能难以优化。部分问题是where条款中的内容。您可能希望先过滤这些,然后使用like进行连接。或者,您可以尝试更快地进行连接,然后对结果进行全表扫描。

SQL Server应该优化形式为'abc%'的like语句 - 也就是说,通配符在最后的位置。 (例如,请参阅here。)因此,您可以从maintable.org上的索引开始。幸运的是,您的示例符合此标准。但是,如果您有'%abc' - 通配符首先出现 - 那么优化将无效。

为使索引最佳,可能还需要考虑where子句中的条件。换句话说,添加索引是暗示性的,但查询的其余部分可能会排除使用索引。

而且,让我补充一点,这些类型的搜索的最佳解决方案是使用SQL Server中的全文搜索功能(请参阅here)。

答案 2 :(得分:1)

这种带有可选过滤器的动态查询和由表(!)驱动的LIKE非常难以优化,因为几乎没有任何静态知识。优化器必须创建一个非常通用的计划。

你可以做两件事来加速大量订单

  1. 使用OPTION (RECOMPILE)进行游戏。如果编译times是可接受的,那么至少会处理所有可选的过滤器(但不能处理LIKE表)。
  2. 代码生成和EXEC sp_executesql代码。使用内联到SQL中的所有LIKE子句构建一个查询,使其看起来像这样:WHERE a LIKE @like0 OR a LIKE @like1 ...(不确定是否需要ORAND)。这允许优化器摆脱连接并只执行正常的谓词。