SQL - как эффективно выбирать отдельные записи - PullRequest
0 голосов
/ 02 октября 2011

У меня очень чувствительная к производительности база данных 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 голосов
/ 03 октября 2011

Не уверен, что я понимаю, что вы хотите, чтобы ваш запрос вернул, но в любом случае.Этот запрос даст вам пользователей в группе, которая активна в последней записи.Он использует 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
0 голосов
/ 03 октября 2011

Попробуйте это:

SELECT t.* FROM tbl t 
INNER JOIN (
    SELECT MAX(id) id
    FROM tbl
    GROUP BY userid 
) m
ON t.id = m.id 
0 голосов
/ 02 октября 2011

Попробуйте это:

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

Если активное поле установлено на 1 для комбинации пользователь / группа, вы получите 1, если нет, то получите 0 для последнего состояния.

0 голосов
/ 02 октября 2011

Я не большой поклонник использования колонки "isActive", как вы это делаете.Для этого требуется два UPDATE с, чтобы изменить активное состояние, и эффект несколько раз сохраняет информацию об активном состоянии в разных записях.

Вместо этого я удалил бы поле active и сделал бы одноиз следующих двух вещей:

  1. Если у вас уже есть таблица, в которой (userid, groupid) является (или может быть) PRIMARY KEY или UNIQUE INDEX, то добавьте activeстолбец к этой таблице.Когда пользователь становится активным или неактивным по отношению к определенной группе, обновите только эту единственную запись с помощью true или false.

  2. Если такая таблица еще не существует, создайтеодин с '(userid, groupid) as the PRIMARY KEY and the field active`, а затем обработайте таблицу как указано выше.

В любом случае вам нужно только запросить эту таблицубез агрегации) для определения статуса пользователей по отношению к конкретной группе.Не менее важно то, что вы сохраняете значение true или false только один раз и вам нужно только UPDATE одно значение для изменения статуса.Наконец, эти таблицы действуют как место, в котором вы можете хранить другую информацию, относящуюся к членству этого пользователя в этой группе, которая применяется только один раз для каждого членства, а не один раз для изменения статуса.

0 голосов
/ 02 октября 2011

А как насчет вида, такого как:

createview ACTIVE as select * from USERS where Active = TRUE

Тогда достаточно будет только одного выбора из этого представления:

select user from ACTIVE where ID ....
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...