Хорошо,
Я делал большое чтение при возврате случайного набора строк в прошлом году, и решение, которое мы предложили, было
ORDER BY newid()
Это хорошо для <5k строки. Но когда мы добираемся> 10-20k строки, мы получаем время SQL outs, запланированное Выполнение говорит мне, что 76% моей стоимости запроса прибывают из этой строки. и удаление этой строки увеличивает скорость порядком величины, когда у нас есть большая сумма строк.
У наших пользователей есть требование выполнения до 100k строк в такое время.
Предоставлять Вам всем немного больше подробной информации.
У нас есть таблица с 2,6 миллионами 4 буквенно-цифровых кода цифры. Мы используем случайный набор их для получения записи в место проведения. Например, если у нас будет событие с 5 000 способности, то случайный набор 5000 из них будет оттянут из таблицы, затем выпущенной каждому клиенту как штрихкод, затем приложение сканирования штрихкода у двери с имеет тот же список 5000. Причина использования 4 альфа-цифровых кодов цифры (и не глупо длинное количество как GUID) состоит в том, что ему легкий для людей записать число (или SMS это другу) и просто принести число и ввели его вручную, таким образом, мы не хотим большого количества символов. Клиенты любят последний бит btw.
Есть ли лучший путь, чем ORDER BY newid()
, или есть ли более быстрый способ получить 100k случайные строки от таблицы с 2,6 миллиметрами?
О, и мы используем MS SQL 2005.
Спасибо,
Jo
Существует статья MSDN под названием "Выбор строк случайным образом из большой таблицы", в которой говорится именно об этой проблеме и показано решение (без сортировки, а с использованием предложения WHERE на сгенерированном столбце для фильтрации строк).
Причина медленной работы вашего запроса в том, что предложение ORDER BY
заставляет копировать всю таблицу в tempdb для сортировки.
Интересно, какова производительность, если вы замените
ORDER BY newid()
на
ORDER BY CHECKSUM(newid())
Если вы хотите сгенерировать случайные 4-значные коды, почему бы просто не сгенерировать их вместо того, чтобы пытаться извлечь их из базы данных?
Сгенерировать 100 тысяч уникальных чисел от 0 до 1 679 616 (что является количество уникальных четырехзначных буквенно-цифровых кодов без учета регистра (2,6 миллиона строк должны иметь несколько дубликатов) и преобразовать их в ваши четырехзначные коды.
Одна мысль состоит в том, чтобы разбить процесс на этапы. Добавьте в таблицу столбец для идентификатора GUID, затем выполните оператор обновления в таблице, добавив идентификаторы GUID. При необходимости это можно сделать заранее. После этого вы сможете выполнить запрос с помощью orderby в столбце GUID, чтобы получить результаты таким же образом.
Вам не нужно сортировать.
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()
Пробовали ли вы использовать % (modulo) для данного столбца int? Не уверен, какова структура вашей таблицы, но вы могли бы сделать что-то вроде этого:
select top 50000 * из вашей_таблицы where CAST((CAST(ASCII(SUBSTRING(venuecode,1,1)) as varchar(3))+ CAST(ASCII(SUBSTRING(venuecode,2,1)) as varchar(3))+ CAST(ASCII(SUBSTRING(venuecode,3,1))as varchar(3))+ CAST(ASCII(SUBSTRING(venuecode,4,1))as varchar(3))) as bigint) % 500000 между 0 и 50000
Приведенный выше код возьмет все ваши альфа-числовые значения и преобразует их в целое число, а затем разделит всю таблицу на 500000 ведер, из которых вы возьмете 50000 лучших, которые находятся между 0 и 50000. Вы можете играть с числом после % (500 000) и с числом между ними. Это должно рандомизировать его для вас. Не уверен, что условие where повлияет на производительность, но попробовать стоит. Кроме того, без order by нет гарантии порядка (если у вас несколько процессоров и потоков).