Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Новости сайта "Упражнения по SQL" (http://www.sql-ex.ru) 231


Новости сайта "Упражнения по SQL (http://www.sql-ex.ru)"

Выпуск 231 от 28 февраля 2009 г.

Новым посетителям сайта

SQL Exercises Сайт посвящен изучению языка, с помощью которого осуществляется взаимодействие с реляционными (и не только) СУБД. Суть обучения состоит в выполнении заданий на написание запросов к учебным базам данных; при этом система контролирует правильность выполнения заданий. В настоящее время реализованы все операторы подъязыка манипуляции данными (DML), которые включают в себя оператор извлечения данных SELECT, а также операторы модификации данных - INSERT, DELETE и UPDATE.

Мы надеемся, что справочного материала сайта окажется достаточно для самостоятельного обучения. Кроме того, свои решения вы можете обсудить на форуме сайта. Опытных же специалистов приглашаем проверить (продемонстрировать) свое мастерство и принять участие в соревновании, обеспечиваемом рейтинговой системой учета времени выполнения заданий. Фактически, рейтинг ведется на втором этапе тестирования, который начинается сейчас после решения 50-й задачи первого этапа. При подсчете рейтинга каждого участника отбрасывается один самый худший показатель среди всех решенных им упражнений.

Демонстрация плана выполнения запроса и сравнительная оценка эффективности решений поможет вам освоить принципы оптимизации запросов, которые пригодятся на третьем рейтинговом этапе, который начинается после 138 задачи.

Имеется возможность получить сертификат по SQL DML при выполнении определенного количества заданий.


Новости сайта

§ Вчера во время подготовки рассылки исчез из сети наш хостер - netter.ru. Причины неизвестны, т.к. связи с ними нет.
Я выпущу спец.выпуск рассылки, когда что-нибудь прояснится. А пока то, что успел подготовить.

§ По многочисленным просьбам сделал пояснение к основному рейтингу TOP 100. Собираюсь сделать то же самое и для других рейтингов.

§ Fiolent добавил подсказку для задачи 75. Также написаны подсказки для задач 40 и 68, и дополнены подсказки для задач 41 и 125.

§ Дважды произошла смена лидера.
Изменения среди лидеров (решенные за неделю задачи третьего этапа):
1. Arcan (153)
2. vlksm (153)
8. lepton (151)

§ Продвинулись в рейтинге:
53. Fomichev (задач 135, время 20.347)
65. B o r i s (130, 187.773)
69. a66at (130, 5.290)
83. Pavel_yu (126, 255.136)

§ Новые лица в ТОР 100 и вернувшиеся туда:
52. SCAT (136, 7.401)

§ Продвижение ближайших претендентов на попадание в ТОР 100:
117. EffEct (121, 87.113)

§ На этой неделе сертифицированы:
Mr_Smith (A09017178) [BK] - г.Новосибирск, Россия
nonStyle (A09024170) [BK] - г.Челябинск, Россия

§ Число подписчиков - 3825

Число участников рейтинга - 19359

Число участников второго этапа - 1731

Число участников третьего этапа - 46

Сертифицировано на сайте - 354

Лучшие результаты (ТОР 20)

No Person Number of
Sel_ex
Last_Sel Number of
DML_ex
Scores Days Days_2 Days_3 S_3 LastSolved LastVisit
1 Креславский О.М. (Arcan)1 153 153 21 374 757 62.968 44.093 49 25 Feb 2009 27 Feb 2009
2 Карасёва Н.В. (vlksm)1 153 153 21 374 1024 88.313 59.250 49 23 Feb 2009 27 Feb 2009
3 Сальников С.А. ($erges)1 152 151 21 371 356 3.781 4.118 46 16 Feb 2009 27 Feb 2009
4 Сенкевич С.В. (GreyC)1 152 152 21 371 358 57.860 27.102 46 26 Jan 2009 27 Feb 2009
5 Селезнёв А.С. (Артём С.)1 150 152 21 365 444 47.248 37.524 46 25 Jan 2009 27 Feb 2009
6 Никотин В.М. (@Nikotin)1 150 150 21 365 108 8.371 3.751 40 13 Dec 2008 27 Feb 2009
7 Печатнов В.В. (pvv)1 146 149 21 352 357 30.849 17.490 36 10 Oct 2008 27 Feb 2009
8 Мурашкин И.В. (lepton)1 144 151 21 348 1066 68.477 57.992 36 21 Feb 2009 21 Feb 2009
9 Зотов П.Г. (Ozzy)8 144 153 21 348 341 93.533 111.247 36 14 Feb 2009 27 Feb 2009
10 Муллаханов Р.Х. (rem)9 149 152 21 360 483 14.427 20.056 35 05 Jan 2009 25 Feb 2009
11 Дроздков А.Н. (anddros)11 147 151 21 356 260 6.074 6.723 31 11 Feb 2009 27 Feb 2009
12 Шиндин А.В. (AlShin)10 147 150 21 355 79 20.458 7.203 30 05 Jan 2009 28 Jan 2009
13 Умрихина Е.В. (Umrikhina)13 146 146 21 353 295 13.521 15.879 28 13 Feb 2009 27 Feb 2009
14 Держальцев В.А. (MadVet)14 137 146 21 333 1257 60.783 28.482 28 24 Sep 2008 30 Dec 2008
15 Любченко В.А. (IAS56)15 136 146 21 332 615 403.343 373.617 28 11 May 2008 01 Dec 2008
16 Голубин Р.С. (Roman S. Golubin)16 141 145 21 338 1260 93.162 58.822 25 29 Jan 2009 08 Feb 2009
17 Nikolaenko A.V. (Shadow77)17 142 147 21 339 436 77.451 14.010 23 22 Oct 2008 11 Dec 2008
18 Солдатенков Ю.С. (SolYUtor)18 138 146 21 331 819 22.615 6.102 20 14 Aug 2008 23 Oct 2008
19 Белогурова К. (Katy_Ekb)19 133 143 21 321 552 10.666 4.673 18 27 Nov 2008 23 Feb 2009
20 Егоров А.Б. (ABEgorov)20 137 144 21 329 180 12.897 8.815 18 03 Aug 2008 12 Aug 2008

Лучшие результаты за неделю

No surname n_sel sel_all sel_scores dml_scores scores rating last_visit

Изучаем SQL

Массивы и списки в SQL Server 2005 (начало в вып.217-229)

Erland Sommarskog (оригинал: Arrays and Lists in SQL Server 2005 )
Перевод: Моисеенко С.И.

Очевидной проблемой этой функции является надежность. Разделенный запятыми список, который содержит более миллиона символов - очень длинная строка, но рано или поздно она все же упрется в предел. И в таком случае эта функция возвратит неправильные результаты при отсутствии какого-либо сообщения об ошибке.

Другая проблема - производительность. Как я уже отметил, charindex медленнее работает на nvarchar (MAX), чем на nvarchar (4000). И что совсем плохо, там выполняется сравнение строк посимвольно. В результате получается, что эта встроенная функция вдвое медленнее многооператорной табличной функции с разбиениями, которую мы рассмотрим в следующем разделе. Хотя вся история производительности inline_split_me является намного более сложной и весьма запутанной. Видите ли, когда я выполнял свои тесты производительности, то заметил, что я получал параллельный план при соединении с моей тестовой таблицей. Для коротких списков параллелизм, скорее, увеличивал нагрузку. Но на самых длинных тестовых строках с 10 000 элементов inline_split_me неожиданно выполнялась быстрее, чем CLR на машине с 4 центральными процессорами. (Полную информацию о тестах вы найдете в приложении.)

Получите вы параллельный план или нет, зависит от большого количества условий, но размер входного параметра входа не является одним из них. Независимо от входной строки оптимизатор предположит, что первое условие в WHERE уберет 30 % строк в таблице Numbers, то есть 300 000 в нашем случае, а второе условие для подстроки уменьшит предполагаемое число строк приблизительно до 9 500. Видимо, это в сочетании с моей тестовой таблице и привело к параллельному плану. Отсюда следует, что если входной параметр роли не играет, то значение имеет размер Numbers. Еще имеет значение подобные мелкие детали:

Number <= convert(int, len(@param))

Для типов данных MAX функции len и datalength возвращают bigint. Поскольку Numbers.Number есть int, этот столбец должен быть неявно преобразован без использования convert на len. Оптимизатор тогда решил бы это с функцией RangeSeek подобно тому, что имело место, когда varchar преобразуется к nvarchar. Само преобразование не является дорогостоящим в этом случае, но по некоторым причинам, это не дает оптимизатору выбрать параллельный план./p>

Каков практический вывод из всего этого? В большинстве случаев Вы должны избегать использования inline_split_me. Она может подойти только для длинного входного параметра, когда Вы, вероятно, извлечете пользу в результате параллельного выполнения запроса. И если Вы рассчитываете на многочисленные процессы, вызывающие вашу хранимую процедуру, которая использует inline_split_me, вряд ли Вы захотите, чтобы все они пытались использовать все центральные процессоры одновременно. Таким образом, если Вы рассматриваете возможность использования inline_split_me в целях оптимизации, необходимо протестировать ее с вашим запросом и посмотреть, какую производительность Вы получите.

Есть еще одна проблема с производительностью inline_split_me. Процедуры, которые используют эти функции, вероятно, будут подвержены ошибкам, которые я обсуждал в разделе "Проблемы кэширования однострочных функций T-SQL".

Есть способ сделать эту функцию неизменно быстрой: если Вы знаете, что ваша входная строка всегда будет вписываться в nvarchar (4000), то можете использовать этот тип данных для входного параметра. Это также решило бы проблему кэширования. Но, конечно, функция стала бы не очень надежной, и именно поэтому я не выполнял никаких тестов с nvarchar (4000) для входного параметра.

Многооператорная функция с разбиениями

Как и в случае с итерационным методом, разбиение входной строки на куски по nvarchar (4000) улучшает производительность. Вот многооператорная функция, которая делает это:

CREATE FUNCTION duo_chunk_split_me(@list  nvarchar(MAX),
                                   @delim nchar(1) = N',')
RETURNS @t TABLE (str   nvarchar(4000) NOT NULL,
                  nstr  nvarchar(4000) NOT NULL) AS
BEGIN
   DECLARE @slices TABLE (slice nvarchar(4000) NOT NULL)
   DECLARE @slice nvarchar(4000),
           @textpos int,
           @maxlen  int,
           @stoppos int

   SELECT @textpos = 1, @maxlen = 4000 - 2
   WHILE datalength(@list) / 2 - (@textpos - 1) >= @maxlen
   BEGIN
      SELECT @slice = substring(@list, @textpos, @maxlen)
      SELECT @stoppos = @maxlen -
                        charindex(@delim COLLATE Slovenian_BIN2,
                                 reverse(@slice))
      INSERT @slices (slice)
         VALUES (@delim + left(@slice, @stoppos) + @delim)
      SELECT @textpos = @textpos - 1 + @stoppos + 2
      -- On the other side of the comma.
   END
   INSERT @slices (slice)
       VALUES (@delim + substring(@list, @textpos, @maxlen) + @delim)

   ;WITH stringget (str) AS (
      SELECT ltrim(rtrim(substring(s.slice, N.Number + 1,
                charindex(@delim COLLATE Slovenian_BIN2,
                          s.slice, N.Number + 1) -
                N.Number - 1)))
       FROM  Numbers N
       JOIN  @slices s
         ON  N.Number <= len(s.slice) - 1
        AND  substring(s.slice, N.Number, 1) = @delim COLLATE Slovenian_BIN2
   )
   INSERT @t (str, nstr)
      SELECT str, str
      FROM   stringget

   RETURN
END

Мы сначала разбиваем текст на куски и помещаем их в табличную переменную @slices. Когда мы создавали куски для итерационного метода, то не беспокоились, если элемент списка расщеплялся по двум кускам. Но для этого метода, мы должны принять меры предосторожности, чтобы избежать такой ситуации, и мы должны проверять, что последний символ в куске - разделитель. Сначала мы получаем предварительный кусок максимальной длины, которую мы можем обработать. Затем находим последний разделитель в этом куске с помощью функции charindex, которая применяется к результату функции reverse, - небольшой трюк. Когда мы вставляем кусок в табличную переменную, то проверяем, что разделитель имеется и до, и после, так что нам не придется заниматься этим позже. Следует отметить, что если текст на входе укладывается в рамки обычного nvarchar, мы не входим в цикл, а просто вставляем текст непосредственно в таблицу @slices.

Как только @slices заполнена, мы применяем логику встроенной функции, хотя и несколько отличную, поскольку, как мы знаем, все строки в @slices начинаются и заканчиваются разделителем. Теперь числа, отфильтрованные через JOIN, есть положения разделителей, и элементы начинаются на одну позицию вперед. Отметим, что нам не нужны итерации по @slices; мы можем выполнить непосредственное соединение с Numbers. То, что начинается с WITH, есть Общее Табличное Выражение. Здесь мы лишь используем его как макрос, т.е. не повторяя сложное выражение, в котором мы извлекаем строку. Далее еще будут рассматриваться общие табличные выражения.

Как и в случае с iter_charlist_to_table, эта функция возвращает таблицу с двумя столбцами типов varchar и nvarchar. Мои тесты показали, что стоимость будет на 10-15 % выше для возвращаемой таблицы, если она имеет только один столбец nvarchar.

Эта функция в большинстве случаев значительно быстрее, чем inline_split_me, вплоть до 2 раз. Как я обсуждал в предыдущем разделе, inline_split_me может оказаться очень быстрой при параллельном плане и длинным входным параметром. Прекрасно, что при работе с могооператорной функцией с разбиениями Вы получаете согласующуюся производительность. По сравнению с CLR duo_chunk_split_me в моих тестах был на 25-50 % медленнее только на распаковке списка в таблицу.

Отметим, что эта функция не имеет проблем с надежностью как у встроенной функции. Посредством разбиения мы защищаемся от больших чисел, лишь бы у нас было 4000 чисел в таблице. Хорошо, но если Мы получаем больше кусков, чем имеется чисел в таблице, то у нас проблема. Но миллион чисел в таблице будет поддерживать входную длину около четырех миллиардов символов, что намного превышает размер для nvarchar (MAX).

(Продолжение следует...)

Полезная информация

§ Приглашаем вас посетить новый проект - Интерактивный учебник по SQL.
   Ресурс позиционируется как "справочное обеспечение" для сайта SQL-EX.RU, но может использоваться и независимо от него.

§ Онлайновый выпуск рассылки можно почитать на сайте.

§ Все статьи, публикуемые в рассылке, затем выкладываются на сайте Книги и статьи по SQL.

§ Хотите поддержать проект? Вот инструкция по применению. :-)

Контакты

По всем вопросам, связанным с функционированием сайта, проблемами при решении упражнений, идеями вы можете обращаться к Сергею И.Моисеенко msi77[@]yandex.ru. Вы также можете предложить свои задачи для публикации на сайте.

Подписка Subscribe.Ru
Новости сайта "Упражнения по SQL"

В избранное