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

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


Новости сайта "Упражнения по SQL (http://www.sql-ex.ru)" Выпуск 209 (27 сентября 2008 г.)

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

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

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

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

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


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

§ Реанимировали работу быстрых клавиш на страницах с упражнениями:
Ctrl+Enter - выполнение запроса;
Ctrl+Shift+пробел - табуляция
Было замечено (Ozzy), что какое-то время назад быстрые клавиши перестали работать под Мозиллой. Похоже, что каждая новая версия браузера задействует наши комбинации. Так что мы можем теперь гарантировать функционирование только до появления новых версий браузеров. :-)

§ Изменения среди лидеров (решенные за неделю задачи третьего этапа):
1. Артём С. (147)
4. Arcan (148)
5. pvv (148)
17. anddros (141)

§ Одна задача до 3 этапа осталась:
40. yoj (задач 137, время 16.068).

§ Новые лица в ТОР 100 и вернувшиеся туда:
94. glassman (125, 29.232)

§ Продвинулись в рейтинге:
42. Fomichev (136, 19.518)
44. Gendalf (135, 134.446)
49. avk (134, 87.038)
51. VOVA_KHILKO (135, 54.966)
77. Чумазик (127, 140.277)
86. Shurgenz (126, 12.696)

§ Продвижение ближайших претендентов на попадание в ТОР 100:
117. D2NX (123, 496.298)
137. Pavel_yu (120, 113.124)
141. Ashton (118, 14.186)
151. B o r i s (117, 45.840)
152. @Nikotin (117, 4.023)
180. orange (111, 10.025)

§ На этой неделе сертифицированы:
Toxa number 768 (A08037854) [BK] - г.Москва, Россия
аrisana (A08029436) [BK] - г.Москва, Россия
_ORA_ (A08032989) [BK] - г.Москва, Россия

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

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

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

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

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

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

No Person Number of
Sel_ex
Last_Sel Number of
DML_ex
Scores Days Days_2 Days_3 S_3 LastSolved LastVisit
1 Селезнёв А.С. (Артём С.) 148 147 21 360 322 38.520 29.234 36 25 Sep 2008 26 Sep 2008
2 Карасёва Н.В. (vlksm) 149 149 21 363 866 77.241 49.173 36 18 Sep 2008 26 Sep 2008
3 Сальников С.А. ($erges) 148 54 21 361 196 2.854 3.359 34 09 Sep 2008 26 Sep 2008
4 >Креславский О.М. (Arcan) 148 148 21 360 605 40.052 28.202 33 26 Sep 2008 26 Sep 2008
5 Печатнов В.В. (pvv) 147 148 21 357 341 21.816 8.440 30 24 Sep 2008 26 Sep 2008
6 Держальцев В.А. (MadVet) 140 15 21 344 1257 60.815 28.482 28 24 Sep 2008 25 Sep 2008
7 Любченко В.А. (IAS56) 139 146 21 343 615 403.439 373.617 28 11 May 2008 16 Aug 2008
8 Голубин Р.С. (Roman S. Golubin) 143 54 21 346 1122 93.054 58.822 25 13 Sep 2008 25 Sep 2008
9 >Nikolaenko A.V. (Shadow77) 143 54 21 346 410 51.575 14.010 23 26 Sep 2008 26 Sep 2008
10 Мурашкин И.В. (lepton) 141 146 21 343 839 37.289 26.815 21 09 Jul 2008 25 Sep 2008
11 Солдатенков Ю.С. (SolYUtor) 141 146 21 342 819 22.703 6.102 20 14 Aug 2008 24 Sep 2008
12 Белогурова К. (Katy_Ekb) 135 143 21 331 361 10.714 4.673 18 20 May 2008 05 Sep 2008
13 Егоров А.Б. (ABEgorov) 140 144 21 340 180 12.917 8.815 18 03 Aug 2008 12 Aug 2008
14 Войнов П.Е. (pаparome) 142 88 21 341 1125 3.132 .213 17 22 Sep 2008 23 Sep 2008
15 iglbeat (iglbeat) 140 145 21 339 360 34.601 15.225 17 08 Aug 2008 25 Aug 2008
16 Северюхин Ю.А. (Venser) 131 142 21 322 335 4.925 .655 14 01 Feb 2008 04 Feb 2008
17 Дроздков А.Н. (anddros) 142 141 21 341 121 4.095 .780 14 25 Sep 2008 26 Sep 2008
18 Борисенков Д.В. (xuser) 136 55 21 329 236 3.245 .926 14 23 Sep 2008 26 Sep 2008
19 Мишин С.А. (CepbIu) 137 142 21 331 69 9.772 2.148 14 26 Jun 2008 10 Sep 2008
20 Тарасов Д.Б. (Gavrila) 138 142 21 333 1069 24.230 2.501 14 30 Jul 2008 26 Sep 2008

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

