Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
9
Добавлен:
15.01.2021
Размер:
14.96 Mб
Скачать

Пример 3: использование функции COUNT и оценка её производительности

Здесь можно увидеть несколько странную картину.

Для MySQL подтверждается бытующее мнение о том, что COUNT(*) работает медленнее всего, но неожиданно самым быстрым оказывается вариант с COUNT (поле_без_индекса). Однако стоит отметить, что на меньшем объёме данных (до миллиона записей) ситуация оказывается совершенно иной — быстрее всего работает COUNT (*).

MS SQL Server показал ожидаемые результаты: COUNT(первичный_ключ) оказался самым быстрым, COUNT(DISTINCT поле_без_индекса) — самым мед-

ленным. На меньших объёмах данных этот результат не меняется.

И теперь самое интересное — результаты Oracle: здесь снова подтвердились слухи о медленной работе COUNT(*) , но все остальные запросы показали по-

трясающий результат, очень высокую стабильность этого результата и полную независимость от объёма анализируемых данных. (Обратитесь к документации по Oracle, чтобы узнать, как этой СУБД удаётся так быстро выполнять некоторые виды

COUNT).

Пусть данное исследование и не претендует на научный подход, но общая рекомендация состоит в том, чтобы использовать COUNT(1) как в среднем один из самых быстрых вариантов для разных СУБД и разных объёмов данных, т.к. остальные варианты иногда оказываются быстрее, но иногда и медленнее.

Исследование 2.1.3.EXP.B: рассмотрим, как функция COUNT реагирует на NULL-значения и на повторяющиеся значения в DISTINCT-РЄЖИМЄ. Добавим в базу данных «Исследование» таблицу table_with_nulls.

dm MySQL Р

dm SQLServer2012

 

 

 

 

 

table with nulls 5

tabl e_with_nulls

table w ith nulls 5

 

 

 

«column»

«column»

«column»

x: INT

x: int

x: NUMBER(10)

MySQL

MS SQL Server

Oracle

Рисунок 2.1.f — Таблица table_with_nulls во всех трёх СУБД

Поместим в созданную таблицу следующие данные (одинаковые для всех трёх СУБД):

x

1 __

1 __

2 _

NULL

Выполним следующие запросы на подсчёт количества записей в этой таб-

лице:

MySQL I Исследование 2.1.3.EXP.B |

1— Вариант 1: COUNT(*)

2SELECT COUNT(*) AS 'total records'

3 FROM 'table_with_nulls'

1— Вариант 2: COUNT(l)

2SELECT COUNT(l) AS 'total records'

3

FROM

'table with nulls'

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 30/545

Пример 3: использование функции COUNT и оценка её производительности

MS SQL Исследование 2.1.3.EXP.B

1— Вариант 1: COUNT(*)

2SELECT COUNT(*) AS [total records]

3FROM [table_wi

th_nulls]

1— Вариант 2: COUNT(1)

2SELECT COUNT(1) AS [total records]

3

FROM

[table with nulls]

 

Oracl

і

Исследование 2.1.3.EXP.B

|

e

 

 

 

 

 

 

1

 

— Вариант 1: COUNT(*)

 

2

 

SELECT COUNT(*) AS "total records"

3

 

FROM

"table_wi th_nulls"

1— Вариант 2: COUNT(1)

2SELECT COUNT 1 AS "total records"

3

FROM

"table with nulls"

Все шесть запросов во всех СУБД вернут одинаковый результат: total_records

4

Теперь выполним запрос с COUNT, где аргументом будет являться имя поля:

Поскольку в таком случае подсчёт не учитывает NULL-значения, во всех трёх СУБД получится следующий результат:

total_records

3

И, наконец, выполним запрос с COUNT в DISTINCT-РЄЖИМЄ:

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 31/545

Пример 3: использование функции COUNT и оценка её производительности

В таком режиме COUNT не учитывает не только NULL-значения, но и все дуб-

ликаты значений (в наших исходных данных значение «1» было представлено дважды). Итого, результат выполнения запроса во всех трёх СУБД:

total_records

2

Осталось проверить, как COUNT работает на пустом множестве значений. Изменим запрос так, чтобы в выборку не попадал ни один ряд:

Все три СУБД возвращают одинаковый легко предсказуемый результат:

negative_records

0

Задание 2.1.3.TSK.A: показать, сколько всего читателей зарегистрировано в библиотеке.

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 32/545

Пример 4: использование функции COUNT в запросе с условием

2.1.4.Пример 4: использование функции COUNT в запросе с условием

Задача 2.1.4.a{29}: показать, сколько всего экземпляров книг выдано читателям.

Задача 2.1.4. b{30}: показать, сколько всего разных книг выдано читателям.

Ожидаемый результат 2.1.4.a.

in_use

5

Ожидаемый результат 2.1.4. b.

in_use

4

Решение 2.1.4.

Вся информация о выданных читателям книгах (фактах выдачи и возврата) хранится в таблице subscriptions, поле sb_book которой содержит идентификатор выданной книги. Поле sb_is_active содержит значение Y в случае, если книга сейчас находится у читателя (не возвращена в библиотеку).

Таким образом, нас будут интересовать только строки со значением поля sb_is_active равным Y (что отражено в секции WHERE, см. третью строку всех

шести запросов 2.1.4.a-2.1.4.b), а разница между задачами 2.1.4.a и 2.1.4.b состоит в том, что в первом случае мы просто считаем все случаи «книга находится у читателя», а во втором случае мы не учитываем повторения (когда на руки выдано несколько экземпляров одной и той же книги) — и достигаем это за счёт COUNT (DIS-

TINCT поле).

MySQL і Решение 2.1.4.a

1 SELECT COUNT('sb book') AS 'in use' 2 FROM 'subscriptions'

3 WHERE 'sb is active' = 'Y'

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 33/545

Пример 4: использование функции COUNT в запросе с условием

Решение 2.1.4.b{29}.

Здесь мы расширяем решение{29} задачи 2.1.4.a{29}, добавляя ключевое слово DISTINCT в параметр функции COUNT, что обеспечивает подсчёт неповторяющихся значений поля sb_book.

Задание 2.1.4.TSK.A: показать, сколько всего раз читателям выдавались книги.

& Задание 2.1.4.TSK.B: показать, сколько читателей брало книги в библиотеке.

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 34/545

Пример 5: использование функций SUM, MIN, MAX, AVG

2.1.5. Пример 5: использование функций SUM, MIN, MAX, AVG

Задача 2.1.5.a{31}: показать общее (сумму), минимальное, максимальное и среднее значение количества экземпляров книг в библиотеке.

Ожидаемый результат 2.1.5.a.

sum

min

max

avg

33

1

12

4.7143

чР Решение 2.1.5.a{31}.

Втакой простой формулировке эта задача решается запросом, в котором достаточно перечислить соответствующие функции, передав им в качестве параметра поле b_quantity (и только в MS SQL Server придётся сделать небольшую

доработку).

Обратите внимание на 4-ю строку в запросе 2.1.5.a для MS SQL Server: без приведения функцией CAST значения количества книг к дроби, итоговый результат работы функции AVG будет некорректным (это будет целое

число), т.к. MS SQL Server выбирает тип данных результата на основе типа данных входного параметра. Продемонстрируем это.

MS SQL

Решение 2.1.5.a (пример запроса с ошибкой)

 

1SELECT SUM [b_quantity] AS [sum],

2MIN([b_quantity]) AS [min],

3MAX([b_quantity]) AS [max],

4AVG([b_quantity]) AS [avg]

5FROM [books]

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 35/545

Пример 5: использование функций SUM, MIN, MAX, AVG

 

Получится:

 

 

 

 

 

sum

min

max

avg

 

 

 

33

1

 

12

 

4

 

 

 

 

 

А должно быть:

 

 

 

 

sum

min

max

avg

 

 

 

33

 

1

 

12

 

4.7143

 

