![]() |
+7 (495) 229-0436 | ![]() |
shopadmin@itshop.ru | 119334, г. Москва, ул. Бардина, д. 4, корп. 3 | ![]() |
![]() |
![]() |
|
|
MS SQL: генерация псевдослучайных данных с использованием newID(). Возможности и подводные камни05.12.2013 17:54
gleb_l
Известно, что встроенная функция newID() широко используется разработчиками не только по прямому назначению - то есть для генерации уникальных первичных ключей, но и в качестве средства для генерации массивов псевдослучайных данных.
Для плавающих чисел можно использовать свойство функции rand() инициализировать генератор целым числом:
Еще один интересный вариант - генерация нормально-распределенных данных. Здесь будем использовать метод Бокса-Мюллера:
Все это хорошо работает и позволяет очень быстро сгенерировать хоть десяток миллионов записей, не используя решения "в лоб" типа циклов, курсоров, или даже вставки записей по одной в базу из слоя приложения. Нужно только убедиться, что таблицы, которые вы используете как источник строк, имеют достаточную емкость, и либо увеличить количество CROSS JOIN'ов, либо использовать табличные переменные с нужным количеством строк в качестве источника. Однако, тема не только об этом. В подавляющем большинстве случаев сгенерированные строки материализуются, то есть вставляются в постоянную или временную таблицу, либо в табличную переменную. Если это так, то дальше можно не читать - материализованные данные будут работать отлично. Однако, встречаются случаи, когда вышеуказанные стейтменты используются в подзапросах. И вот здесь появляются труднообъяснимые на первый взгляд особенности поведения SQL engine. Рассмотрим их на примерах, а затем попытаемся проанализировать, почему так происходит, и как с этим бороться: Для начала просто напишем statement с newID() в subquery и запустим его несколько раз в цикле:
Теперь интереснее. Пробуем поджойнить результат из SUBQ на какую-нибудь другую таблицу. Ее можно создать, а можно поджойнить subquery на subquery - результат от этого не изменится. Пишем:
Теперь делаем невинное изменение - меняем INNER на LEFT:
Еще один тест - возвращаем INNER, но добавляем TOP / ORDER BY в первый сабквери. Зачем - об этом позже, давайте просто попробуем:
Погуглив, выясняем, что с подобным поведением периодически сталкиваются SQL-разработчики со всего мира - примеры здесь, или здесь Люди предполагают, что материализация subquery помогает. Действительно, если переписать пример, выбрав сначала записи в явном виде во временную таблицу, а затем только поджойнив, все работает нормально. Почему же на нормальную работу влияет замена INNER на LEFT, или добавление TOP / ORDER BY там, где это не нужно? Все потому же - в одном случае присутствует материализация результатов subquery, в другом - нет. Нагляднее разницу может показать анализ плана более развернутого случая, например вот этого:
Мы видим, что запрос сращивает два потока строк до вычисления значения колонки, зависящей от newID(). Это может происходить потому, что SQL engine считает, что значение, возвращаемое newID(), хоть и non-deterministic, но не изменяется в течение всего батча. Однако, это не так - и скорее всего поэтому запрос работает неправильно. Теперь меняем INNER на LEFT, и смотрим план:
Ага, LEFT JOIN заставил SQL engine выполнить Compute Scalar перед объединением потоков, поэтому наш запрос стал работать правильно. И наконец, проверим версию с добавлением TOP / ORDER BY:
Собственно, диагноз ясен. MS SQL не учитывает особенности newID(), и соответственно, неправильно строит планы, полагаясь на константное значение, возвращаемое функцией в скоупе батча. На эту особенность есть воркэраунд - заставлять SQL engine любыми способами материализовать выборку, перед тем как ее использовать в зависимых запросах. Каким способом вы будете материализовать - дело ваше, однако лучше всего, наверное, использовать табличные переменные, особенно если размер подвыборки невелик. Иначе результат, мягко говоря, не 100% гарантирован; кроме того, нет никакой гарантии, что однажды вы сами, или кто-нибудь другой не отревьюит код, выкинув "ненужные" TOP / ORDER BY или мудро заменив LEFT на INNER. Собственно, все. Удачного SQL-программирования! Ссылки по теме |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
О нас |
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.
На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям. Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе. В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.
|
119334, г. Москва, ул. Бардина, д. 4, корп. 3 +7 (495) 229-0436 shopadmin@itshop.ru |
|
© ООО "Interface Ltd." Продаем программное обеспечение с 1990 года |