100k строк, возвращаемых в случайном порядке, без времени ожидания SQL, пожалуйста - PullRequest
5 голосов
/ 24 февраля 2010

Хорошо,

Я много читал о возврате случайного набора строк в прошлом году, и решение, которое мы придумали, было

ORDER BY newid()

Это хорошо для <5k строк. Но когда мы получаем> 10-20 тыс. Строк, мы получаем тайм-ауты SQL, запланированное выполнение говорит мне, что 76% моей стоимости запроса приходится на эту строку. и удаление этой линии увеличивает скорость на порядок при большом количестве строк.

Наши пользователи должны выполнять до 100 тыс. Строк одновременно, как это.

Чтобы дать вам немного больше подробностей.

У нас есть таблица с 2,6 миллионами 4-значных буквенно-цифровых кодов. Мы используем случайный набор из них, чтобы получить доступ к месту проведения. Например, если у нас есть событие с вместимостью 5000, случайный набор из 5000 будет извлечен из таблицы, а затем выдан каждому клиенту в виде штрих-кода, а затем приложение сканирования штрих-кода у двери с тот же список из 5000. Причина использования 4-значного буквенно-цифрового кода (а не тупо длинного числа, такого как GUID) состоит в том, что людям легко записать номер (или отправить его другу) и просто принести номер и введите его вручную, поэтому мы не хотим большого количества символов. Клиенты любят последний бит между прочим.

Есть ли лучший способ, чем ORDER BY newid(), или есть более быстрый способ получить 100 000 случайных строк из таблицы с 2,6 мил?

О, и мы используем MS SQL 2005.

Спасибо

Jo

Ответы [ 6 ]

7 голосов
/ 24 февраля 2010

Существует статья MSDN под названием « Выбор строк случайным образом из большой таблицы », в которой говорится об этой конкретной проблеме и показано ее решение (без сортировки, но вместо этого с помощью предложения WHERE в сгенерированном столбце для фильтрации). строки).

Причина, по которой ваш запрос медленный, заключается в том, что предложение ORDER BY приводит к тому, что вся таблица копируется в базу данных tempdb для сортировки.

3 голосов
/ 24 февраля 2010

Если вы хотите сгенерировать случайные 4-значные коды, почему бы просто не сгенерировать их вместо того, чтобы пытаться извлечь их из базы данных?

Создайте 100 000 уникальных номеров от 0 до 1 679 616 (это число уникальных четырехзначных буквенно-цифровых кодов, игнорируя регистр - 2,6 миллиона строк должны иметь несколько дубликатов) и преобразуйте их в свои четырехзначные коды.

1 голос
/ 24 февраля 2010

Вам не нужно сортировать.

 DECLARE @RandomNumber int
 DECLARE @Threshold float
 SELECT @RandomNumber = COUNT(*) FROM customers
 SELECT @Threshold = 50000 / @RandomNumber

 SELECT TOP 50000 * FROM customers WHERE rand() > @Threshold ORDER BY newid()
0 голосов
/ 24 февраля 2010

Вы пытались использовать% (по модулю) для данного столбца int? Не уверен, какова ваша структура таблицы, но вы могли бы сделать что-то вроде этого:

выберите топ 50000 * из твоей_таблицы где CAST ((CAST (ASCII (SUBSTRING (код места, 1,1)) как varchar (3)) + CAST (ASCII (SUBSTRING (код места, 2,1)) как varchar (3)) + CAST (ASCII (SUBSTRING (код места, 3,1)) как varchar (3)) + CAST (ASCII (SUBSTRING (код места, 4,1)) как varchar (3))) как bigint)% 500000 между 0 и 50000

Приведенный выше код возьмет все ваши буквенно-цифровые места и преобразует их в целое число, а затем разделит всю таблицу на 500 000 сегментов, из которых вы берете верхние 50000, которые находятся в диапазоне от 0 до 50000. Вы можете играть с числом после% с (500 000), и вы можете играть с ними. Это должно рандомизировать это для вас. Не уверен, что пункт где будет кусать вас на производительность, но это стоит попробовать. Кроме того, без заказа по, нет гарантии заказа (если у вас несколько процессоров и потоков).

0 голосов
/ 24 февраля 2010

Одна мысль состоит в том, чтобы разбить процесс на этапы. Добавьте столбец в таблице для идентификатора GUID, затем выполните обновление в таблице, добавив идентификаторы GUID. Это может быть сделано заранее, если это необходимо. После этого вы сможете выполнить запрос с помощью orderby для столбца GUID, чтобы получить результаты таким же образом.

0 голосов
/ 24 февраля 2010

Интересно, какова производительность, если вы замените

ORDER BY newid()

от

ORDER BY CHECKSUM(newid())
...