(

Стоит упомянуть ещё одну опасную ошибку: очень легко забыть, что при

вычислении суммы и среднего значения (которое определяется как

сумма, поделённая на количество значений) может произойти переполнение разрядной сетки.

Исследование 2.1.5. EXP.A: рассмотрим реакцию различных СУБД на ситуацию переполнения разрядной сетки.

Создадим в БД «Исследование» таблицу overflow с одним числовым целочисленным полем:

dm MySQL Р

dm SQLServer2012

dm Oracle

 

overflow

 

 

 

 

 

 

«column»

«column»

«column»

x: INT

x: int

x: NUMBER(10)

MySQL MS SQL Server Oracle

Рисунок 2.1.g — Таблица overflow во всех трёх СУБД

Поместим в созданную таблицу три максимальных значения для её поля x:

___ x

 

 

X

 

x ___

2147483647

 

2147483647

9999999999

2147483647

 

2147483647

9999999999

2147483647

 

2147483647

9999999999

MySQL

MS SQL Server

Oracle

1-- Запрос 1: SUM

2SELECT SUM [x]) AS [sum]

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 36/545

Пример 5: использование функций SUM, MIN, MAX, AVG

3 FROM [overflow]

1-- Запрос 2: AVG

2SELECT AVG [x]) AS [avg]

3FROM [overflow]

Теперь выполним для каждой СУБД запросы на получение суммы значений

MySQL Исследование 2.1.5.EXP.A

1-- Запрос 1: SUM

2SELECT SUM('x') AS 'sum'

FROM 'overflow'

Исследование 2.1.5.EXP.A

1-- Запрос 2: AVG

2SELECT AVG('x') AS 'avg' FROM 'overflow'

из поля x и среднего значения в поле х:

MS SQL

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 37/545

Пример 5: использование функций SUM, MIN, MAX, AVG

 

Oracl

і

Исследование 2.1.5.EXP.A

|

e

 

 

 

 

 

1

 

-- Запрос 1: SUM

 

2 SELECT SUM("x" AS "sum"

3 FROM "overflow"

1-- Запрос 2: AVG

2SELECT AVG("x" AS "avg"

3FROM "overflow"

MySQL и Oracle выполнят запросы 2.1.5.EXP.A и вернут корректные данные, а в MS SQL Server мы получим сообщение об ошибке:

Msg 8115, Level 16, State 2, Line 1. Arithmetic overflow error converting expression to data type int.

Это вполне логично, т.к. при попытке разместить в переменной типа INT трёхкратное максимальное значение типа INT, возникает переполнение разрядной

сетки.

MySQL и Oracle менее подвержены этому эффекту, т.к. у них «в запасе» есть DECIMAL и NUMBER, в формате которых и происходит вычисление. Но при достаточ-

ном объёме данных там тоже возникает переполнение разрядной сетки.

Особая опасность этой ошибки состоит в том, что на стадии разработки и поверхностного тестирования БД она не проявляется, и лишь со временем, когда у реальных пользователей накопится большой объём данных, в какой-то момент ранее прекрасно работавшие запросы перестают работать.

Исследование 2.1.5.EXP.B. Чтобы больше не возвращаться к особенностям работы агрегирующих функций, рассмотрим их поведение в случае наличия в анализируемом поле NULL-значений, а также в случае пустого набора входных значений.

Используем ранее созданную таблицу table_with_nulls{26}. В ней попрежнему находятся следующие данные:

x

_1 ___

_1 ___

_2 ___

NULL

Выполним запросы 2.1.5.EXP.B:

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 38/545

Пример 5: использование функций SUM, MIN, MAX, AVG

Все запросы 2.1.5.EXP.B возвращают почти одинаковый результат (разница только в количестве знаков после запятой в значении функции AVG: у MySQL там четыре знака, у MS SQL Server и Oracle — 14 и 38 знаков соответственно):

sum

min

max

avg

4

1

2

1.3333

Как легко заметить из полученных данных, ни одна из функций не учитывает NULL-значения.

Исследование 2.1.5.EXP.C. Последний эксперимент будет заключаться в применении к выборке такого условия, которому не соответствует ни один ряд: таким образом в выборке окажется пустое множество строк.

Здесь все три СУБД также работают одинаково, наглядно демонстрируя, что на пустом множестве функции SUM, MIN, MAX, AVG возвращают NULL:

sum

min

max

avg

NULL

NULL

NULL

NULL

Также обратите внимание, что при вычислении среднего значения не произошло ошибки деления на ноль.

Логику работы на пустом множестве значений функции COUNT мы уже рассмотрели ранее (см. исследование 2.1.3.EXP.B{28}).

& Задание 2.1.5.TSK.A: показать первую и последнюю даты выдачи книги читателю.

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 39/545