No surname n_sel sel_all sel_scores dml_scores scores rating last_visit
1 >Супрун Д.В. (TimonSP) 104 104 205 34 239 219 26 Sep 2008
2 >Семашко В.В. (fitu) 58 59 107 34 141 794 26 Sep 2008
3 Гибало М.В. (Двоюшник) 47 47 91 11 102 1523 26 Sep 2008
4 >Черняев (breezemaster1) 54 54 100 0 100 1571 26 Sep 2008
5 >Азбель (enull) 37 37 73 0 73 2650 26 Sep 2008
6 >Скво (WFR) 30 30 54 3 57 3755 26 Sep 2008
7 >Никотин В.М. (@Nikotin) 21 117 52 0 52 152 26 Sep 2008
8 Чойбеков Б.Э. (Bolat) 21 31 48 0 48 3596 22 Sep 2008
9 >vsh V.V. (vsh) 23 28 46 0 46 3003 26 Sep 2008
10 >Комов Д.М. (Komov) 10 61 13 31 44 769 26 Sep 2008
11 >Кузнецов К.В. (Незнайка на Луне) 18 30 43 0 43 3850 26 Sep 2008
12 >Zoltan (zbalazs) 23 23 41 0 41 5464 25 Sep 2008
13 >Anonym J.N. (habdl) 19 72 39 0 39 462 26 Sep 2008
14 Мельникова О. (MOlgaY) 22 22 39 0 39 5686 25 Sep 2008
15 >Писаренко Д.Н. (dimaP) 14 67 25 13 38 859 26 Sep 2008
16 Мурашенков Д.О. (a1r) 16 40 38 0 38 2482 20 Sep 2008
17 Kitanin (non) 15 28 37 0 37 3458 21 Sep 2008
18 >Катков М. (MIket) 16 25 36 0 36 5021 26 Sep 2008
19 >Башаримов В.Н. (D2NX) 14 123 34 0 34 117 26 Sep 2008
20 >Комарова Т.С. (lambda) 14 109 34 0 34 187 26 Sep 2008
21 >Фолифоров М.А. (Max_GT) 12 34 25 8 33 2207 26 Sep 2008
22 Похмелкин А.Ю. (Corleone) 14 28 33 0 33 4443 24 Sep 2008
23 >Лукоянова Е.А. (Leo81) 19 19 33 0 33 6350 26 Sep 2008
24 >Свиридов К.Ю. (orange) 12 111 32 0 32 180 26 Sep 2008
25 >Астафьев Д. (ORADIM) 16 23 31 0 31 5795 26 Sep 2008
26 Осипова И.А. (@ira@) 19 19 31 0 31 6701 26 Sep 2008
27 >Фокин Ф.А. (Philippok) 8 44 15 15 30 1530 26 Sep 2008
28 Vasiliev A. (Andrey_knit) 14 38 30 0 30 2740 25 Sep 2008
29 >q (t_b_i) 20 20 30 0 30 6905 26 Sep 2008
30 Рыбкина (RyAnna) 19 19 30 0 30 6920 23 Sep 2008

Изучаем SQL

Требования к SQL Server по усилению поддержки: предложение OVER() и упорядоченные вычисления (продолжение, начало в вып.195-199, 202-208)

Itzik Ben-Gan и Sujata Mehta (оригинал: SQL Server Feature Enhancement Request - OVER Clause and Ordered Calculations )
Перевод: Карасева Н.В.

Максимум параллельных сессий

Задача максимума параллельных сессий является ещё одним примером вычислений на упорядоченных данных. Вы записываете данные пользовательских сессий для разного рода приложений в таблицу Sessions. Выполните следующий запрос, для того чтобы создать и заполнить таблицу Sessions.

