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

Пример 39: оптимизация производительности с помощью хранимых процедур

MS SQL Решение 5.2.2.a (код процедуры)

1CREATE PROCEDURE UPDATE_BOOKS_STATISTICS

2AS

3IF (NOT EXISTS(SELECT *

4

 

FROM [information_schema].[tables]

5

 

WHERE

[table_catalog] = DB_NAME()

6

 

AND

[table_name] = 'books_statistics'))

7BEGIN

8RAISERROR ('The [books_statistics] table is missing.', 16, 1);

9RETURN;

10END;

11

12UPDATE [books_statistics]

13SET

14[books_statistics].[total] = [src].[total],

15[books_statistics].[given] = [src].[given],

16[books_statistics].[rest] = [src].[rest]

17FROM [books_statistics]

18JOIN

19(SELECT 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])

27AS [prepared_data]

28) AS [src]

29ON 1=1;

30GO

Проверим работоспособность (предварительно можно выполнить отдельный запрос на обновление данных в таблице books_statistics и установить все значения в ноль).

MS SQL Решение 5.2.2.a (запуск и проверка работоспособности)

1 EXECUTE UPDATE_BOOKS_STATISTICS

Установка запуска полученной хранимой процедуры по расписанию в MS SQL Server не только выглядит куда более сложно, но и не даст эффекта, если вы используете Express Edition этой СУБД: в этой версии отсутствует компонент SQL Server Agent, который и отвечает за выполнение запланированных задач.

По каждой приведённой далее команде в официальной документации написано очень много (перед каждой командой специально приведены ссылка на соответствующий раздел документации), но если выразить простыми словами алгоритм, получится следующее. Необходимо:

Создать задачу.

Создать шаг задачи, описывающий запуск нашей хранимой процедуры.

Создать расписание, в котором указать требуемую периодичность выполнения.

Прикрепить ранее созданную задачу к только что созданному расписанию.

Передать созданную задачу на обработку в SQL Server Agent.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 390/545

Пример 39: оптимизация производительности с помощью хранимых процедур

MS SQL

Решение 5.2.2.a (установка запуска по расписанию)

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_jobstep

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 = 000100 ;

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 Server Express Edition):

MS SQL Решение 5.2.2.a (просмотр расписания)

1 SELECT * FROM msdb.dbo.sysschedules

В данном обсуждении24 представлен очень хороший готовый SQL-скрипт для получения в удобной форме информации обо всех запланированных в MS SQL Server задачах.

На этом решение для MS SQL Server завершено.

Переходим к Oracle. Логика работы хранимой процедуры здесь полностью эквивалентна решениям для MySQL и MS SQL Server: мы проверяем наличие таблицы books_statistics в строках 5-15 (и завершаем работу хранимой процедуры, если таблицы нет), а в строках 17-27 выполняем запрос, обновляющий данные.

24 http://www.sqlservercentral.com/Forums/Topic410557-116-1.aspx

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 391/545

Пример 39: оптимизация производительности с помощью хранимых процедур

Oracle Решение 5.2.2.a (код процедуры)

1CREATE OR REPLACE PROCEDURE UPDATE_BOOKS_STATISTICS

2AS

3rows_count NUMBER;

4BEGIN

5SELECT COUNT(1) INTO rows_count

6FROM ALL_TABLES

7WHERE OWNER = USER

8AND TABLE_NAME = 'books_statistics';

9

10IF (rows_count = 0)

11THEN

12RAISE_APPLICATION_ERROR(-20001,

13

 

'The "books_statistics" table is missing.');

14RETURN;

15END IF;

16

17UPDATE "books_statistics"

18SET ("total", "given", "rest") =

19(SELECT NVL("total", 0) AS "total",

20

 

 

NVL("given", 0)

AS "given",

 

21

 

 

NVL("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

 

 

FROM dual) "prepared_data");

 

28END;

29/

Проверим работоспособность (предварительно можно выполнить отдельный запрос на обновление данных в таблице books_statistics и установить все значения в ноль).

Oracle

Решение 5.2.2.a (запуск и проверка работоспособности)

1 EXECUTE UPDATE_BOOKS_STATISTICS

Установка запуска полученной хранимой процедуры по расписанию выглядит следующим образом.

Oracle

 

Решение 5.2.2.a (установка запуска по расписанию)

1

BEGIN

 

 

2

 

