库表变更、加锁没审计?PolarDB MySQL 新功能 SQL Detail
Author: 勉仁
PolarDB MySQL最新引入了库表变更、加锁操作的详细审计功能SQL Detail。
背景
在数据库使用过程中,库表的变更,例如删除、创建、增加列和索引等都是非常敏感的。对库表的加锁也会影响整个业务的使用。对应操作的审计日志对于数据库的运维人员就非常重要,需要能够知道操作的用户账号、客户端IP、操作时间、完成时间等详细信息。
以往的审计日志基本都是全局开关,对所有SQL语句都做审计。这样记录的SQL全面,但成本也会很高。同时很多时候需要额外的组件存储信息,维护和信息安全控制的成本也高。而对业务会造成重大影响的很多由库表操作引发,这部分的审计很多时候又不可或缺。
因此PolarDB MySQL内核开发了能够对库表变更、加锁操作的详细审计功能SQL Detail。同时该功能的审计记录存储在用户数据库实例中,用户可以配置审计记录的保存时间,审计记录过期后会自动删除。该功能审计的成本极低,以每条审计记录存储1KB,每天库表变更1024次,审计保存30天算,仅需要30M的存储空间。该功能在相关语句开始执行时就会捕获到,记录到相关系统表中,并会在执行结束时进一步更新相关状态。
下面会对该功能的使用做详细的介绍。
功能介绍
功能开关与相关变量
- 功能开关
用户可以通过全局参数awr_sqldetail_enabled来开启SQL Detail功能(在阿里云PolarDB实例控制台上搜索参数loose_awr_sqldetail_enabled)。该参数的配置无需重启实例。
- 审计SQL类型子开关
通过全局参数awr_sqldetail_switch可以控制库表变更或者库表加锁释放锁是否记录。作为一个switch变量,当前有两个子开关,ddl(是否记录DDL变更)和lock_db_table(是否记录库表加锁释放锁)。ddl和lock_db_table默认都是开启的,即默认值为’ddl=on,lock_db_table=on’。
DDL包括的语句类型如下:
create_table、alter_table、drop_table、rename_table、create_index、drop_index、create_db、drop_db、alter_db、create_view、drop_view、create_trigger、drop_trigger、create_event、alter_event、create_function、create_procedure、drop_procedure、drop_function、alter_procedure、alter_function、truncate、alter_tablespace、repair、optimize、install_plugin、uninstall_plugin、install_component、uninstall_component、alter_instance、import、create_spatial_reference_system、drop_spatial_reference_system。
LOCK_DB_TABLE包括的语句类型如下:
lock_tables、unlock_tables。
- 审计保存时间定义
通过全局参数awr_sqldetail_retention可以配置SQL Detail审计记录的保存时间,其单位是秒。当审计记录保存超过该时候后,内核会通过后台线程自动淘汰该记录。该参数默认值是:2592000(30天)。
审计记录表
SQL Detail功能的记录存储在一张新的PolarDB系统表sys.hist_sqldetail中。该表的定义如下:
1. CREATE TABLE `hist_sqldetail` (
2. `Id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
3. `State` varchar(16) COLLATE utf8mb4_bin DEFAULT NULL,
4. `Thread_id` bigint(20) unsigned DEFAULT NULL,
5. `Host` varchar(60) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
6. `User` varchar(32) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
7. `Client_ip` varchar(60) COLLATE utf8mb4_bin DEFAULT NULL,
8. `Db` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL,
9. `Sql_text` mediumtext COLLATE utf8mb4_bin NOT NULL,
10. `Server_command` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
11. `Sql_command` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL,
12. `Start_time` timestamp(6) NULL DEFAULT NULL,
13. `Exec_time` bigint(20) DEFAULT NULL,
14. `Wait_time` bigint(20) DEFAULT NULL,
15. `Error_code` int(11) DEFAULT NULL,
16. `Rows_sent` bigint(20) DEFAULT NULL,
17. `Rows_examined` bigint(20) DEFAULT NULL,
18. `Rows_affected` bigint(20) DEFAULT NULL,
19. `Logical_read` bigint(20) DEFAULT NULL,
20. `Phy_sync_read` bigint(20) DEFAULT NULL,
21. `Phy_async_read` bigint(20) DEFAULT NULL,
22. `Process_info` text COLLATE utf8mb4_bin,
23. `Extra` text COLLATE utf8mb4_bin,
24. `Create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
25. `Update_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
26. PRIMARY KEY (`Id`),
27. KEY `i_start_time` (`Start_time`),
28. KEY `i_update_time` (`Update_time`)
29. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
该表各个字段表示的意义如下。可以看到该表会详细的记录库表变更、锁操作。
| 字段 | 描述 |
|---|---|
| Id | sys.hist_sqldetail表的自增ID。 |
| State | 该操作被记录时所处的状态。 |
| Thread_id | 执行该SQL会话的线程ID |
| Host | 执行该SQL会话的用户Host |
| User | 执行该SQL会话的用户名 |
| Client_ip | 执行该SQL会话的客户端IP |
| Db | 该SQL执行时所在的DB |
| Sql_text | 具体SQL |
| Server_command | 执行该SQL的server命令 |
| Sql_command | 命令类型 |
| Start_time | 开始执行的时间 |
| Exec_time | 执行时间,单位微秒 |
| Wait_time | 等待时间,单位微秒 |
| Error_code | 错误码 |
| Rows_sent | 返回的数据行 |
| Rows_examined | 扫描的数据行 |
| Rows_affected | 影响的行数 |
| Logical_read | 逻辑读次数 |
| Phy_sync_read | 物理同步读次数 |
| Phy_async_read | 物理异步读次数 |
| Process_info | 扩展字段,处理过程信息。 |
| Extra | 扩展字段,其他信息。 |
| Create_time | 记录写入时间 |
| Update_time | 记录更新时间 |
使用示例
配置awr_sqldetail_enabled为ON后,SQL Detail功能就会自动记录DDL,LOCK DB\TABLE操作,并自动管理这些记录。例如配置awr_sqldetail_enabled为ON后,我们在test库下做如下操作:
1. mysql> create table t(c1 int);
2. Query OK, 0 rows affected (0.02 sec)
4. mysql> create table t(c1 int);
5. ERROR 1050 (42S01): Table 't' already exists
7. mysql> alter table t add column c2 int;
8. Query OK, 0 rows affected (0.02 sec)
9. Records: 0 Duplicates: 0 Warnings: 0
11. mysql> lock tables t read;
12. Query OK, 0 rows affected (0.00 sec)
14. mysql> unlock tables;
15. Query OK, 0 rows affected (0.00 sec)
17. mysql> insert into t values(1, 2);
18. Query OK, 1 row affected (0.00 sec)
执行完后,我们可以通过sys.hist_sqldetail查看上述操作中DDL和LOCK DB\TABLE的信息,而DML语句不会被记录。
1. mysql> select * from sys.hist_sqldetail\G
2. *************************** 1. row ***************************
3. Id: 1
4. State: FINISH
5. Thread_id: 18
6. Host: localhost
7. User: root
8. Client_ip: 127.0.0.1
9. Db: test
10. Sql_text: create table t(c1 int)
11. Server_command: Query
12. Sql_command: create_table
13. Start_time: 2023-01-13 16:18:21.840435
14. Exec_time: 17390
15. Wait_time: 318
16. Error_code: 0
17. Rows_sent: 0
18. Rows_examined: 0
19. Rows_affected: 0
20. Logical_read: 420
21. Phy_sync_read: 0
22. Phy_async_read: 0
23. Process_info: NULL
24. Extra: NULL
25. Create_time: 2023-01-13 16:18:22.391407
26. Update_time: 2023-01-13 16:18:22.391407
27. *************************** 2. row ***************************
28. Id: 2
29. State: FINISH
30. Thread_id: 18
31. Host: localhost
32. User: root
33. Client_ip: 127.0.0.1
34. Db: test
35. Sql_text: create table t(c1 int)
36. Server_command: Query
37. Sql_command: create_table
38. Start_time: 2023-01-13 16:18:22.416321
39. Exec_time: 822
40. Wait_time: 229
41. Error_code: 1050
42. Rows_sent: 0
43. Rows_examined: 0
44. Rows_affected: 0
45. Logical_read: 55
46. Phy_sync_read: 0
47. Phy_async_read: 0
48. Process_info: NULL
49. Extra: NULL
50. Create_time: 2023-01-13 16:18:23.393071
51. Update_time: 2023-01-13 16:18:23.393071
52. *************************** 3. row ***************************
53. Id: 3
54. State: FINISH
55. Thread_id: 18
56. Host: localhost
57. User: root
58. Client_ip: 127.0.0.1
59. Db: test
60. Sql_text: alter table t add column c2 int
61. Server_command: Query
62. Sql_command: alter_table
63. Start_time: 2023-01-13 16:18:34.123947
64. Exec_time: 16420
65. Wait_time: 245
66. Error_code: 0
67. Rows_sent: 0
68. Rows_examined: 0
69. Rows_affected: 0
70. Logical_read: 778
71. Phy_sync_read: 0
72. Phy_async_read: 0
73. Process_info: NULL
74. Extra: NULL
75. Create_time: 2023-01-13 16:18:34.394067
76. Update_time: 2023-01-13 16:18:34.394067
77. *************************** 4. row ***************************
78. Id: 4
79. State: FINISH
80. Thread_id: 18
81. Host: localhost
82. User: root
83. Client_ip: 127.0.0.1
84. Db: test
85. Sql_text: lock tables t read
86. Server_command: Query
87. Sql_command: lock_tables
88. Start_time: 2023-01-13 16:19:49.891559
89. Exec_time: 145
90. Wait_time: 129
91. Error_code: 0
92. Rows_sent: 0
93. Rows_examined: 0
94. Rows_affected: 0
95. Logical_read: 0
96. Phy_sync_read: 0
97. Phy_async_read: 0
98. Process_info: NULL
99. Extra: NULL
100. Create_time: 2023-01-13 16:19:50.399585
101. Update_time: 2023-01-13 16:19:50.399585
102. *************************** 5. row ***************************
103. Id: 5
104. State: FINISH
105. Thread_id: 18
106. Host: localhost
107. User: root
108. Client_ip: 127.0.0.1
109. Db: test
110. Sql_text: unlock tables
111. Server_command: Query
112. Sql_command: unlock_tables
113. Start_time: 2023-01-13 16:19:56.924648
114. Exec_time: 98
115. Wait_time: 0
116. Error_code: 0
117. Rows_sent: 0
118. Rows_examined: 0
119. Rows_affected: 0
120. Logical_read: 0
121. Phy_sync_read: 0
122. Phy_async_read: 0
123. Process_info: NULL
124. Extra: NULL
125. Create_time: 2023-01-13 16:19:57.400294
126. Update_time: 2023-01-13 16:19:57.400294
SQL Detail在DDL开始执行时就会被捕获记录到系统表中。我们做如下操作
1. create table t1 as select c1, sleep(10) from t;
在上述DDL执行时,我们用另一个session查看sys.hist_sqldetail,可以看到处理PROCESS状态的审计记录。当该语句执行完,相关状态会被自动更新。
1. select * from sys.hist_sqldetail where state='PROCESS'\G
2. *************************** 1. row ***************************
3. Id: xx
4. State: PROCESS
5. Thread_id: 36
6. Host: localhost
7. User: root
8. Client_ip: 127.0.0.1
9. Db: test
10. Sql_text: create table t1 as select c1, sleep(10) from t
11. Server_command: Query
12. Sql_command: create_table
13. Start_time: 2023-01-19 17:34:42.293752
14. Exec_time: 0
15. Wait_time: 0
16. Error_code: 0
17. Rows_sent: 0
18. Rows_examined: 0
19. Rows_affected: 0
20. Logical_read: 0
21. Phy_sync_read: 0
22. Phy_async_read: 0
23. Process_info: NULL
24. Extra: NULL
25. Create_time: 2023-01-19 17:34:42.641854
26. Update_time: 2023-01-19 17:34:42.641854
总结
PolarDB MySQL新功能SQL Detail可以详细记录用户的各类库表变更操作,并且可以自动淘汰过期记录,帮助用户以极低的成本对库表操作做审计工作。