USE tempdb;
GO
IF OBJECT_ID('dbo.Sessions') IS NOT NULL
  DROP TABLE dbo.Sessions;
GO

CREATE TABLE dbo.Sessions
(
  keycol    INT         NOT NULL IDENTITY PRIMARY KEY,
  app       VARCHAR(10) NOT NULL,
  usr       VARCHAR(10) NOT NULL,
  host      VARCHAR(10) NOT NULL,
  starttime DATETIME    NOT NULL,
  endtime   DATETIME    NOT NULL,
  CHECK(endtime > starttime)
);
INSERT INTO dbo.Sessions
  VALUES('app1', 'user1', 'host1', '20030212 08:30', '20030212 10:30');
INSERT INTO dbo.Sessions
  VALUES('app1', 'user2', 'host1', '20030212 08:30', '20030212 08:45');
INSERT INTO dbo.Sessions
  VALUES('app1', 'user3', 'host2', '20030212 09:00', '20030212 09:30');
INSERT INTO dbo.Sessions
  VALUES('app1', 'user4', 'host2', '20030212 09:15', '20030212 10:30');
INSERT INTO dbo.Sessions
  VALUES('app1', 'user5', 'host3', '20030212 09:15', '20030212 09:30');
INSERT INTO dbo.Sessions
  VALUES('app1', 'user6', 'host3', '20030212 10:30', '20030212 14:30');
INSERT INTO dbo.Sessions
  VALUES('app1', 'user7', 'host4', '20030212 10:45', '20030212 11:30');
INSERT INTO dbo.Sessions
  VALUES('app1', 'user8', 'host4', '20030212 11:00', '20030212 12:30');
INSERT INTO dbo.Sessions
  VALUES('app2', 'user8', 'host1', '20030212 08:30', '20030212 08:45');
INSERT INTO dbo.Sessions
  VALUES('app2', 'user7', 'host1', '20030212 09:00', '20030212 09:30');
INSERT INTO dbo.Sessions
  VALUES('app2', 'user6', 'host2', '20030212 11:45', '20030212 12:00');
INSERT INTO dbo.Sessions
  VALUES('app2', 'user5', 'host2', '20030212 12:30', '20030212 14:00');
INSERT INTO dbo.Sessions
  VALUES('app2', 'user4', 'host3', '20030212 12:45', '20030212 13:30');
INSERT INTO dbo.Sessions
  VALUES('app2', 'user3', 'host3', '20030212 13:00', '20030212 14:00');
INSERT INTO dbo.Sessions
  VALUES('app2', 'user2', 'host4', '20030212 14:00', '20030212 16:30');
INSERT INTO dbo.Sessions
  VALUES('app2', 'user1', 'host4', '20030212 15:30', '20030212 17:00');

CREATE INDEX idx_app_st_et ON dbo.Sessions(app, starttime, endtime);

Для каждого приложения требуется вычислить максимальное количество сессий, открытых в один и тот же момент времени. Такие расчеты необходимы для определения стоимости типа лицензии на обслуживание, зависящей от максимального числа параллельных сессий.

Попытаемся решить задачу основываясь на теоретико-множественном подходе; затем оптимизируем решение; и после этого оценим его потенциальную производительность. Ниже я буду рассматривать решение в курсорах и приведу сравнительную таблицу для решения в рамках теоретико-множественного подхода и решения посредством курсора.

Один из путей решения состоит в создании вспомогательной таблицы, содержащей все возможные моменты времени из рассматриваемого временного интервала. Затем выполняется подзапрос для вычисления количества активных сессий для каждого такого момента времени, потом создается производная таблица/CTE из таблицы с результатами, и, наконец, выполняется группировка строк производной таблицы по приложениям с подсчетом максимуммального числа параллельных сессий для каждого приложения. Такое решение весьма неэффективно. Даже если вы создадите оптимальный индекс для него - один на (app, starttime, endtime) - полное число строк, которое сканирует запрос только на листовом уровне индекса, огромно. Оно равно числу строк во вспомогательной таблице, умноженному на среднее количество активных сессий в каждый момент времени. Для того чтобы почувствовать, насколько громоздка эта задача, представьте, что вам нужно выполнить расчет для месяца рабочей деятельности. Тогда число записей во вспомогательной таблице будет: 31(дни) x 24(часы) x 60(минуты) x 60(секунды) x 300 (интервалы в пределах секунды). Теперь умножьте результат этого вычисления на среднее число активных сессий в каждый момент времени (скажем, 20 сессий), и вы получите 16.070.400.000.

