【问题标题】:Querying data from a combination of columns using Like (SQL Server 2005/8)使用 Like (SQL Server 2005/8) 从列组合中查询数据
【发布时间】:2012-01-06 21:15:50
【问题描述】:

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

为了加快数据组合的检索,我们创建了一个 Computed 字段,我们在其中以以下格式存储这些列的值:UserID::LocationID::DepartmentID::CoOrdinate1:...:CoOrdinate15: - a样本值看起来像:1:100:20:22:39:94:29:..:9:

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

例如,如果用户查询 UserID = 1 和 CoOrdinate = 15,我们计划构建一个 Like 条件 '%:1::%::%::%::%::%::%::%: :%::15:%'。

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

【问题讨论】:

  • UserId 字段是主键吗?
  • 没有。有一个 id 字段是主键。

标签: sql sql-server-2008 sql-server-2005 tsql


【解决方案1】:

从提供的信息来看,现有表中的每条记录似乎最多有 15 个数字坐标。

这意味着现有表未正确规范化。

我强烈建议将现有表重组为更像:

UserID
LocationID
DepartmentID
CoOrdinate Number
CoOrdinate Value

(或者,保留没有 CoOrdate 字段的现有表,并添加一个新表,并将 UserID、LocationID、DepartmentID 组合替换为现有表中的键字段。)

这应该允许更简单和更有效地查询数据 - 数字字段的索引比长字符串字段的索引更小且访问速度更快。

【讨论】:

    【解决方案2】:

    那个计算域完全没有意义。 LIKE 查询非常慢。您可以在一个表上拥有多个索引,根据需要包括多个列。依赖 SQL Server 自己的索引比尝试自己创建索引要好得多。

    【讨论】:

    • +1 涉及like '%... 的查询通常根本不使用like 字段上的索引。
    • 我们创建 Computed 列主要是为了创建一个包含字段中所有值组合的索引字段。另一种选择是创建包含所有这些列的索引。此外,在搜索所有组合时,我们必须添加 18 个 where 条件。通过添加这个计算列,我们创建了 1 个索引并在 1 列上进行搜索。
    • 但是你有 18 个 WHERE 条件,因为……你实际上有 18 个条件。出于性能目的将它们连接成一个假设您的基于字符串的实现比数据库的跨多列索引的内部实现更有效,肯定吗?我不认为这是对的。无论如何,尝试将您的串联列与 LIKE 一起使用将是非常低效的。如果您使用的是 RDBMS,为什么不使用它的索引功能?
    • 谢谢!是的,我同意,当孤立地考虑问题时,数据库内部实现可能看起来更加优化并且是正确的方法。但是当我们考虑其他问题时,计算列给了我们一点优势,优先于性能(和存储)考虑。然而,我们将继续探索找到解决方案的可能性。任何情况下都放弃了 Like 使用的想法。
    【解决方案3】:

    让我总结一下:

    • 查询表时,在 where 子句中可以有一个列的任意组合
    • 您可以在每一列上创建一个单独的索引,但只有其中一个用于您的查询,因为普通的 b 树索引无法组合
    • 您可以在某些列组合上创建composite indexes,但这些索引只能由那些具有与复合索引中的列匹配的 where 子句的查询使用;此外,拥有许多广泛的复合索引会导致大量维护开销
    • 由于您要过滤查询中列的任意组合,因此不能选择复合索引:您不能为所有可能的列组合创建复合索引

    一般来说,这个问题的解决方案是在每一列上都有bitmap indexes,因为可以组合位图索引。不幸的是 SQL Server 不支持位图索引,但我听说它有一些类似的功能。我建议你调查一下:

    http://msdn.microsoft.com/en-us/library/bb522541.aspx (本文讨论了连接表时位图索引的用法,但不要让您感到困惑,当您查询单个表时,它们在您的用例中也很有用。)

    【讨论】:

    • 感谢您的回复。正如您所强调的,创建这些索引是一个问题。出于好奇 - 在这种情况下,全文索引会有所帮助吗?
    • 嗯,不是真的。至少不是您为计算字段建议的格式。假设您要搜索 LocationID=123 和 DepartmentID=2 和 CoOrdnate1=12。全文索引的搜索结果将包含 UserID=123 和 DepartmentID=123 等记录。也就是说,每次搜索都会返回大量误报结果。
    • 谢谢!将继续探索找到解决方案的可能性。任何情况下都放弃了 Like 使用的想法。
    【解决方案4】:

    尝试简单的方法,我将它包装到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
    

    RECOMPILE 使 Sql Server 的优化器在考虑 NULL 值参数的情况下精细地采用对 SP 的每次调用,并为每次调用选择正确的索引

    【讨论】:

      【解决方案5】:

      没有。前导通配符 LIKE 搜索总是很垃圾。

      真的需要完全详尽的搜索灵活性吗?

      如果您正在寻找'%:1::%::%::%::%::%::%::%::%::15:%',那么您应该使用WHERE x=1 and y=15 正确搜索并添加适当的索引。

      【讨论】:

      • 问题在于创建索引组合。事实上,我们创建 Computed 列主要是为了创建一个包含字段中所有值组合的索引字段。这样,所有定位组合的都通过索引。此外,我们预计此表会非常大。
      • @stackoverflow: 和?由于前导通配符,您选择的解决方案不会在索引上搜索。另请参阅 Mark Ba​​nnister 关于纠正您的设计的回答
      【解决方案6】:

      如果你坚持计算域,你应该这样构造它:

      "field1=value1;field2=value2;....;fieldn=valuen"

      那是

      "UserID=123;LocationID=34;DepartmentID=2;CoOrdinate1=56;..."

      您将在计算字段上定义 full text index

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

      WHERE CONTAINS(computed_field, "UserID=1" AND "CoOrdinate=15")

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

      【讨论】:

      • 无论如何,在我们的例子中,坐标、用户 ID 等都来自同一个表,因此文本实际上可以是一系列数字,例如“180 175 200 199 ...”,搜索条件可以是 WHERE CONTAINS (computed_field, "180" AND "200")。谢谢!
      【解决方案7】:

      构建 where 子句以 where 1=1 开始,并将每个相关部分附加为 and xx_field = 'value'and xx_field like '%value%'

      【讨论】:

        【解决方案8】:

        Erland Sommarskog 对您的案例进行了很好的分析:Dynamic Search Conditions in T-SQL

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-08
          • 1970-01-01
          • 2011-01-25
          • 1970-01-01
          • 1970-01-01
          • 2018-09-18
          相关资源
          最近更新 更多