SQL - 如何有效地选择不同的记录

时间:2011-10-02 13:48:38

标签: sql sql-server performance sqlperformance

我有一个性能敏感的SQL Server数据库。我需要对以下问题进行有效选择:

我有一个包含4个字段的简单表:

ID [int, PK]
UserID [int, FK]
Active [bit]
GroupID [int, FK]

每个UserID可以使用GroupID(以及在几个groupID中)使用Active ='false'多次出现,但只有一次使用Active ='true'。

如:

(id,userid,active,groupid)
1,2,false,10
2,2,false,10
3,2,false,10
4,2,true,10

我需要从某个组中的表中选择所有不同的用户,它应该保持用户的最后一个活动状态。如果用户具有活动状态 - 它不应该返回用户的非活动状态,如果它在某个时间点已经存在。

天真的解决方案是双重选择 - 一个用于选择所有活动用户,然后一个用于选择所有未出现在第一个选择语句中的非活动用户(因为每个用户可能在某些用户处于非活动状态)时间点)。但是这会运行第一次选择(使用活动用户)两次 - 这是非常不需要的。

是否有任何智能方法只需要一个选择来获取所需的查询?想法?

非常感谢提前!

5 个答案:

答案 0 :(得分:0)

这样的观点怎么样:

createview ACTIVE as select * from USERS where Active = TRUE

然后从该视图中选择一个就足够了:

select user from ACTIVE where ID ....

答案 1 :(得分:0)

试试这个:

Select
   ug.GroupId,
   ug.UserId,
   max(ug.Active) LastState
from
   UserGroup ug
group by
   ug.GroupId,
   ug.UserId

如果用户/组合组合的活动字段设置为1,您将获得1,否则您将获得最后一个状态的0。

答案 2 :(得分:0)

我不像你正在做的那样使用“isActive”专栏。这需要两个UPDATE来更改活动状态,并且可以在不同记录中多次存储有关活动状态的信息。

相反,我会删除active字段并执行以下两项操作之一:

  1. 如果您已经在某个地方(userid, groupid)某个地方PRIMARY KEYUNIQUE INDEX,那么请将active列添加到该表中。当用户对特定群组变为有效或无效时,请仅使用truefalse更新该单个记录。

  2. 如果此类表尚不存在,则使用'(userid,groupid)as the PRIMARY KEY and the field active`创建一个表,然后按上述方式处理该表。

  3. 在任何一种情况下,您只需查询此表(无聚合)即可确定用户相对于特定组的状态。同样重要的是,您只存储truefalse值一次,只需要UPDATE一个值来更改状态。最后,此表充当您可以存储其他信息的位置,该信息特定于该用户在该组中的成员资格,每个成员资格仅适用一次,而不是每次更改状态一次。

答案 3 :(得分:0)

试试这个:

SELECT t.* FROM tbl t 
INNER JOIN (
    SELECT MAX(id) id
    FROM tbl
    GROUP BY userid 
) m
ON t.id = m.id 

答案 4 :(得分:0)

不确定我是否理解您希望查询返回的内容,但无论如何。此查询将为您提供最后一个条目中处于活动状态的组中的用户。它使用row_number(),因此您至少需要SQL Server 2005。

表格定义:

create table YourTable
(
  ID int identity primary key,
  UserID int,
  Active bit,
  GroupID int
)

支持查询的索引:

create index IX_YourTable_GroupID on YourTable(GroupID) include(UserID, Active)

示例数据:

insert into YourTable values
(1, 0, 10),
(1, 0, 10),
(1, 0, 10),
(1, 1, 10),
(2, 0, 10),
(2, 1, 10),
(2, 0, 10),
(3, 1, 10)

查询:

declare @GroupID int = 10

;with C as 
(
  select UserID,
         Active,
         row_number() over(partition by UserID order by ID desc) as rn
  from YourTable as T
  where T.GroupID = @GroupID
)
select UserID
from C
where rn = 1 and
      Active = 1

结果:

UserID
-----------
1
3