Конечно, возможности для оптимизации есть. Будут периоды, в течение которых число одновременных сессий не меняется, поэтому для них подсчеты не нужны. Количество меняется, когда стартует новая сессия (число сессий увеличивается на 1) или завершается существующая сессия (число уменьшается на 1). Более того, поскольку в момент начала сессии число сессий увеличивается, а при завершении - уменьшается, именно моменты начала сессий будут кандидатами на момент, в который число сессий достигнет искомого максимума. Наконец, если 2 сессии открываются в одно и то же время, то нет нужды подсчитывать количества для каждой из них. Таким образом, вы можете использовать предложение DISTINCT в запросе, который вернет вам начальные моменты для каждого приложения, хотя при уровне точности 3 1/3 миллисекунды (ms), число дубликатов было бы очень мало- пока вы не имеете дело с очень большим количеством данных.

Короче говоря, вы можете просто использовать в качестве вспомогательной таблицы производную таблицу или СТЕ, которая возвращает все различные времена начала сессий для каждого приложения. С этого момента все, что вам нужно сделать, - следовать логике, приведенной ранее. Вот оптимизированное решение, основанное на теории множеств:

SELECT app, MAX(concurrent) AS mx
FROM (SELECT app,
        (SELECT COUNT(*)
         FROM dbo.Sessions AS S2
         WHERE S1.app = S2.app
           AND S1.ts >= S2.starttime
           AND S1.ts < S2.endtime) AS concurrent
      FROM (SELECT DISTINCT app, starttime AS ts
            FROM dbo.Sessions) AS S1) AS C
GROUP BY app;

App mx
app1 4
app2 3

Заметьте, что вместо использования предиката BETWEEN для определения активности сессии в момент времени (ts), я использовал ts >= starttime и ts < endtime. Если сессия заканчивается в момент ts, то я не рассматриваю ее как активную.

План выполнения этого запроса показан на рис.4-1.

Рисунок 4-1. Вычисление максимума одновременных сессий. План для запроса, основанного на теоретико-множественном подходе

Во-первых, сканируется индекс, который я создал (app, starttime, endtime), и убираются дубликаты (оператором Stream Aggregate). Если таблица не очень большая, вы можете предположить, что число возвращаемых строк будет очень близко к числу строк в таблице. Для каждого app, starttime (обозначенного как ts) возвращенных после удаления дубликатов, начинает выполняться оператор Nested Loops, в котором вычисляется количество активных сессий (поиском по индексу с последующим частичным сканирования для подсчета активных сессий). Число страниц, прочитанных при каждой итерации Nested Loops, будет равно числу уровней в индексе плюс число страниц занимаемых активными сессиями. Для достижения свой цели я сосредоточусь на числе строк, просмотренных на листовом уровне (коррелирующий подзапрос - прим. перев.), потому что это число изменяется в зависимости от числа активных сессий. Конечно, для получения адекватных оценок производительности, вы должны учесть количество страниц (логических чтений) наряду с многими другими факторами. Если у вас N записей в таблице, то в предположении, что большая часть из них имеет уникальные значения app, starttime, и в любой момент времени у вас O перекрывающихся сессий, вы получите в итоге N х O строк, просканированных на листовом уровне, не считая сканирования страниц операциями поиска (seek) в процессе перехода к листовому уровню.

Теперь посмотрим, как масштабируется это решение с ростом таблицы. Как правило, такие отчеты нужны периодически - например, раз в месяц, за последний месяц. При наличии рекомендованного индекса, производительность решения не должна меняться пока не увеличится месячный траффик - то есть составлять N x O (где N - число записей за последний месяц). Но предположим, что вы предвидите увеличение траффика в f раз? Если траффик вырастает в f раз, то как число строк, так и число активных сессий в заданный момент времени, вырастут в f раз; в итоге число строк, просмотренных на уровне листьев, будет равно (N x f)x (O x f) = N x O x f2. Вы видите, что с ростом траффика производительность падает не линейно; она ухудшается более радикально.

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

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

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

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

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

Контакты

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

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

В избранное