Получить TOP X членов каждой группы, используя SQL Server 2005 - PullRequest
2 голосов
/ 27 июня 2009

Я видел, как этот вопрос задавался пару раз, и я написал свой собственный запрос, но он довольно медленный, и я был бы чрезвычайно признателен, если бы кто-то мог дать совет о том, как его ускорить.

В упрощенном сценарии у меня есть следующие две таблицы:

* Группа 1005 * - GroupID (первичный ключ)

Участник
- MemberID (первичный ключ)
- GroupID (внешний ключ)

Допустим, для каждого GroupID в группе я хочу найти 2 верхних значения MemberID от Member, которые имеют этот GroupID.

Вот мой текущий запрос, который работает, но мучительно медленно:

SELECT M.MemberID, M.GroupID
FROM   Member AS M
WHERE  M.MemberID in 
        (Select top 2 Member.MemberID
         FROM Member
         Where Member.GroupID = M.GroupID
         ORDER BY Member.MemberID)

Say Group имеет следующие строки
GroupID
1
2
3

и член имеет следующие строки
MemberID, GroupID
1, 1
2, 2
3, 3
4, 1
5,2
6, 3
7, 1
8,2
9, 3

Тогда мой запрос должен вернуть:
MemberID GroupID
1, 1
2, 2
3, 3
4, 1
5,2
6, 3

Ответы [ 3 ]

5 голосов
/ 27 июня 2009

Я полагаю, что зависимому вложенному запросу может быть действительно сложно оптимизировать движок db (хотя запрос @John Saunders о том, чтобы увидеть план выполнения, вполне обоснован, и просмотр того, какие у вас индексы также не повредят ;-).

Но более естественный подход к таким проблемам, связанным с ранжированием, в SQL Server 2005 и 2008 (и других механизмах SQL, поскольку эта функция используется в последних стандартах ANSI) - это ранжирование функций - RANK, DENSE_RANK или ROW_NUMBER ... они все равно эквивалентны, когда вы ранжируете по уникальному полю ;-). Даже если не считать оптимизацию, их легче читать, когда вы к ним привыкли (и более эффективны, когда ваши проблемы сложнее, чем эта), особенно с помощью этой другой аккуратной новой конструкции, предложения WITH ...:

WITH OrderedMembers AS
(
    SELECT MemberId, GroupId,
    ROW_NUMBER() OVER (PARTITION BY GroupId ORDER BY MemberId) AS RowNumber
    FROM Member 
) 
SELECT MemberId, GroupId
FROM OrderedMembers 
WHERE RowNumber <= 2
ORDER BY MemberId;
2 голосов
/ 27 июня 2009

Возможно, вы могли бы использовать функцию RANK для этого, но это может быть не быстрее. Это потому, что вы не знаете, почему ваш запрос медленный.

Почему бы не пойти узнать? Посмотрите на план выполнения. Посмотрите, есть ли сканирование таблицы? Запустите Оптимизатор запросов и посмотрите, что он скажет.

Нет смысла оптимизировать, пока вы не поймете, что не так.

0 голосов
/ 30 июня 2009

Спасибо, Джон и Алекс, за ваши ответы. Я довольно новичок в школе и очень плохо знаком с SQLServer, поэтому вариант плана выполнения был для меня совершенно новым. Он сообщил, что 96% стоимости запроса было использовано при сканировании кластерного индекса, которое, как я полагаю, было результатом вложенного запроса. По правде говоря, я не совсем уверен, каким будет следующий шаг по оптимизации.

Алекс, ваш запрос был запущен в мгновение ока к моему набору данных.

Еще раз спасибо, господа, я очень ценю вашу помощь.

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