使用Like(SQL Server 2005/8)从列组合中查询数据

使用Like(SQL Server 2005/8)从列组合中查询数据,sql,sql-server-2008,sql-server-2005,tsql,Sql,Sql Server 2008,Sql Server 2005,Tsql,我有一个大约有15列的表,可以用不同的组合进行查询。例如,表列是UserID、LocationID、DepartmentID、CoOrdinate1、CoOrdinate2、CoOrdinate3…CoOrdinate15 为了加快数据组合的检索速度,我们创建了一个计算字段,在其中以以下格式存储这些列的值:UserID::LocationID::DepartmentID::CoOrdinate1:…:CoOrdinate15:-示例值如下:1:100:20:22:39:94:29:…:9: 虽然

我有一个大约有15列的表,可以用不同的组合进行查询。例如,表列是UserID、LocationID、DepartmentID、CoOrdinate1、CoOrdinate2、CoOrdinate3…CoOrdinate15

为了加快数据组合的检索速度,我们创建了一个计算字段,在其中以以下格式存储这些列的值:UserID::LocationID::DepartmentID::CoOrdinate1:…:CoOrdinate15:-示例值如下:1:100:20:22:39:94:29:…:9:

虽然这对于检索索引键与=运算符匹配的数据很好,但我们正在探索获取组合的最佳方法

例如,如果用户查询UserID=1和CoOrdinate=15,我们计划构建一个类似的条件“%$


SQL Server正在执行索引扫描以检索数据。从性能的角度来看——是否有更好的方法来解决这个问题。

计算字段毫无意义。LIKE查询非常慢。一个表上可以有多个索引,根据需要包括多个列。依赖SQL Server自己的索引比尝试使用自己的索引要好得多。

构建where子句通常从where 1=1开始,并将每个相关部分附加为and xx_字段='value'或and xx_字段,如'%value%'

尝试简单的方法,我将其包装到SP中:

CREATE PROC Find
@UserId int,
@LocationId int,
....
@CoOrdinate15 int
WITH RECOMPILE
AS
BEGIN
  SET NOCOUNT ON;

  SELECT [what you need]
  FROM YourTable
  WHERE 
      (@UserId IS NULL OR UserId = @UserId) 
  AND (@LocationId IS NULL OR LocationId = @LocationId)
  ...
  AND (@CoOrdinate15 IS NULL OR CoOrdinate15  = @CoOrdinate15)
END

重新编译会使Sql Server的优化器在考虑空值参数的情况下仔细地采用对SP的每个调用,并为每个调用选择正确的索引。前导的类似通配符的搜索永远是垃圾

你真的需要彻底的搜索灵活性吗


如果要查找“%”:1::%:%:%:%:%:%:%:%:%:%::15:%”,则应使用其中的x=1和y=15进行正确搜索,并添加适当的索引。

根据提供的信息,现有表上的每条记录似乎最多有15个数字坐标

这意味着现有表未正确标准化

我强烈建议对现有表格进行重组,使其更像:

UserID
LocationID
DepartmentID
CoOrdinate Number
CoOrdinate Value
或者,保留不带坐标字段的现有表,并添加一个新表,其中UserID、LocationID、DepartmentID组合由现有表中的键字段替换


这将允许更简单、更有效地查询数据-数字字段上的索引比长字符串字段上的索引小得多,访问速度也更快。

Erland Sommarskog对您的案例进行了非常好的分析:

让我总结一下:

查询表时,在where子句中可以有任意列组合 您可以在每一列上创建一个单独的索引,但查询只能使用其中一个索引,因为普通的b树索引无法组合 您可以在某些列的组合上创建索引,但这些索引将仅由那些具有与复合索引中的列匹配的where子句的查询使用;此外,拥有许多宽泛的综合指数会带来巨大的维护开销 由于要针对查询中的任意列组合进行筛选,所以不能选择组合索引:不能为所有可能的列组合创建组合索引 通常,这个问题的解决方案是在每个列上都有一个位图索引,因为位图索引可以组合。不幸的是,SQL Server不支持位图索引,但我听说它有一些类似的功能。我建议你研究一下:


这篇文章讨论了在连接表时位图索引的用法,但不要让它迷惑你,当你查询单个表时,它们在你的用例中也很有用。

如果你坚持使用计算字段,你应该这样构造它:

字段1=值1;字段2=值2;。。。。;fieldn=valuen

就是

UserID=123;LocationID=34;部门ID=2;坐标1=56

您可以在计算字段上定义一个

例如,如果用户查询UserID=1和CoOrdinate=15,您的where子句将是

其中包含计算字段,UserID=1,坐标=15


定义索引时,必须注意正确索引=和数字。您应该将=和数字视为单词的一部分,因此UserID=1将是索引中的一个单词

UserId字段是主键吗?否。有一个id字段是主键。+1查询涉及“%”之类的内容。。。通常不在like字段上使用索引。我们创建Computed列主要是为了创建一个包含字段中所有值的索引字段。另一个选项是创建包含所有这些列的索引。此外,在搜索所有组合时,我们必须添加18个where条件。通过添加此计算列,我们创建了1个索引并在1列上搜索。但您有18个WHERE条件,因为。。。你实际上有18个co
条件。为了提高性能,将它们连接到一个中会假定基于字符串的实现比跨多个列的索引的数据库内部实现更高效,是吗?我认为那是不对的。无论如何,尝试将连接列与LIKEs一起使用将是非常低效的。如果您使用的是RDBMS,为什么不使用它的索引功能呢?谢谢!是的,我同意当孤立地考虑这个问题时,数据库内部实现可能看起来更优化,而且是正确的方法。但是当我们考虑其他问题时,计算列给我们一个稍微优于性能和存储考虑的边。然而,我们将继续探索解决这一问题的可能性。任何情况下,类似用法的想法都会被放弃。谢谢您的回复。正如您所强调的,创建这些索引是一个问题。出于好奇-全文索引在这种情况下会有帮助吗?嗯,不是真的。至少与您为计算字段建议的格式不同。假设您要搜索LocationID=123、DepartmentID=2和CoOrdinate1=12。全文索引上的搜索结果将包含UserID=123和DepartmentID=123等记录。也就是说,每次搜索都会返回大量假阳性结果。谢谢!我们将继续探索解决这一问题的可能性。在任何情况下,都会放弃类似用法的想法。问题在于创建索引的组合。事实上,我们创建Computed列主要是为了创建一个包含字段中所有值的索引字段。这样,所有定位组合的操作都将通过索引进行。此外,我们预计此表将非常大。@stackoverflow:和?由于前导通配符,您选择的解决方案不会在索引上搜索。另请参阅Mark Bannister关于更正您的设计的回答无论如何,在我们的案例中,坐标、用户ID等来自同一个表,因此文本实际上可以是一系列数字,如180 175 200 199。。。搜索条件可以是containsComputered_字段,180和200。非常感谢。