【问题标题】:Can I optimize this sql Query?我可以优化这个 sql 查询吗?
【发布时间】:2011-04-25 00:24:27
【问题描述】:

下面是我正在尝试做的一个示例查询,它完成了工作,但我觉得子查询不是最好的方法。有什么指点吗?

SELECT DISTINCT
    u.UserID,   
    (SELECT COUNT(LoginID) FROM Logins WHERE Success = 1 AND UserID = u.UserID) AS Successful,
    (SELECT COUNT(LoginID) FROM Logins WHERE Success = 0 AND UserID = u.UserID) AS Unsuccessful,        
    (SELECT TOP 1 LoginDate FROM Logins WHERE UserID = u.UserID ORDER BY LoginDate DESC) AS LastLogin
FROM 
    Users u INNER JOIN 
    Logins l ON u.UserID = l.UserID

顺便说一句,上面的例子看起来不需要加入,但在真正的解决方案中,我会得到一些其他的列......

【问题讨论】:

  • 可以发一下执行计划吗?
  • 在我看来,您可以通过使用sum(if success = 0 then 1 else 0 endif) 之类的方式,在一次选择而不是三次选择中完成所有登录查询?

标签: sql sql-server sql-server-2005 optimization


【解决方案1】:

我会尝试这样的:

declare @Users Table (UserID int)
declare @Logins Table (LoginID int, UserID int, LoginDate DateTime, Success Bit)

Insert into @Users
select 1 union select 2

insert into @Logins
select 1, 1, '2010-10-13 6:00:00', 1
union
select 2, 1, '2010-10-13 7:00:00', 0
union
select 3, 1, '2010-10-13 8:00:00', 1
union
select 4, 2, '2010-10-13 6:00:00', 0
union
select 5, 2, '2010-10-13 7:00:00', 1
union
select 6, 2, '2010-10-13 9:00:00', 1
union
select 7, 2, '2010-10-13 10:00:00', 1

Select    UserID,
          [1] As Successful,
          [0] As Unsuccessful,
          LoginDate As LoginDate
From (
    SELECT
        u.UserID, 
        l.LoginID,
        l.Success,
        Max(LoginDate) Over (Partition By u.UserID) As LoginDate
    FROM @Users u 
        INNER JOIN @Logins l ON u.UserID = l.UserID
) Data Pivot (
    Count(LoginID) For Success In (
        [0], [1]
    )
) Result

【讨论】:

    【解决方案2】:

    如果这对您的情况更有效,您可以尝试:

    select
      u.UserID,   
      sum(case when l.Success = 1 then 1 else 0 end) as Successful,
      sum(case when l.Success = 0 then 1 else 0 end) as Unsuccessful,
      max(LoginDate) as LastLogin
    from 
      Users u
      inner join Logins l on l.UserID = u.UserID
    group by
      u.UserId
    

    【讨论】:

      【解决方案3】:

      我是否遗漏了一些重要的东西,或者你不能用一个聚合查询来做到这一点?

      SELECT u.UserID,
          SUM(CASE WHEN Success = 1 THEN 1 ELSE 0 END) AS Successful,
          SUM(CASE WHEN Success = 0 THEN 1 ELSE 0 END) AS Unsuccessful,
          MAX(LoginDate) AS LastLogin
      FROM Users u
      INNER JOIN Logins l on u.UserID = l.UserID
      GROUP BY u.UserID
      

      【讨论】:

      • 是的,这就是我的评论的意思。我没有给出答案,因为我不确定语法。好东西,因为我弄错了。
      • 我很想知道与我的数据透视示例相比,它的表现如何。
      • @ChaosPandion 我也很好奇。如果有人有机会进行比较,请与我们分享您的结果。
      • @OMG Ponies 嘿,通常情况正好相反。干杯。 :)
      • 仅供参考 - 我刚刚在小型生产服务器上运行了这个查询。我添加了 50,000 个用户和大约 400 万条登录记录。 djacobson 的查询运行大约需要 6 秒;我的(我已经删除了)花了将近 50 秒。 ChaosPandions 的回答也花了大约 45 秒。
      猜你喜欢
      • 2018-01-11
      • 1970-01-01
      • 1970-01-01
      • 2022-10-30
      • 2019-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-22
      相关资源
      最近更新 更多