Новости сайта "Упражнения по SQL" (http://www.sql-ex.ru) 233
Новости сайта "Упражнения по SQL (http://www.sql-ex.ru)"
Выпуск 233 от 14 марта 2009 г.
Новым посетителям сайта
Сайт посвящен изучению языка, с помощью которого осуществляется взаимодействие с реляционными (и не только) СУБД. Суть обучения
состоит в выполнении заданий на написание запросов к учебным базам данных; при этом система контролирует правильность выполнения заданий. В настоящее время реализованы все операторы подъязыка манипуляции данными (DML), которые включают в себя оператор извлечения данных SELECT, а также операторы модификации данных - INSERT, DELETE и UPDATE.
Мы надеемся, что справочного материала сайта окажется достаточно для самостоятельного обучения. Кроме того, свои решения вы можете обсудить на форуме сайта. Опытных же специалистов приглашаем проверить (продемонстрировать) свое мастерство и принять участие в соревновании, обеспечиваемом рейтинговой системой учета времени выполнения заданий. Фактически, рейтинг ведется на втором этапе тестирования, который начинается сейчас после решения 50-й задачи первого этапа. При подсчете рейтинга каждого участника
отбрасывается один самый худший показатель среди всех решенных им упражнений.
Демонстрация плана выполнения запроса и сравнительная оценка эффективности решений поможет вам освоить принципы оптимизации запросов, которые пригодятся на третьем рейтинговом этапе, который начинается после 138 задачи.
Имеется возможность получить сертификат по SQL DML при выполнении определенного количества заданий.
Новости сайта
§ Функциональность сайта после сбоя почти восстановлена. Еще некоторое результаты требуют корректировки, и я буду продолжать этим заниматься.
§ Ростовчан приглашаем посетить семинар, посвященный SQL Server 2008 Express. Два доклада сделает Алексей Шуленин (Майкрософт): 1. Express - бесплатная редакция SQL Server. Обзор возможностей. 2. Подготовка отчетов с помощью SQL Server. Семинар состоится 25 марта (начало в 15:40) по адресу: ул. Мильчакова 10 (здание НКТБ Пьезоприбор), Факультет высоких технологий ЮФУ, а. 514 (5 этаж)
§ Изменения среди лидеров (решенные за неделю задачи третьего этапа): 7. Ozzy (149)
§ Подошли к третьему этапу: 47. SCAT (задач 138, время 9.860)
§ Продвинулись в рейтинге: 50. _Bkmz_ (136, 4.864) 55. B o r i s (135, 188.704)
§ Новые лица в ТОР 100 и вернувшиеся туда: 91. Elz (125, 16.901)
Один возможный недостаток строк фиксированной длины заключается в том, что этот метод более чувствителен к порче данных на входе. Если Вы потеряете где-нибудь один символ или передадите неправильное значение в @itemlen, то весь список будет неправильно интерпретирован. Однако в предположении программного построения списка, это не должно быть серьезным препятствием.
Вы могли заметить, что я не приводил len(@str) к int, как делал это в inline_split_me. Это неплохая идея, и я не обнаружил какого-либо влияния на производительность в этом случае. Чтобы сделать процедуры фиксированной длины простыми для чтения, я решил убрать здесь convert.
Вы можете также вспомнить баг кэша, который я обсуждал в начале статьи. Весьма интересно, что процедуры, использующие метод фиксированной длины, кажется, не подвержены этой ошибке. Но всегда есть повод проверить все прежде, чем двигаться вперед; особенно в многопользовательской среде.
Неограниченный вход
Когда я представил inline_split_me, то отметил, что эта встраиваемая функция в большинстве случаев не обладает хорошей производительностью по причине использования операций charindex и substring со значениями типа nvarchar(MAX). Это не так для fixstring_single: метод не использует никаких операций charindex и не выполняет substring для каждого символа. Короче говоря, нет никакой потребности в версии fixstring_single с разбиениями; метод хорош и в таком виде.
Риск, что мы исчерпаем все числа, существует и здесь, но он меньше, так как используется всего по одному числу на каждый элемент списка, а не на каждый символ. Так с таблицей Numbers, приведенной выше, мы можем обработать один миллион элементов списка, что достаточно много. Однако можно написать и функцию, которая будет "водонепроницаемой" в этом отношении. Стив Касс (Steve Kass) предложил функцию, которая выполняет самосоединение таблицы Numbers, что возводит в квадрат максимально возможное
число. Таким образом, с одним миллионом чисел в таблице, Вы получаете всего 1E12 чисел для работы.
CREATE FUNCTION fixstring_multi(@str nvarchar(MAX), @itemlen tinyint)
RETURNS TABLE AS
RETURN(SELECT listpos = n1.Number + m.maxnum * (n2.Number - 1),
str = substring(@str,
@itemlen *
(n1.Number + m.maxnum * (n2.Number - 1) - 1) + 1,
@itemlen)
FROM Numbers n1
CROSS JOIN (SELECT maxnum = MAX(Number) FROM Numbers) AS m
JOIN Numbers n2 ON
@itemlen *
(n1.Number + m.maxnum * (n2.Number - 1) - 1) + 1 <=
len(@str)
WHERE n2.Number <= len(@str) / (m.maxnum * @itemlen) + 1
AND n1.Number <= CASE WHEN len(@str) / @itemlen <= m.maxnum
THEN len(@str) / @itemlen +
CASE len(@str) % @itemlen
WHEN 0 THEN 0
ELSE 1
END
ELSE m.maxnum
END
)
Это более сложная функция, чем fixstring_single, но для экономии места я оставляю в качестве упражнения читателю разобраться в том, как она работает; замечу лишь одно - что строка с CROSS JOIN спасает меня от излишнего кодирования большого числа строк в Numbers.
Вы можете подумать, что самосоединение, которое позволяет получить 1E12 чисел, должно дорого обойтись, и действительно, если ваши списки, по большей части, коротки (менее 200 элементов), то увеличение нагрузки будет значительным. Однако в моих тестах были случаи, когда fixstring_multi выигрывал у fixstring_single с большим запасом на машине с 4-мя центральными процессорами. Так же, как и в случае с inline_split_me, причина этому - параллелизм. В случае fixstring_multi, оптимизатор использует параллельное
выполнение даже для такого запроса:
SELECT * FROM fixstring_multi ('000000123000000456', 9)
Что касается inline_split_me, то оптимизатор не использует длину входного параметра для своих оценок.
Другой подход к разрешению неограниченного входа состоит, естественно, в том, чтобы выполнить разбиение. И с методом строк фиксированной длины это можно сделать при помощи встраиваемой функции:
CREATE FUNCTION fixstring_multi2(@str nvarchar(MAX), @itemlen tinyint)
RETURNS TABLE AS
RETURN(
SELECT listpos = (s.sliceno - 1) * (s.maxnum / @itemlen) + n.Number,
str = substring(s.slice, @itemlen * (n.Number - 1) + 1, @itemlen)
FROM (SELECT m.maxnum,
sliceno = n.Number,
slice = substring(@str,
(m.maxnum - m.maxnum % @itemlen) *
(n.Number - 1) + 1,
m.maxnum - m.maxnum % @itemlen)
FROM Numbers n
CROSS JOIN (SELECT maxnum = MAX(Number) FROM Numbers) AS m
WHERE n.Number <= len(@str) /
(m.maxnum - m.maxnum % @itemlen) +
CASE len(@str) % (m.maxnum - m.maxnum % @itemlen)
WHEN 0 THEN 0
ELSE 1
END) AS s
JOIN Numbers n ON n.Number <= len(s.slice) / @itemlen +
CASE len(s.slice) % @itemlen WHEN 0 THEN 0 ELSE 1 END
)
Производительность практически такая же, как и для fixstring_multi, включая хорошие показатели на многопроцессорных машинах благодаря параллелизму.
(Продолжение следует...)
Полезная информация
§ Приглашаем вас посетить новый проект - Интерактивный учебник по SQL. Ресурс позиционируется как "справочное обеспечение" для сайта SQL-EX.RU, но может использоваться и независимо от него.
§ Онлайновый выпуск рассылки можно почитать на сайте.
§ Все статьи, публикуемые в рассылке, затем выкладываются на сайте Книги и статьи по SQL.
По всем вопросам, связанным с функционированием сайта, проблемами при решении упражнений, идеями вы можете обращаться к Сергею И.Моисеенко msi77[@]yandex.ru. Вы также можете предложить свои задачи для публикации на сайте.