DBMS_SCHEDULER.CREATE_JOB (

3

 

job_name

=> 'hourly_update_books_statistics',

4

 

job_type

=> 'STORED_PROCEDURE',

5

 

job_action

=> 'UPDATE_BOOKS_STATISTICS',

6

 

start_date

=>

'01-APR-16 1.00.00 AM',

7

 

repeat_interval

=>

'FREQ=HOURLY;INTERVAL=1',

8

 

auto_drop

=>

FALSE,

9

 

enabled

=>

TRUE);

10

END;

 

 

Убедиться, что соответствующая задача добавлена в планировщик, можно выполнив следующий запрос:

Oracle Решение 5.2.2.a (просмотр расписания)

1 SELECT * FROM ALL_SCHEDULER_JOBS WHERE OWNER=USER

На этом решение данной задачи завершено.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 392/545

Пример 39: оптимизация производительности с помощью хранимых процедур

Решение 5.2.2.b{388}.

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

Вопрос оптимизации производительности баз данных и СУБД заслуживает отдельной книги, потому здесь мы пойдём по пути наименьшего сопротивления и будем считать, что:

Для MySQL будет достаточно выполнить OPTIMIZE для всех таблиц.

Для MS SQL Server достаточно выполнить REORGANIZE или REBUILD для всех кластерных индексов (что приводит к оптимизации соответствующей таблицы, на которых построен индекс).

Для Oracle будет достаточно выполнить SHRINK SPACE COMPACT CASCADE для всех таблиц.

Ещё раз особо подчеркнём: решение данной задачи носит исключительно демонстрационный характер и не должно рассматриваться как рекомендация по универсальной оптимизации производительности. В некоторых случаях выполнение показанных ниже действий может снизить производительность базы данных, потому обязательно внимательно изучите официальную документацию по соответствующей СУБД и профессиональные рекомендации по оптимизации производительности в той или иной реальной ситуации.

Традиционно начинаем с MySQL.

MySQL Решение 5.2.2.b (код процедуры)

1DELIMITER $$

2CREATE PROCEDURE OPTIMIZE_ALL_TABLES()

3BEGIN

4DECLARE done INT DEFAULT 0;

5DECLARE tbl_name VARCHAR(200) DEFAULT '';

6DECLARE all_tables_cursor CURSOR FOR

7SELECT `table_name`

8

 

FROM

`information_schema`.`tables`

9

 

WHERE

`table_schema` = DATABASE()

10

 

AND

`table_type` = 'BASE TABLE';

11

 

DECLARE

CONTINUE HANDLER FOR NOT FOUND SET done = 1;

12

 

 

 

13

 

OPEN all_tables_cursor;

14

 

 

 

15tables_loop: LOOP

16FETCH all_tables_cursor INTO tbl_name;

17IF done THEN

18LEAVE tables_loop;

19END IF;

20

21SET @table_opt_query = CONCAT('OPTIMIZE TABLE `', tbl_name, '`');

22PREPARE table_opt_stmt FROM @table_opt_query;

23EXECUTE table_opt_stmt;

24DEALLOCATE PREPARE table_opt_stmt;

25

26 END LOOP tables_loop;

27

28CLOSE all_tables_cursor;

29END;

30$$

31

32 DELIMITER ;

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 393/545

Пример 39: оптимизация производительности с помощью хранимых процедур

Запрос в строках 7-10 позволяет получить список таблиц текущей базы данных (часть условия в строке 10 позволяет отличить таблицы от представлений), после чего:

для полученного списка таблиц открывается курсор (строка 13);

для всех строк курсора выполняется цикл (строки 15-26);

в теле цикла формируется (строка 21) и выполняется (строки 22-23) запрос, реализующий оптимизацию таблицы.

Запустить полученную хранимую процедуру можно следующим образом.

MySQL

Решение 5.2.2.b (запуск и проверка работоспособности)

1 CALL OPTIMIZE_ALL_TABLES

Теперь остаётся создать событие, запускаемое планировщиком задач MySQL по определённому расписанию. Это реализуется следующим кодом.

MySQL

Решение 5.2.2.b (установка запуска по расписанию)

1 SET GLOBAL event_scheduler = ON;

2

3CREATE EVENT `optimize_all_tables_daily`

4ON SCHEDULE

5EVERY 1 DAY

6STARTS DATE(NOW()) + INTERVAL 1 HOUR

7ON COMPLETION PRESERVE

8DO

9CALL OPTIMIZE_ALL_TABLES;

