Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle
.pdfПример 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