Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle
.pdfПример 39: оптимизация производительности с помощью хранимых процедур
Запрос в строках 7-10 позволяет получить список таблиц текущей базы данных (часть условия в строке 10 позволяет отличить таблицы от представлений), после чего:
•для полученного списка таблиц открывается курсор (строка 13);
•для всех строк курсора выполняется цикл (строки 15-26);
•в теле цикла формируется (строка 21) и выполняется (строки 22-23) запрос, реализующий оптимизацию таблицы.
Запустить полученную хранимую процедуру можно следующим образом.
MySQL |
Решение 5.2.2.b (запуск и проверка работоспособности) |
1 |
CALL OPTIMIZE ALL TABLES |
Теперь остаётся создать событие, запускаемое планировщиком задач MySQL по определённому расписанию. Это реализуется следующим кодом.
запуска по
1 SET GLOBAL event_scheduler = ON;
CREATE EVENT 'optimize_all_tables_daily'
4ON SCHEDULE
5EVERY 1 DAY
6STARTS DATE(NOW()) + INTERVAL 1 HOUR
7ON COMPLETION PRESERVE
8DO
9CALL OPTIMIZE ALLTABLES;
Убедиться, что событие добавлено, можно следующим запросом.
MySQL і Решение 5.2.2.b (просмотр расписания)
1 |
SELECT * FROM 'information_schema' 'events' |
| |
Если рассмотреть избранные поля результата такого запроса, получается следующая картина. Здесь также представлено событие, активирующее раз в час хранимую процедуру, созданную в процессе решения{388} задачи 5.2.2.a{388}.
EVENT_NAME |
EVENT_TYPE |
INTER- |
INTER- |
STARTS |
ENDS |
|
ON_COM- |
|
|
|
|
|
|
|
|
|
|
VAL_VALUE |
VAL_FIELD |
|
|
STATUS |
PLETION |
update_books_statis- |
RECURRING |
1 |
HOUR |
2016-04-27 |
NULL |
ENA |
PRESERVE |
|
|
|
|
|
|
||
tics hourly |
|
|
|
14:01:00 |
|
BLED |
|
|
|
|
|
|
|
|
|
optimize_all_tables |
RECURRING |
1 |
DAY |
2016-04-27 |
NULL |
ENA |
PRESERVE |
|
|
|
|
|
|
|
|
daily |
|
|
|
01:00:00 |
|
BLED |
|
|
|
|
|
|
|
|
|
На этом решение для MySQL завершено.
Переходим к MS SQL Server. Концепция представленного ниже решения основана на этой рекомендации25.
Итак, мы должны будем получить список кластерных индексов текущей базы данных, выяснить степень их фрагментации (avg_fragmentation_in_percent) и,
в зависимости от этого значения, выполнить реорганизацию (REORGANIZE) или перестроение (REBUILD) индекса.
Для начала напишем запрос, предоставляющий информацию по всем индексам, соответствующим таблицам, полям и т.д. К сожалению, готового решения MS SQL Server не предоставляет, потому придётся всё делать «вручную».
25 http://blog.sqlauthority.com/2010/01/12/sql-server-fragmentation-detect-fragmentation-and-eliminate-fragmentation/
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 420/545
Пример 39: оптимизация производительности с помощью хранимых процедур
MS SQL |
Решение 5.2.2.b |
данных по всем |
|
|
1 |
SELECT [tables] [name] |
|
AS [table name], |
|
2 |
|
[indexes] [name] |
|
AS [index name], |
3 |
|
[indexes] [type] |
|
AS [index type], |
4 |
|
[stats] [index type desc] |
AS [index type desc], |
|
5 |
|
[indexes] [object id] |
AS [index object id], |
|
6 |
|
[columns] [name] |
|
AS [column name], |
7 |
|
[s tats] |
|
AS [avg_fragm_perc], |
8 |
|
[stats] [avg page space used in percent] AS [avg space perc] |
||
9 |
FROM |
sys.indexes AS [indexes] |
|
|
10 |
|
INNER JOIN sys.index columns AS [index columns] |
||
11 |
|
ON [indexes] [object id] = [index columns] [object id] |
||
12 |
|
AND [indexes] [index id] = |
[index columns] [index id] |
|
13 |
|
INNER JOIN sys.columns AS [columns] |
|
|
14 |
|
ON [index columns] [object id]= [columns] [object id] |
||
15 |
|
AND [index columns] [column id] = [columns] [column id] |
||
16 |
|
INNER JOIN sys.tables AS [tables] |
|
|
17 |
|
ON [indexes] [object id] = [tables] [object id] |
||
18 |
|
INNER JOIN sys.dm_db_index_physical_stats(DB_ID(DB_NAME()), |
||
19 |
|
|
|
NULL, NULL, NULL, |
20 |
|
|
|
'SAMPLED') AS [s tats] |
21 |
|
ON [indexes] [object id] = [stats] [object id] |
||
22 |
|
|
AND [indexes] [indexid] = [stats] [index id] |
|
23 |
ORDER |
BY [tables] [name], |
|
|
24 |
|
[indexes] [name], |
|
|
25 |
|
[indexes] [index id] |
|
|
26 |
|
[index columns] [index column id] |
|
|
|
|
|
|
|
В результате выполнение такого запроса мы получим следующие данные.
table_name |
index_name |
in- |
index_type_desc |
index_ob- |
col- |
avg_fragm_ |
avg_space_perc |
|
|
|
dex_typ |
|
ject_id |
umn_name |
|
perc |
|
|
|
|
|
|
|
|
|
|
authors |
PK_authors |
1 |
CLUSTERED |
245575913 |
a_id |
0 |
|
3.22461082283173 |
|
|
|
|
|
|
|
|
|
|
|
|
INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
books |
PK_books |
1 |
CLUSTERED |
277576027 |
b_id |
0 |
|
5.72028663207314 |
|
|
|
|
|
|
|
|
|
|
|
|
INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
genres |
PK_genres |
1 |
CLUSTERED |
309576141 |
g_id |
0 |
|
2.59451445515196 |
|
|
|
|
|
|
|
||
|
|
|
INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
genres |
UQ_genres g |
2 |
NONCLUS |
309576141 |
g_name |
0 |
|
2.37212750185322 |
|
|
|
|
|
|
|
|
|
|
name |
|
TERED INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m2m_books |
PK_m2m_boo ks |
1 |
CLUSTERED |
341576255 |
b_id |
0 |
|
1.86557944156165 |
authors |
authors |
|
INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m2m_books |
PK_m2m_boo ks |
1 |
CLUSTERED |
341576255 |
a_id |
0 |
|
1.86557944156165 |
authors |
authors |
|
INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m2m_books |
PK_m2m_boo ks |
1 |
CLUSTERED |
373576369 |
b_id |
0 |
|
2.28564368668149 |
genres |
genres |
|
INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m2m_books |
PK_m2m_boo ks |
1 |
CLUSTERED |
373576369 |
g_id |
0 |
|
2.28564368668149 |
genres |
genres |
|
INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subscribers |
PK_subscribers |
1 |
CLUSTERED |
405576483 |
s_id |
0 |
|
1.95206325673338 |
|
INDEX |
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subscriptions |
PK_subscrip- |
1 |
CLUSTERED |
437576597 |
sb_id |
0 |
|
5.16431924882629 |
|
|
|
|
|
|
|
||
tions |
|
INDEX |
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
Этот результат хорош тем, что удобен для просмотра человеком, но внутри хранимой процедуры нам будут нужны только три поля: имя таблицы, имя индекса, процент фрагментации. К тому же составные кластерные индексы (например, PK_m2m_books_authors) должны быть представлены только один раз (а не по разу на каждое из входящих в состав индекса полей, как это есть сейчас).
Упростим запрос так, чтобы оставить только необходимые данные.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 421/545
Пример 39: оптимизация производительности с помощью хранимых процедур
MS SQL і |
Решение 5.2.2.b (получение краткого набора данных по всем индексам) |
| |
|
|||||
1 |
SELECT DISTINCT |
|
|
|
|
|
|
|
2 |
|
[tables] [name] |
AS [table_name], |
|
|
|
|
|
3 |
|
[indexes].[name] |
AS [index_nams], |
|
|
|
|
|
4 |
|
[stats] |
[avg_fragmentation_in_percent] |
AS |
||||
5 |
FROM |
[avg_fragm_perc] |
|
|
|
|
|
|
6 |
|
sys.indexes AS [indexes] INNER JOIN sys.tables AS [tables] |
|
|
||||
7 |
|
ON [indexes] [object_id] |
= [tables] |
[object_id] |
|
|||
8 |
|
INNER JOIN sys.dm_db_index_physical_stats(DB_ID(DB_NAME()), |
|
|
||||
9 |
|
|
NULL, NULL, NULL, 'SAMPLED') AS [s tats] |
|||||
10 |
|
ON [indexes] [object_id] |
= [stats] |
[object_id] |
|
|||
11 |
|
AND [indexes] |
[index_id] |
= [stats] |
[index_id] |
|
||
12 |
|
[indexes].[type] = 1 BY [tables].[name], |
|
|
|
|
||
13 |
WHERE |
[indexes].[name] |
|
|
|
|
|
|
14 |
ORDER |
В результате |
выполнение |
такого запроса мы |
получим |
|||
15 |
|
следующие данные.
table_name |
index_name |
avg_fragm_perc |
authors |
PK_authors |
0 |
books |
PK books |
0 |
genres |
PK_genres |
0 |
m2m_books_authors |
PK_m2m_books_authors |
0 |
m2m books genres |
PK m2m books genres |
0 |
subscribers |
PK_subscribers |
0 |
subscriptions |
PK subscriptions |
0 |
Теперь используем полученный запрос в теле хранимой процедуры. Проходя по всем рядам, возвращаемым курсором (цикл в строках 29-56), мы будем анализировать значение avg_fragm_perc и либо выполнять одно из двух действий по оптимизации, либо не выполнять никаких действий.
MS SQL I |
Решение 5.2.2.b (код процедуры) | |
1CREATE PROCEDURE OPTIMIZE ALL TABLES
2AS
3BEGIN
4DECLARE @table name NVARCHAR'200 ;
5DECLARE @index name NVARCHAR'200 ;
6DECLARE @avg_fragm_perc DOUBLE PRECISION;
7DECLARE @query text NVARCHAR'2000 ;
8DECLARE indexes cursor CURSOR LOCAL FAST FORWARD FOR
9SELECT DISTINCT
10 |
|
[tables] [name] |
AS [table name] |
11 |
|
[indexes] [name] |
AS [index name] |
12 |
|
[stats] [avg_fragmentation_in_percent] |
AS [avg_fragm_perc] |
13 |
FROM |
sys.indexes AS [indexes] |
|
14 |
|
INNER JOIN sys.tables AS [tables] |
|
15 |
|
ON [indexes] [object id] = [tables] [object id] |
|
16 |
|
INNER JOIN sys.dm_db_index_physical_stats(DB_ID(DB_NAME()), |
|
17 |
|
|
NULL, NULL, NULL, |
18 |
|
|
'SAMPLED') AS [stats] |
19 |
|
ON [indexes] [object id] = [stats] [object id] |
|
20 |
|
AND [indexes] [index id] = [stats] [index id] |
|
21 |
WHERE |
[indexes] [type] = 1 |
|
22 |
ORDER BY [tables] [name], |
|
|
23 |
|
[indexes] [name]; |
|
24 |
|
|
|
25OPEN indexes cursor;
26FETCH NEXT FROM indexes cursor INTO @table name,
27 |
@index name, |
28 |
@avg_fragm_perc; |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 422/545
Пример 39: оптимизация производительности с помощью хранимых процедур
MS SQL Решение 5.2.2.b
29WHILE @@FETCH STATUS = 0
30BEGIN
31IF (@avg_fragm_perc >= 5.0) AND @avg_fragm_perc <= 30.0)
32BEGIN
33SET @query text = CONCAT('ALTER INDEX [', @index name
34 |
'] ON [', @table name, '] REORGANIZE'); |
35 |
PRINT CONCAT('Index [', @index name,'] on [', @table name |
36 |
'] will be REORGANIZED...'); |
37EXECUTE sp_executesql @query_text
38END;
39IF (@avg_fragm_perc > 30.0)
40BEGIN
41SET @query text = CONCAT('ALTER INDEX [', @index name '] ON [',
42 |
@table name. '] REBUILD'); |
43 |
PRINT CONCAT('Index [', @index name,'] on [', @table name |
44 |
'] will be REBUILT...'); |
45EXECUTE sp_executesql @query_text
46END;
47IF (@avg_fragm_perc < 5.0)
48BEGIN
49PRINT CONCAT('Index [', @index name,'] on [', @table name
50 |
'] needs no optimization...'); |
51 |
END; |
52 |
|
53 |
FETCH NEXT FROM indexes cursor INTO @table name |
54 |
@index name |
55 |
@avg_fragm_perc |
56END;
57CLOSE indexes cursor;
58DEALLOCATE indexes cursor
59END;
60GO
Запустить полученную хранимую процедуру можно следующим образом.
MS SQL |
Решение 5.2.2.b (запуск и проверка работоспособности) |
1 |
EXECUTE OPTIMIZE ALL TABLES |
Логика установки запуска задачи по расписанию была рассмотрена в решении{388} задачи 5.2.2.a{388}, потому здесь просто приведём код, с помощью которого выполняется эта операция.
MS SQL |
Решение 5.2.2.b (установка запуска по расписанию) |
| |
1USE msdb ;
2GO
3—https: //msdn.microsoft.com/en-us/library/ms182079 .aspx
4EXEC dbo sp add job
5@job name = N'Hourly [books statistics] update';
6GO
7—https://msdn.microsoft.com/en-us/library/ms187358.aspx
8EXEC sp_add_j obstep
9@job name = N'Hourly [books statistics] update',
10@step name = N'Execute UPDATE BOOKS STATISTICS stored procedure',
11@subsystem = N'TSQL',
12@command = N'EXECUTE UPDATE BOOKS STATISTICS',
13@database name = N'library ex 2015 mod';
14GO
15—https://msdn.microsoft.com/en-us/library/ms187320.aspx
16EXEC dbo sp add schedule
17@schedule name = N'UpdateBooksStatistics',
18@freq_type = 4
19@freq_interval = 4
20@freq_subday_type = 8,
21@freq_subday_interval = 1,
22@active start time = 000105 ;
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 423/545
Пример 39: оптимизация производительности с помощью хранимых процедур
MS SQL |
Решение 5.2.2.b (установка запуска по расписанию) |
| |
23USE msdb ;
24GO
25—https://msdn.microsoft.com/en-us/library/ms186766.aspx
26EXEC sp attach schedule
27@job name = N'Hourly [books statistics] update',
28@schedule name = N'UpdateBooksStatistics';
29GO
30—https://msdn.microsoft.com/en-us/library/ms178625.aspx
31EXEC dbo sp add jobserver
32@job name = N'Hourly [books statistics] update';
33GO
Убедиться, что событие добавлено, можно следующим запросом.
MS SQL Решение 5.2.2.b (просмотр расписания)
1 SELECT * FROM msdb dbo sysschedules
Если рассмотреть избранные поля результата такого запроса, получается следующая картина. Здесь также представлено событие, активирующее раз в час хранимую процедуру, созданную в процессе решения{388} задачи 5.2.2.a{388}.
Name |
enable |
freq_type |
freq_inter- |
freq_subday |
freq_subday_in- |
ac |
ac |
||
|
d |
|
|
|
|
|
|
||
|
|
val |
|
type |
|
terval |
tive start date |
tive start time |
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
||
UpdateBooksStatistics |
1 |
4 |
4 |
8 |
|
1 |
|
20160427 |
000105 |
DailyOptimizeAllTables |
1 |
4 |
4 |
1 |
|
1 |
|
20160427 |
000100 |
|
|
|
|
|
|
|
|
|
|
На этом решение для MS SQL Server завершено.
Переходим к Oracle. Код создания нужной нам хранимой процедуры выглядит следующим образом.
Oracle Решение 5.2.2.b (код процедуры)
1CREATE OR REPLACE PROCEDURE OPTIMIZE ALL TABLES
2AS
3table name VARCHAR(150) := '';
4query text VARCHAR(1000) := '';
5CURSOR tables cursor IS
6SELECT TABLE NAME AS "table name"
7FROM ALL TABLES
8WHERE OWNER=USER;
9BEGIN
10FOR one row IN tables cursor
11LOOP
12query text := 'ALTER TABLE "' || one row "table name" ||
13 |
'" ENABLE ROW MOVEMENT'; |
14 |
DBMS OUTPUT.PUT LINE('Enabling row movement for "' || |
15 |
one row "table name" || '"...'); |
16 |
EXECUTE IMMEDIATE query text |
17 |
|
18 |
query text := 'ALTER TABLE "' || one row "table name" || |
19 |
'" SHRINK SPACE COMPACT CASCADE'; |
20 |
DBMS OUTPUT.PUT LINE('Performing SHRINK SPACE COMPACT CASCADE on "' || |
21 |
one row "table name" || '"...'); |
22 |
EXECUTE IMMEDIATE query text |
23 |
|
24 |
query text := 'ALTER TABLE "' || one row "table name" || |
25 |
'" DISABLE ROW MOVEMENT'; |
26 |
DBMS OUTPUT.PUT LINE('Disabling row movement for "' || |
27 |
one row "table name" || '"...'); |
28EXECUTE IMMEDIATE query text
29END LOOP;
30END;
31/
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 424/545
Пример 39: оптимизация производительности с помощью хранимых процедур
Концепция представленного решения основана на этой рекомендации26. Итак, мы должны будем получить список всех таблиц, а затем для каждой из них сначала разрешить перемещение рядов, потом выполнить компактификацию и, наконец, снова запретить перемещение рядов. В отличие от MS SQL Server все запросы здесь совершенно тривиальны.
Запустить полученную хранимую процедуру можно следующим образом.
Oracle |
Решение 5.2.2.b (запуск и проверка работоспособности) |
1SET SERVEROUTPUT ON;
EXECUTE OPTIMIZE ALL TABLES;
Теперь остаётся создать событие, запускаемое планировщиком задач Oracle по определённому расписанию. Это реализуется следующим кодом.
Oracle |
Решение 5.2.2.b (установка запуска по расписанию) |
|
1 |
BEGIN |
|
2 |
DBMS SCHEDULER.CREATE JOB ( |
|
3 |
j ob_name |
=> ' daily_optimize_all_tables' , |
4 |
j ob type |
=> 'STORED PROCEDURE', |
5 |
job action |
=> 'OPTIMIZE ALL TABLES', |
6 |
start date |
=> '25-APR-16 4.00.00 PM', |
7 |
repeat_interval |
=> 'FREQ=DAILY;INTERVAL=1', |
8 |
auto_drop |
=> FALSE |
9 |
enabled |
=> TRUE); |
10 |
END; |
|
|
|
|
Убедиться, что событие добавлено, можно следующим запросом.
Oracle Решение 5.2.2.b (просмотр расписания)
1 SELECT * FROM ALL_SCHEDULER_JOBS WHERE OWNER=USER
Если рассмотреть избранные поля результата такого запроса, получается следующая картина. Здесь также представлено событие, активирующее раз в час хранимую процедуру, созданную в процессе решения{388} задачи 5.2.2.a{388}.
JOB_NAME |
JOB_STY |
JOB_TYPE |
JOB_ACTION |
START_DATE |
REPEAT_INTER- |
ENA |
STATE |
|
LE |
|
|
|
VAL |
BLED |
|
|
|
|
|
|
|
|
|
DAILY_OPTI- |
REGU |
STORED_PR |
OPTI- |
25-APR-27 |
FREQ=DAILY;IN |
TRU |
SCHE |
MIZE_ALL_TA- |
LAR |
OCEDURE |
MIZE_ALL_TA- |
04.00.00.000000 |
TERVAL=1 |
E |
DULE |
BLES |
|
|
BLES |
000 PM -03:00 |
|
|
D |
|
|
|
|
|
|
|
|
HOURLY_UP- |
REGU |
STORED_PR |
UP- |
22-APR-27 |
FREQ=HOURLY |
TRU |
SCHE |
DATE_BOOKS_S |
LAR |
OCEDURE |
DATE_BOOKS_S |
04.00.00.000000 |
;INTERVAL=1 |
E |
DULE |
TATISTICS |
|
|
TATISTICS |
000 PM -03:00 |
|
|
D |
|
|
|
|
|
|
|
|
На этом решение данной задачи завершено.
& Задание 5.2.2.TSK.A: создать хранимую процедуру, запускаемую по расписанию каждые 12 часов и обновляющую данные в агрегирующей таблице subscriptions_ready (см. задачу 3.1.2.b{215}).
Задание 5.2.2.TSK.B: создать хранимую процедуру, запускаемую по расписанию раз в неделю и оптимизирующую (дефрагментирующую, компактифицирующую) все таблицы базы данных, в которых находится не менее одного миллиона записей.
26 https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:17312316112393#1765387500346472492
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 425/545
Пример 40: управление структурами базы данных с помощью хранимых процедур
5.2.3.Пример 40: управление структурами базы данных с помощью хранимых процедур
Задача 5.2.3.a{400}: создать хранимую процедуру, автоматически создающую и наполняющую данными агрегирующую таблицу books_statistics (см. задачу 3.1.2.a{215}).
Задача 5.2.3.b{404}: создать хранимую процедуру, автоматически создающую и наполняющую данными агрегирующую таблицу tables_rc, содержащую информацию о количестве записей во всех таблицах базы данных в формате (имя_таблицы, количество_записей).
Ожидаемый результат 5.2.3.a.
При вызове хранимой процедуры таблица books_statistics создаётся и наполняется данными. Если таблица уже существует на момент вызова хранимой процедуры, данные в ней обновляются (приводятся в актуальное состояние).
Пример содержимого таблицы books_statistics см. в задаче 3.1.2.a{215}.
Ожидаемый результат 5.2.3.b.
При вызове хранимой процедуры таблица tables_rc создаётся и наполняется данными. Если таблица уже существует на момент вызова хранимой процедуры, данные в ней обновляются (приводятся в актуальное состояние).
Пример содержимого таблицы tables_rc:
table_name |
rows_count |
authors |
7 |
books |
7 |
books statistics |
1 |
genres |
6 |
m2m_books_authors |
9 |
m2m books genres |
11 |
subscribers |
4 |
subscriptions |
11 |
tables_rc |
8 |
чг Решение 5.2.3.a{400}.
Врешении{367} задачи 5.1.1.c{352} уже содержатся готовые запросы для создания таблицы books_statistics, наполнения её данными и обновления её дан-
ных. Сейчас нам остаётся только разместить эти запросы внутри хранимой процедуры и добавить проверку существования самой таблицы books_statistics.
Решения для MySQL и MS SQL Server будут полностью идентичными, а в Oracle нам придётся все запросы выполнять через EXECUTE IMMEDIATE, т.к. в случае отсутствия таблицы books_statistics эта СУБД автоматически считает хранимую процедуру некорректной, если в ней напрямую прописаны запросы, обращающиеся к этой таблице.
Теперь остаётся только привести код.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 426/545
Пример 40: управление структурами базы данных с помощью хранимых процедур
Решение для MySQL выглядит следующим образом.
MySQL I |
Решение 5.2.3.a (код процедуры) | |
1DELIMITER $$
2CREATE PROCEDURE CREATE BOOKS STATISTICS() BEGIN
34
5IF NOT EXISTS
6(SELECT 'table name'
7 |
FROM |
'information schema' 'tables' |
|||
8 |
WHERE |
'table schema' |
= DATABASE() |
||
9 |
AND |
'table |
type' |
= |
'BASE TABLE' |
10 |
AND |
'table |
name' |
= |
'books statistics') |
11THEN
12CREATE TABLE 'books statistics'
13(
14'total' INTEGER UNSIGNED NOT NULL,
15'given' INTEGER UNSIGNED NOT NULL,
16'rest' INTEGER UNSIGNED NOT NULL
17);
18INSERT INTO 'books statistics'
19 |
('total', |
20 |
'given', |
21 |
'rest') |
22SELECT IFNULL('total', 0 ,
23IFNULL('given', 0 ,
24IFNULL('total' - 'given', 0) AS 'rest'
25 |
FROM |
(SELECT (SELECT SUM('b quantity') |
|
|
|
26 |
|
FROM |
'books') |
AS |
'total' |
27 |
|
(SELECT COUNT('sb book') |
|
|
|
28 |
|
FROM |
'subscriptions' |
|
|
29 |
|
WHERE |
'sb is active' = 'Y') AS |
'given') |
30AS 'prepared data';
31ELSE
32UPDATE 'books statistics'
33JOIN
34(SELECT IFNULL('total', 0) AS 'total',
35 |
|
IFNULL('given', 0) AS 'given', |
|
|
36 |
|
IFNULL('total' - 'given', 0 AS 'rest' |
|
|
37 |
FROM |
(SELECT (SELECT SUM('b quantity') |
|
|
38 |
|
FROM |
'books') |
AS 'total' |
39 |
|
(SELECT COUNT('sb book') |
|
|
40 |
|
FROM |
'subscriptions' |
|
41 |
|
WHERE |
'sb is active' = 'Y') |
'given') |
42 |
|
AS 'prepared data') AS 'src' |
|
43SET 'books statistics' 'total' = 'src' 'total',
44'books statistics' 'given' = 'src' 'given',
45'books statistics' 'rest' = 'src' 'rest';
46END IF;
47END;
48$$
49DELIMITER ;
Для проверки корректности полученного решения можно выполнить следующие запросы.
MySQL |
Решение 5.2.3.a (проверка работоспособности) |
DROP TABLE 'books_statistics';
2 CALL CREATE_BOOKS_STATISTICS; SELECT * FROM 'books statistics';
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 427/545
Пример 40: управление структурами базы данных с помощью хранимых процедур
Решение для MS SQL Server выглядит следующим образом.
MS SQL Решение 5.2.3.a (код процедуры)
1CREATE PROCEDURE CREATE BOOKS STATISTICS
2AS
3BEGIN
4IF NOT EXISTS
5(SELECT [name]
6 |
FROM |
sys.tables |
7 |
WHERE |
[name] = 'books statistics') |
8BEGIN
9CREATE TABLE [books statistics]
10(
11[total] INTEGER NOT NULL,
12[given] INTEGER NOT NULL,
13[rest] INTEGER NOT NULL
14);
15INSERT INTO [books statistics]
16 |
([total] |
17 |
[given] |
18 |
[rest]) |
19SELECT ISNULL([total], 0 AS [total]
20ISNULL([given], 0 AS [given]
21ISNULL([total] - [given], 0) AS [rest]
22 |
FROM |
(SELECT (SELECT SUM [b quantity] |
|
|
23 |
|
FROM |
[books]) |
AS [total] |
24 |
|
(SELECT COUNT([sb book]) |
|
|
25 |
|
FROM |
[subscriptions] |
|
26 |
|
WHERE |
[sb is active] = 'Y') AS [given] |
|
27 |
|
AS [prepared_data]; |
|
|
28 |
|
|
|
|
29END
30ELSE
31BEGIN
32UPDATE [books statistics]
33SET
34[books statistics] [total] = [src] [total],
35[books statistics] [given] = [src] [given],
36[books statistics] [rest] = [src] [rest]
37FROM [books statistics]
38JOIN
39(SELECT ISNULL [total], 0) AS [total],
40 |
|
ISNULL [given], 0) AS [given], |
||
41 |
|
ISNULL [total] - [given], 0 |
AS [rest] |
|
42 |
FROM |
(SELECT (SELECT SUM([b quantity]) |
||
43 |
|
FROM |
[books] |
AS [total], |
44 |
|
(SELECT COUNT [sb book]) |
||
45 |
|
FROM |
[subscriptions] |
|
46 |
|
WHERE |
[sb is active] = 'Y') AS [given]) |
|
47 |
|
AS [prepared data] |
|
48) AS [src]
49ON 1 1;
50END;
51END;
52GO
Для проверки корректности полученного решения можно выполнить следующие запросы.
MS SQL |
Решение 5.2.3.a (проверка работоспособности) |
DROP TABLE [books_statistics];
EXECUTE CREATE_BOOKS_STATISTICS;
SELECT * FROM [books statistics];
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 428/545
Пример 40: управление структурами базы данных с помощью хранимых процедур
Решение для Oracle выглядит следующим образом. Обратите внимание на то, как реализована проверка существования таблицы books_statistics: т.к. Oracle не поддерживает вариант с IF NOT EXISTS, мы вынуждены поместить в переменную количество найденных рядов и затем проверить его значение в блоке IF.
Orac |
?le 1 Решение 5.2.3.a (код процедуры) |
І |
|
1 |
|
|
|
2 |
|
|
|
3 |
|
|
|
4 |
CREATE OR REPLACE PROCEDURE CREATE_BOOKS_STATISTICS |
||
5 |
AS table_found NUMBER(1) : |
0 |
|
6 |
BEGIN |
|
|
7 |
|
|
|
8 |
SELECT COUNT 1 INTO table_found |
||
9 |
FROM |
ALL_TABLES |
|
10 |
WHERE |
OWNER=USER |
|
11 |
AND |
TABLE_NAME = 'books_statistics'; |
|
12 |
|
|
|
13IF table_found = 0)
14THEN
15EXECUTE IMMEDIATE 'CREATE TABLE "books_statistics
16(
17"total" NUMBER(10),
18"given" NUMBER(10),
19"rest" NUMBER(10)
20)' ;
45 |
END IF; |
|
|
46 |
|
|
|
END; |
|
|
|
47 |
|
|
|
/ |
|
|
|
48 |
|
|
|
21 |
EXECUTE IMMEDIATE 'INSERT INTO |
||
22 |
|
|
"books_statistics |
23 |
" |
|
|
24 |
("total", "given", "rest") |
||
25 |
SELECT "total", |
|
|
26 |
|
"given", |
|
27 |
|
("total" - "given") AS "rest" |
|
28 |
FROM |
(SELECT SUM("b_quantity") AS "total" |
|
29 |
|
FROM |
"books") |
30 |
JOIN (SELECT COUNT("sb_book") AS"given" |
||
31 |
|
FROM |
"subscriptions" |
32 |
|
WHERE |
"sb_is_active" =''Y'') |
33 |
ON 1 = 1'; |
|
|
34 |
|
|
|
35 |
ELSE |
|
|
36 |
EXECUTE IMMEDIATE 'UPDATE "books_statistics" |
||
37 |
SET ("total", "given", "rest") = (SELECT |
||
38 |
"total", "given", ("total" - "given") AS "rest" |
||
39 |
FROM |
(SELECT SUM("b_quantity") AS "total" |
|
40 |
|
FROM |
"books") |
41 |
JOIN (SELECT COUNT("sb_book") AS "given" |
||
42 |
|
FROM |
"subscriptions" |
43 |
|
WHERE |
"sb_is_active" = ''Y'') |
44 |
ON 1 = 1)'; |
|
|
|
|
Для проверки корректности полученного решения можно выполнить следующие запросы.
Oracle |
Решение 5.2.3.а (проверка работоспособности) |
DROP TABLE "books_statistics"
2EXECUTE CREATE_BOOKS_STATISTICS;
3SELECT * FROM "books statistics"1
На этом решение данной задачи завершено.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 429/545