【问题标题】:Optimal search queries最佳搜索查询
【发布时间】:2010-05-07 12:10:26
【问题描述】:

继我的上一个问题Sql Server query performance 之后,发现我在搜索查询中允许可选参数的方法不是最佳的,有没有人有关于如何处理这个问题的指南?

例如,假设我有一个应用程序表、一个客户表和一个联系人详细信息表,并且我想创建一个 SP,它允许搜索姓氏、家庭电话、手机和应用程序 ID 的部分、无或全部,我可以使用类似下面的东西:

select *
from application a inner join customer c on a.customerid = a.id
    left join contact hp on (c.id = hp.customerid and hp.contacttype = 'homephone')
    left join contact mob on (c.id = mob.customerid and mob.contacttype = 'mobile')
where (a.ID = @ID or @ID is null)
    and (c.Surname = @Surname or @Surname is null)
    and (HP.phonenumber = @Homphone or @Homephone is null)
    and (MOB.phonenumber = @Mobile or @Mobile is null)

上面使用的模式不是真实的,我不会在现实世界的场景中使用 select *,它是我感兴趣的 where 子句的构造。有没有更好的方法,动态 sql 或一种可以实现相同结果的替代方法,而不需要许多嵌套条件。一些 SP 可能有 10 - 15 条以这种方式使用的标准

【问题讨论】:

    标签: sql-server tsql


    【解决方案1】:

    对此没有“一刀切”的查询方法,您如何执行此操作会对性能产生微妙的影响。如果您不希望仅仅让查询返回正确的答案,不管它有多慢,请查看这篇文章:Dynamic Search Conditions in T-SQL by Erland Sommarskog。它涵盖了每种方法,并非常详细地给出了每种方法的优缺点。

    如果您可以确定搜索列的最小和最大可能范围,并且搜索列不是 NULL,那么您可以比 (@Search IS NULL OR Col=@Search)、see this area of the above linked article 做得更好。但是您应该阅读整篇文章,有很多变化取决于您的情况,您确实需要学习多种方法以及何时使用它们。

    另请参阅另一个最近的答案:SQL Server 2008 - Conditional Query

    【讨论】:

    • 很棒的文章,一些 DBA 告诉我动态 SQL 是邪恶的(即使使用 sp_executesql),但我自己并没有真正研究过。重写一些关键查询以使用这种方法取得了显着的改进
    【解决方案2】:

    好的,我们开始

    选项(重新编译)

    是必须的 - 否则第一个查询计划将被重用,无论参数如何匹配。抱歉,没有更好的方法。

    除此之外 - 不,抱歉。动态 SQL 可以变得更高效(通过避免使用 IS NULL 替代方案),但如果不可能的话,您基本上已经确定了它。

    使用动态 SQL,如果 HomePhone 变量为空,则基本上没有 HP.phonenumber 的一行;)

    【讨论】:

      【解决方案3】:

      在您的情况下,不同的查询将使用不同的索引。

      您应该定义一组要使用的索引,并为每个组编写单独的查询,将索引字段上的 OR 替换为 UNION ALL

      SELECT  *
      FROM    tables
      WHERE   A = @ID
              AND (c.Surname = @Surname or @Surname IS NULL)
              AND (HP.phonenumber = @Homphone or @Homephone IS NULL)
              AND (MOB.phonenumber = @Mobile or @Mobile IS NULL)
      UNION ALL
      SELECT  *
      FROM    tables
      WHERE   @ID IS NULL
              AND c.Surname = @Surname
              AND (HP.phonenumber = @Homphone or @Homephone IS NULL)
              AND (MOB.phonenumber = @Mobile or @Mobile IS NULL)
      UNION ALL
      SELECT  *
      FROM    tables
      WHERE   @ID IS NULL
              AND @Surname IS NULL
              AND (HP.phonenumber = @Homphone or @Homephone IS NULL)
              AND (MOB.phonenumber = @Mobile or @Mobile IS NULL)
      

      【讨论】:

        猜你喜欢
        • 2021-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-11
        相关资源
        最近更新 更多