2013-06-14 2 views
2

Я пишу некоторый SQL в хранимой процедуре, чтобы уменьшить набор данных до ограниченного случайного числа строк, о котором я хочу сообщить.Использование NEWID() с помощью CTE для создания произвольного подмножества строк дает нечетные результаты

Отчет начинается с Group из Users и применяется фильтр для указания общего количества необходимых случайных строк (@SampleLimit).

Для того, чтобы достичь желаемого результата, я начать с создания КТР (временную таблицу) с:

  • top(@SampleLimit) применяется
  • group by UserId (как Идентификатор_пользователя появляется несколько раз)
  • order by NEWID() ставить результаты в случайном порядке

SQL:

; with cte_temp as 
     (select top(@SampleLimit) UserId from QueryResults 
     where (GroupId = @GroupId) 
     group by UserId order by NEWID()) 

Как только у меня есть этот результирующий набор, я удаляю любые результаты, когда UserId равен NOT IN CTE, созданному на предыдущем шаге.

delete QueryResults 
where (GroupId = @GroupId) and (UserId not in(select UserId from cte_temp)) 

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

Я пробовал разбить SQL и выполнить его вне приложения, и я не могу воспроизвести проблему.

Есть ли что-то принципиально неправильное в отношении того, что я делаю, что может объяснить, почему я иногда получаю больше результатов, которые я запрашиваю?

Для полноты - мое повторно учитываться решение, основанное на ниже ответа:

select top(@SampleLimit) UserId into #T1 
from QueryResults 
where (GroupId = @GroupId) 
group by UserId 
order by NEWID() 

delete QueryResults 
where (GroupId = @GroupId) and (UserId not in(select UserId from #T1)) 
+0

Я хотел бы предложить, что 'SELECT DISTINCT TOP (@SampleLimit) ...' будет работать быстрее, чем 'GROUP BY'. – Stoleg

+0

Получите больше результатов, оставшихся после того, как вы «УДАЛИТЬ ... ГДЕ UserID not IN (...)»? – Stoleg

+0

@Stoleg да, удалять оставляют больше пользователей, чем я указал.Я проверю план выполнения для вашего предложения выше – Tanner

ответ

5

Это undeterministic сколько раз будет выполняться SELECT заявления с участием NEWID().

Если вы получите вложенные циклы анти полу соединения между QueryResults и и нет золотник в плане он, вероятно, будет пересматриваться столько раз, сколько строк в QueryResults это означает, что для каждой внешней строки множество который сравнивается с NOT IN, может быть совершенно иным.

Вместо использования CTE вы можете материализовать результаты во временную таблицу, чтобы избежать этого.

INSERT INTO #T 
SELECT TOP(@SampleLimit) UserId 
FROM QueryResults 
WHERE (GroupId = @GroupId) 
GROUP BY UserId 
ORDER BY NEWID() 

Тогда ссылка, что в DELETE

+0

. Я проверю это, спасибо за предложение – Tanner

+0

. Это похоже на работать. Я сделаю еще несколько тестов и подтвержу это в ближайшее время, но у меня нет неправильного подсчета с момента реализации вышеизложенного. – Tanner

+0

Спасибо за ответ, он исправил проблему, и я переустановил ее в один запрос на удаление, который я опубликовал с вопросом о полноте. – Tanner