【问题标题】:faster way to do this select query执行此选择查询的更快方法
【发布时间】:2009-09-01 19:50:41
【问题描述】:

假设员工有三列 名字、姓氏和 ID。

查询应首先在 firstname 中搜索姓名,仅在未找到时搜索姓氏。

所以选择 *from Employee where FirstName = 'test%' or lastname='test'%'。不会工作。

下面的查询将起作用。

select FirstName, LastName, ID
from EMPLOYEE
WHERE 
    LastName = 'Test%'
    AND
    (COUNT(SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%')=0)
    OR
    SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%'

我需要将其映射回 NHibernate,有没有一种更快更有效的方法来执行此操作,而不是进行两次数据库调用?

【问题讨论】:

  • 我真的认为你不必担心编写两个数据库调用的开销。
  • 只要 FirstName 和 LastName 都被索引,几乎任何非愚蠢的查询都会足够高效(除非您的数据库有数百万个条目)。
  • “所以选择 *from Employee where FirstName = 'test%' or Lastname='test'%'. won't work.”如果您在 FirstName 匹配时总是想要记录(无论 LastName 是什么),那么这确实是查询。详情见我的回答。

标签: sql nhibernate


【解决方案1】:

试试这个:

SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%'
OR (FirstName <> 'Test%' AND LastName = 'Test%')

【讨论】:

    【解决方案2】:
    FROM Employee
    WHERE (FirstName LIKE 'Test%' AND LastName NOT LIKE 'Test%')
    OR (LastName LIKE 'Test%' AND firstName NOT LIKE 'Test%')
    

    当然,您不在乎它们以什么顺序返回。如果记录必须返回与名字匹配的记录,然后是与姓氏匹配的名称,那么这将不起作用。

    【讨论】:

    • 在包含 4000 个条目的数据集上,这确实会快两倍,尽管您可能已经知道这一点。
    • 这是专门针对 SQL Server 的。
    • 此查询使用 HQL。我在我的系统上几乎完全做到了这一点,当然它是 Hibernate,而不是 NHibernate,并且它有效
    • 这完全是错误的:如果 FirstName 匹配(应该包含)但 LastName 也匹配怎么办?您只需丢弃这些记录。
    • 短路应该根据数据库引擎处理。
    【解决方案3】:

    “过早的优化是万恶之源”。

    您为什么要关心优化器看到的搜索是如何完成的,而不是声明您想要什么?
    这一切都归结为一个布尔真值表:当 FirstName 匹配时,您需要记录(无论 LastName 是什么,匹配或不匹配),如果 FirstName 不匹配,您需要 LastName 匹配时的记录:

    F match,   L match   => yes
    F match,   L nomatch => yes
    F nomatch, L match   => yes
    F nomatch, L nomatch => no
    

    这正是 OR 条件:(FirstName matching) OR (LastName matching);唯一丢弃的记录是 FirstName 和 LastName 不匹配时。

    布尔优化将确保当第一个条件为真时,甚至不评估第二个条件。

    所以你的查询是:

    SELECT FirstName, LastName, ID
    FROM Employee
    WHERE (FirstName LIKE 'Test%')
       OR (LastName LIKE 'Test%')
    

    更新:如果发现只有名字的记录确实不返回任何姓氏匹配,我可能误解了目标...
    无论如何,过早优化的立场仍然有效...
    您需要以某种方式进行 2 次查询,因为在您确定在 FirstName 上没有任何匹配项之前,您无法判断是否要考虑 LastName。但是有了适当的索引和统计信息,优化器会使其非常高效。

    查询:

    SELECT FirstName, LastName, ID
    FROM   Employee 
    WHERE  (FirstName LIKE 'Test%')
        OR (LastName LIKE 'Test%'
            AND (SELECT Count(ID)
                 FROM   Employee
                 WHERE  FirstName LIKE 'Test%') = 0) 
    

    只比以前贵一点。

    【讨论】:

      【解决方案4】:
      Select * 
      From Employee 
      Where FirstName Like @Text + '%'
      
      Union
      
      Select * 
      From Employee 
      Where LastName Like @Text + '%';
      

      【讨论】:

      • 我没有投反对票,但我认为这不能回答问题。 "查询应该首先搜索名字中的名字,只有在没有找到的情况下才搜索姓氏。"
      • 这将达到目的而无需程序化。
      • 您的答案与他作为非工作解决方案给出的示例的作用相同(除了使用 UNION 而不是 OR)。
      • 这甚至可以处理像“John Johnson”这样的案例:)
      • 这相当于“select * from Employee where FirstName like 'test%' or LastName like 'test'%'”——他说他不想这样做。如果名字匹配,他根本不想看姓氏。
      【解决方案5】:

      我认为这些查询中的任何一个都不能回答这个问题。我的理解是,搜索“John%”应该返回姓氏为 John、Johnson 等的员工。仅当没有名字为 John、Johnny 等的员工时。所有查询显示都将返回 John Adams 和 Lyndon Johnson如果表包含两者,但应该只出现 John Adams,因为只有在没有匹配的名字时才应该匹配姓氏。

      这是使用 SQL Server 语法的建议。应该可以用其他 SQL 方言来写:

      select top (1) with ties
        FirstName, LastName, ID
      from (
        select
          0 as SearchLastNames,
          FirstName, LastName, ID
        from EMPLOYEE
        where FirstName like 'Test%'
        union all
        select
          1 as SearchLastNames,
          FirstName, LastName, ID
        from EMPLOYEE
        where LastName like 'Test%'
      ) as T
      order by SearchLastNames;
      

      如果有任何匹配的名字,则最小的 SearchLastNames 值将为 0,并且 TOP (1) 与 SearchLastNames .. order by SearchLastNames 将仅返回名字匹配的信息(其中 SearchLastNames 为 0)。

      如果没有匹配的名字,则唯一的 SearchLastNames 值为 1。在这种情况下,TOP 将返回所有姓氏匹配的信息(其中 SearchLastNames 为 1),如果有的话。

      一个更笨拙但更便携的解决方案是:

        select
          FirstName, LastName, ID
        from EMPLOYEE
        where FirstName like 'Test%'
        union all
        select
          FirstName, LastName, ID
        from EMPLOYEE
        where LastName like 'Test%'
        and not exists (
          select
          FirstName, LastName, ID
          from EMPLOYEE
          where FirstName like 'Test%'
        );
      

      【讨论】:

        猜你喜欢
        • 2015-05-08
        • 2012-07-20
        • 2014-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多