Убедиться, что событие добавлено, можно следующим запросом.

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

STA-

ON_COM-

 

 

VAL_VALUE

VAL_FIELD

 

 

TUS

PLETION

update_books_statis-

RECURRING

1

HOUR

2016-04-27

NULL

ENA-

PRESERVE

tics_hourly

 

 

 

14:01:00

 

BLED

 

optimize_all_ta-

RECURRING

1

DAY

2016-04-27

NULL

ENA-

PRESERVE

bles_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 Стр: 394/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

 

 

[stats].[avg_fragmentation_in_percent]

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 [stats]

21

 

 

ON

[indexes].[object_id] = [stats].[object_id]

22

 

 

 

AND [indexes].[index_id] = [stats].[index_id]

 

 

 

 

 

 

23ORDER 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_type

 

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_gen-

2

NONCLUS-

309576141

g_name

0

 

2.37212750185322

 

res_g_name

 

TERED INDEX

 

 

 

 

 

m2m_books

PK_m2m_boo

1

CLUSTERED

341576255

b_id

0

 

1.86557944156165

_authors

ks_authors

 

INDEX

 

 

 

 

 

m2m_books

PK_m2m_boo

1

CLUSTERED

341576255

a_id

0

 

1.86557944156165

_authors

ks_authors

 

INDEX

 

 

 

 

 

m2m_books

PK_m2m_boo

1

CLUSTERED

373576369

b_id

0

 

2.28564368668149

_genres

ks_genres

 

INDEX

 

 

 

 

 

m2m_books

PK_m2m_boo

1

CLUSTERED

373576369

g_id

0

 

2.28564368668149

_genres

ks_genres

 

INDEX

 

 

 

 

 

subscribers

PK_subscrib-

1

CLUSTERED

405576483

s_id

0

 

1.95206325673338

 

ers

 

INDEX

 

 

 

 

 

subscrip-

PK_subscrip-

1

CLUSTERED

437576597

sb_id

0

 

5.16431924882629

tions

tions

 

INDEX

 

 

 

 

 

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

Упростим запрос так, чтобы оставить только необходимые данные.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 395/545

Пример 39: оптимизация производительности с помощью хранимых процедур

 

MS SQL

 

Решение 5.2.2.b (получение краткого набора данных по всем индексам)

 

1

 

SELECT

DISTINCT

 

 

2

 

 

 

[tables].[name]

AS [table_name],

 

3

 

 

 

[indexes].[name]

AS [index_name],

 

4

 

 

 

[stats].[avg_fragmentation_in_percent]

AS [avg_fragm_perc]

 

5

 

FROM

sys.indexes AS [indexes]

 

 

6

 

 

 

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,

 

10

 

 

 

 

'SAMPLED') AS [stats]

 

11

 

 

 

ON [indexes].[object_id] = [stats].[object_id]

12

 

 

 

AND [indexes].[index_id] = [stats].[index_id]

13WHERE [indexes].[type] = 1

14ORDER BY [tables].[name],

15[indexes].[name]

Врезультате выполнение такого запроса мы получим следующие данные.

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 Решение 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]

 

 

 

 

 

 

21WHERE [indexes].[type] = 1

22ORDER 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 Стр: 396/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_jobstep

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 Стр: 397/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

enabled

freq_type

freq_inter-

freq_sub-

freq_subday_in-

ac-

ac-

 

 

 

val

day_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"

7 FROM 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 Стр: 398/545

Пример 39: оптимизация производительности с помощью хранимых процедур

Концепция представленного решения основана на этой рекомендации26. Итак, мы должны будем получить список всех таблиц, а затем для каждой из них сначала разрешить перемещение рядов, потом выполнить компактификацию и, наконец, снова запретить перемещение рядов. В отличие от MS SQL Server все запросы здесь совершенно тривиальны.

Запустить полученную хранимую процедуру можно следующим образом.

Oracle

Решение 5.2.2.b (запуск и проверка работоспособности)

1SET SERVEROUTPUT ON;

2EXECUTE OPTIMIZE_ALL_TABLES;

Теперь остаётся создать событие, запускаемое планировщиком задач Oracle по определённому расписанию. Это реализуется следующим кодом.

Oracle

 

Решение 5.2.2.b (установка запуска по расписанию)

1

BEGIN

 

 

2

 

DBMS_SCHEDULER.CREATE_JOB (

3

 

job_name

=> 'daily_optimize_all_tables',

4

 

job_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 Стр: 399/545