【PostgreSQL内核】Trigger的一生

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: 前言本文简单介绍 PostgreSQL 数据库的 Trigger 从创建、存储、触发、执行、修改,到删除的过程,贯穿 Trigger 的一生。文中引用的函数、结构体来源于 PG 14 源码,分支为 REL_14_STABLE,对应的 commit id 如下。此外还引用了 PG 14 官方文档。commit be0b0528cb64d49750fcb632faa2cfcd8d920be2Auth

前言

本文简单介绍 PostgreSQL 数据库的 Trigger 从创建、存储、触发、执行、修改,到删除的过程,贯穿 Trigger 的一生。

文中引用的函数、结构体来源于 PG 14 源码,分支为 REL_14_STABLE,对应的 commit id 如下。此外还引用了 PG 14 官方文档

commit be0b0528cb64d49750fcb632faa2cfcd8d920be2
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date:   Fri Sep 9 15:34:04 2022 -0400
Fix possible omission of variable storage markers in ECPG.

触发器简介

Trigger 即触发器,它可以在特定事件发生时,对数据库中的对象执行特定操作:

  • 这里的 事件可以是向某张表插入、更新、删除数据,也可以是执行某个 DDL 语句
  • 触发后执行的 操作可以是插入、更新、删除、查询数据等。

根据触发事件的不同,PG 的触发器分为两类:

  • Trigger,普通的触发器,通过 DML 操作触发,比如表上的插入、更新、删除数据的操作
  • Event Trigger,事件触发器,通过 DDL 等事件触发,比如创建表、删除表等操作

另外,不同数据库中触发器的分类有所不同,比如 Oracle 分为 DML Trigger 和 System Trigger,SQL Server 分为 DML Trigger、DDL Trigger 和 Login Trigger,不论其如何划分,多数都可以与 PG 的触发器对应上。

创建触发器

语法

首先介绍创建触发器的 SQL 和 PLpgSQL 语法。

Trigger

根据 PG 官方文档,创建 Trigger的语法如下:

CREATE [ CONSTRAINT ] TRIGGER name { BEFORE | AFTER | INSTEAD OF } { event [ OR ... ] }
    ON table_name
    [ FROM referenced_table_name ]
    [ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ]
    [ REFERENCING { { OLD | NEW } TABLE [ AS ] transition_relation_name } [ ... ] ]
    [ FOR [ EACH ] { ROW | STATEMENT } ]
    [ WHEN ( condition ) ]
    EXECUTE { FUNCTION | PROCEDURE } function_name ( arguments )

event可以是下列之一:
    INSERT
    UPDATE [ OF column_name [, ... ] ]
    DELETE
    TRUNCATE
  • 触发器可以定义在 INSERT、UPDATE、DELETE、TRUNCATE 事件上;可以在事件发生前、发生后触发,还可以取代事件(INSTEAD OF);可通过 WHEN condition 指定触发条件
  • 行级触发器(ROW )对一次 DML 操作涉及的每一行都触发, 语句级触发器( STATEMENT)对一次 DML 只触发一次
  • 若将触发器定义成 约束(Constraint)触发器,可设置触发时机为可延迟(DEFERRABLE)
  • 触发器需要创建在表(或者视图)上, 依赖于表而存在。也正因为如此,触发器本身不属于任何模式(schema),因此不可在创建触发器指定 schema
  • 触发以后需要执行的操作由 EXECUTE 语句的函数(或者存储过程,为方便描述,统一称为函数)决定,该函数通常由用户自定义, 返回值类型必须为 trigger
  • OLD、NEW 为上下文信息,分别对应事件发生前和发生后的表,以 UPDATE 操作为例,OLD.a 表示被更新的行中 a 列的旧值,NEW.a 则表示更新后的新值。需要注意的是:
  • OLD、NEW 表示某一行的内容,只对行级触发器有效,对语句级触发器无效
  • INSERT 操作只有新值 NEW,没有旧值 OLD
  • DELETE 操作只有旧值 OLD,没有新值 NEW

下面以表 t1、t2 为例创建一个简单的触发器示例。表的定义如下:

CREATE TABLE t1 (
  a INTEGER,
  b TEXT
);

CREATE TABLE t2 (
  c INTEGER,
  d TEXT
);

触发器定义如下,是表 t1 上的行级触发器,对 t1 进行 INSERT 之后会触发,并执行 insert_into_t2 函数,将插入到 t1 的数据也插入到 t2。

CREATE TRIGGER after_insert_into_t1
    AFTER INSERT ON t1
    FOR EACH ROW
    EXECUTE FUNCTION insert_into_t2();

insert_into_t2 函数定义如下,其中引用了上下文信息 NEW,表示插入到 t1 的数据,并将其插入到 t2。

CREATE OR REPLACE FUNCTION insert_into_t2()
RETURNS trigger AS $$
BEGIN
  INSERT INTO t2 VALUES (NEW.a, NEW.b);
	RETURN NEW;
END;
$$ language plpgsql;

Event Trigger

创建 Event Trigger的语法如下,相比 Trigger 的语法要简单很多

CREATE EVENT TRIGGER name
    ON event
    [ WHEN filter_variable IN (filter_value [, ... ]) [ AND ... ] ]
    EXECUTE { FUNCTION | PROCEDURE } function_name()
  • event 表示触发事件,目前仅 支持  ddl_command_start ddl_command_end table_rewrite  和  sql_drop
  • WHEN filter_variable 用于过滤部分事件,当前仅支持 TAG 变量
  • 事件触发器并不依赖于表而存在
  • 事件触发器不能定义为约束触发器,不可延迟

以下是 PG 官方文档中的一个简单示例,该 Event Trigger 可以在任何 DDL 语句执行之前触发,并抛出异常,禁止执行任何 DDL 语句。

CREATE EVENT TRIGGER abort_ddl ON ddl_command_start
   EXECUTE FUNCTION abort_any_command();

CREATE OR REPLACE FUNCTION abort_any_command()
RETURNS event_trigger AS $$
BEGIN
  RAISE EXCEPTION 'command % is disabled', tg_tag;
END;
$$ LANGUAGE plpgsql;

创建流程

简单介绍创建触发器时 PG 内核中的函数调用流程。

Trigger

CREATE TRIGGER 命令都属于 DDL 语句,所以会进入 DDL 的处理流程,关键的调用路径为:

ProcessUtilitySlow-->CreateTrigger-->CreateTriggerFiringOn,CreateTriggerFiringOn 函数代码超过 1000 行,因此只介绍其中的关键步骤:

  • 根据表的 oid,打开触发器所在的表,加上 ShareRowExclusiveLock 锁
  • 进行各种合法性检查,过滤不合理的触发器类型,如果检查不通过,直接报错。(之所以要在内核中检查,是因为语法模块无法进行如此复杂的检查)
  • 检查对象类型,触发器只能创建在表、视图上
  • 表和分区表上只能创建 BEFORE、AFTER 触发器,不能创建 INSTEAD OF 触发器
  • 视图上不能创建行级的 BEFORE、AFTER 触发器,且不能创建 TRUNCATE 触发器
  • 外表上不能创建 INSTEAD OF 触发器、TRUNCATE 触发器、约束触发器
  • 不允许行级的 TRUNCATE 触发器
  • INSTEAD OF 触发器必须为行级、不能有 WHEN 条件、不能指定列名
  • 默认不允许在系统表创建触发器(但是可以通过设置 allow_system_table_mods 参数放开限制)
  • REFERENCING 语句不能使用行变量名,只能使用 OLD、NEW 的表别名
  • 外表约束和视图上的约束不能使用 REFERENCING
  • 对于约束触发器,还需要对约束所在的表加上 AccessShareLock,防止 drop table
  • ……
  • 表的 ACL 权限检查
  • 解析 WHEN 条件语句,并进行各种限制条件判断,比如语句级触发器的 WHEN 条件不能引用列名、INSERT 触发器的 WHEN 条件不能引用 OLD……
  • 获取触发器函数,检查其合法性,检查 ACL 权限,检查返回值是否为 trigger
  • 用 table_open 函数 打开 pg_trigger 系统表,对其加上 RowExclusiveLock 锁,并 检查其中是否已经存在同名触发器
  • 在同一个表上,触发器不可重名,但是不同表上的触发器可以重名
  • 假如使用了 CREATE OR REPLACE TRIGGER 语法,则替换原有的同名触发器(官方文档中并没有提到这种语法,但是代码中却进行了检查)
  • 若检查通过,则用 GetNewOidWithIndex 函数为触发器生成一个新的 oid
  • 调用 heap_form_tuple 函数, 在 pg_trigger 系统表中增加一个元组,存储该触发器的各项信息
  • 对于约束触发器,还需要使用 CreateConstraintEntry 函数 在 pg_constraint 系统表中增加一行
  • 用 table_open 函数打开 pg_class 系统表, 更新触发器所在的表在 pg_class 中的信息,并发送信息给后端 更新 relcache 中的系统表信息
  • 调用 recordDependencyOn 记录触发器的依赖关系
  • 最后,对于分区表上的行级触发器,需要对所有分区都递归创建触发器

Event Trigger

CREATE EVENT TRIGGER 的关键调用路径为:standard_ProcessUtility-->CreateEventTrigger,该函数流程相对简单很多:

  • 检查用户权限, 只允许超级用户创建事件触发器,对其他用户报错
  • 检查  event,只能为  ddl_command_start ddl_command_end table_rewrite  或  sql_drop
  • 检查过滤条件, 当前仅支持 tag
  • 调用 SearchSysCache1 函数, 检查同名触发器,重名就报错(与 Trigger 不同,名字必须全局唯一,因为 Event Trigger 不属于任何表)
  • 检查 触发器函数的返回值是否为 event_trigger
  • 调用 insert_event_trigger_tuple 函数: 在 pg_event_trigger 系统表中插入一条记录

触发器的存储

用户创建的触发器必须持久化到数据库中,具体的存储位置是触发器相关的系统表中。

Trigger

Trigger 存储在pg_trigger 系统表中,表中的关键字段如下,包含触发器所在的表、触发器名、触发器调用的函数、是否可推迟等属性。总之,通过 CREATE TRIGGER 创建触发器时指定的任何信息都会存储到系统表中。

字段

描述

oid

触发器的 id

tgrelid

触发器所在的表

tgname

触发器名(在同一个表的触发器中必须唯一)

tgfoid

触发器调用的函数

tgdeferrable

约束触发器是否可推迟

tginitdeferred

约束触发器是否初始可推迟

pg_trigger 系统表的各个字段在内存中用 Trigger 结构体表示,定义如下,可见其成员变量与 pg_trigger 的属性是一一对应的。

typedef struct Trigger
{
    Oid			tgoid;			/* OID of trigger (pg_trigger row) */
    /* Remaining fields are copied from pg_trigger, see pg_trigger.h */
    char	   *tgname;
    Oid			tgfoid;
    int16		tgtype;
    char		tgenabled;
    bool		tgisinternal;
    bool		tgisclone;
    Oid			tgconstrrelid;
    Oid			tgconstrindid;
    Oid			tgconstraint;
    bool		tgdeferrable;
    bool		tginitdeferred;
    int16		tgnargs;
    int16		tgnattr;
    int16	   *tgattr;
    char	  **tgargs;
    char	   *tgqual;
    char	   *tgoldtable;
    char	   *tgnewtable;
} Trigger;

在内存中的 relcache(表缓存)中也同样保存有 Trigger 的信息:

  • RelationData,存放 relcache 的数据
  • TriggerDesc *trigdesc 字段,该表上的触发器信息
  • Trigger *triggers 字段,表上所有触发器组成的数组

Event Trigger

Event Trigger 存储在 pg_event_trigger 系统表中,关键字段如下,包含触发器名、调用的函数等信息。与 Trigger 不同的是,这里并不包含触发器所在的表,因为 Event Trigger 不属于任何一个表。

字段

描述

evtname

触发器名(必须唯一)

evtevent

触发事件的标识符

evtowner

事件触发器的拥有者

evtfoid

触发器调用的函数

触发过程

触发器会在特定事件场景下被触发,它识别这些事件的方式也很简单,就是在对应事件的代码处调用触发器函数。

Trigger

对于普通的触发器,触发时机是 INSERT、UPDATE、DELETE 等操作之前或者之后,所以在 PG 的执行器阶段触发,多数在 ProcessQuery-->ExecutorRun-->ExecModifyTable 函数中

  • 对于 语句级触发器,就在 ExecModifyTable 中调用  fireASTriggers  触发(用 fire 一词来表示触发,使用了 Trigger 的另一层含义:扳机,而 fire 表示扣动扳机的动作,生动形象)
  • 对于 行级触发器,从 ExecModifyTable 继续向下调用一层,到  ExecInsert、ExecUpdate、ExecDelete 函数对每一行进行操作时触发

我们将执行触发操作的函数称为“触发器的执行函数”,各类触发器的执行函数命名格式比较统一,在此列举几种:

  • ExecBRInsertTriggers,BR 表示 Before Row,Insert 表示插入时触发
  • ExecASUpdateTriggers,AS 表示 After Statement,Update 表示更新时触发
  • ExecIRDeleteTriggers,IR 表示 Instead Of Row,Delete 表示删除时触发

以 ExecBRInsertTriggers 为例说明触发过程:

  • 从 ResultRelInfo 结构体获取 TriggerDesc 信息,ResultRelInfo 是执行器阶段的表结构相关信息,TriggerDesc 是触发器信息
  • 遍历 TriggerDesc 中的 Trigger *triggers 数组, 检查该表上的每一个 Trigger
  • 调用 TRIGGER_TYPE_MATCHES 检查触发器类型是否匹配,对于 ExecBRInsertTriggers 代表的触发器,必须是行级、BEFORE、INSERT,不匹配则跳过
  • 调用 TriggerEnabled 检查触发器是否启用,本质是检查 Trigger 结构体的 tgenabled 字段,未启用则跳过
  • 填入 TriggerData 结构体的各个字段内容
  • 若检查通过, 调用 ExecCallTriggerFunc 执行触发器的函数

Event Trigger

事件触发器支持的事件仅有 ddl_command_startddl_command_endtable_rewrite 和 sql_drop 这四类,分别对应四个执行函数,其触发时机说明如下:

  • EventTriggerDDLCommandStartddl_command_start 事件的执行函数
  • 在 ProcessUtilitySlow 函数开头调用,ProcessUtilitySlow 函数用于处理 DDL 语句,所以该触发器 在 DDL 的开始处触发
  • EventTriggerDDLCommandEndddl_command_end 事件的执行函数
  • 在 ProcessUtilitySlow 结尾处调用, 即 DDL 结束时触发
  • EventTriggerSQLDropsql_drop 事件的执行函数
  • 也是在 ProcessUtilitySlow 结尾处调用
  • EventTriggerTableRewritetable_rewrite 事件的执行函数
  • 在 ATRewriteTables 中调用,在 执行 rewrite table 操作之前调用

以 EventTriggerDDLCommandStart 为例说明触发过程:

  • 检查是否为 postmaster,对于 standalone 模式,不允许触发
  • 调用  EventTriggerCommonSetup
  • 调用 EventCacheLookup, 从缓存中获取该事件的触发器函数列表
  • 填入 EventTriggerData 的各个字段内容
  • 调用 EventTriggerInvoke, 遍历触发器函数列表,逐个调用

调用功能函数

用户在创建触发器的 EXECUTE { FUNCTION | PROCEDURE } function_name 语句中指定了该触发器要执行的功能函数。在触发器被触发后,会执行该函数。

Trigger

在执行器阶段触发时,ResultRelInfo 结构体中存有表上的各项信息,其中就包括表上的触发器、函数等,所以直接从中就可以拿到触发器信息。关键结构体为 ResultRelInfo、TriggerDesc、Trigger,其嵌套关系如下:

  • ResultRelInfo,执行器中的表信息
  • TriggerDesc *ri_TrigDesc,表上的触发器信息
  • Trigger *triggers,触发器数组
  • Trigger,触发器名字、 函数 oid 等基本信息
  • bool trig_insert_before_row
    • bool trig_insert_after_row
    • ……

将 ResultRelInfo 中获取的 Trigger 结构体的全部内容都填充到 TriggerData 结构体,ExecCallTriggerFunc 函数再从 TriggerData 中获取函数 oid,并执行该函数

TriggerData 结构体定义如下,其中除了 Trigger 以外还保存了各种执行上下文信息,heap 表信息等,与函数的执行有关。

typedef struct TriggerData
{
	NodeTag		type;
	TriggerEvent tg_event;
	Relation	tg_relation;
	HeapTuple	tg_trigtuple;
	HeapTuple	tg_newtuple;
	Trigger    *tg_trigger;
	TupleTableSlot *tg_trigslot;
	TupleTableSlot *tg_newslot;
	Tuplestorestate *tg_oldtable;
	Tuplestorestate *tg_newtable;
	const Bitmapset *tg_updatedcols;
} TriggerData;

TriggerData 最终会保存到 PLpgSQL_execstate 中,这是 PLpgSQL 执行过程中的一个重要结构体:

typedef struct PLpgSQL_execstate
{
	PLpgSQL_function *func;		/* function being executed */

	TriggerData *trigdata;		/* if regular trigger, data about firing */
	EventTriggerData *evtrigdata;	/* if event trigger, data about firing */
	…………
} PLpgSQL_execstate;

触发器的功能函数执行的方法与普通的 PLpgSQL 函数、存储过程执行方法是类似的,关键调用路径是:

ExecCallTriggerFunc-->plpgsql_call_handler-->plpgsql_exec_trigger-->exec_toplevel_block-->exec_stmt_block-->…………

Event Trigger

对于事件触发器,在触发阶段的 EventTriggerCommonSetup 函数中,通过 EventCacheLookup 从缓存中查找触发器功能函数,然后在 EventTriggerInvoke 中根据触发器函数的 oid 进行调用。

EventTriggerCommonSetup 中还会填充 EventTriggerData 结构体,其中保存了调用过程中的一些关键信息:

typedef struct EventTriggerData
{
	NodeTag		type;
	const char *event;			/* event name */
	Node	   *parsetree;		/* parse tree */
	CommandTag	tag;
} EventTriggerData;

与普通触发器的 TriggerData 结构一样,EventTriggerData 结构体也会保存到 PLpgSQL_execstate 中,在 PLpgSQL 执行过程中使用:

typedef struct PLpgSQL_execstate
{
	PLpgSQL_function *func;		/* function being executed */

	TriggerData *trigdata;		/* if regular trigger, data about firing */
	EventTriggerData *evtrigdata;	/* if event trigger, data about firing */
	…………
} PLpgSQL_execstate;

事件触发器的功能函数实际执行步骤与普通触发器也基本相同,关键调用路径为:

ExecCallTriggerFunc-->plpgsql_call_handler-->plpgsql_exec_event_trigger-->exec_toplevel_block-->exec_stmt_block-->…………

修改触发器

使用 ALTER 语句修改触发器的定义

Trigger

根据 PG 14 官方文档,ALTER TRIGGER 的语法如下:

ALTER TRIGGER name ON table_name RENAME TO new_name
ALTER TRIGGER name ON table_name DEPENDS ON EXTENSION extension_name

仅支持重命名和修改依赖的插件。

重命名触发器的关键调用流程为:standard_ProcessUtility-->ExecRenameStmt-->renametrig,基本原理也是读取 pg_trigger 系统表的信息,修改以后写回系统表。

修改触发器依赖插件的关键调用流程为:standard_ProcessUtility-->ExecAlterObjectDependsStmt,会修改 pg_depend 系统表。

Event Trigger

根据 PG 14 官方文档,ALTER EVENT TRIGGER 语法为:

ALTER EVENT TRIGGER name DISABLE
ALTER EVENT TRIGGER name ENABLE [ REPLICA | ALWAYS ]
ALTER EVENT TRIGGER name OWNER TO { new_owner | CURRENT_USER | SESSION_USER }
ALTER EVENT TRIGGER name RENAME TO new_name

支持对事件触发器进行重命名、禁用、启用、修改 owner 的操作。

ALTER TRIGGER 的关键函数是 AlterEventTrigger,其内容较为简单:

  • table_open 打开 pg_event_trigger 系统表,加 RowExclusiveLock 锁
  • 检查事件触发器是否存在,不存在则报错
  • 检查当前用户是否为事件触发器的 owner,检查不通过则报 ACL 错误
  • 检查通过,更新事件触发器的信息,并写入到 pg_event_trigger 系统表中

删除触发器

使用 DROP 语句删除触发器

Trigger

PG 14 文档中 DROP TRIGGER 语法如下:

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]

删除触发器的关键函数是 RemoveTriggerById,调用流程如下:

ProcessUtilitySlow-->ExecDropStmt-->RemoveObjects-->performMultipleDeletions-->deleteObjectsInList-->deleteOneObject-->doDeletion-->RemoveTriggerById

RemoveTriggerById 函数流程:

  • 调用 table_open 打开 pg_trigger 系统表,根据 oid 在其中查找触发器
  • 调用 table_open 打开触发器所有的表,并检查表类型是否合法,必须是表、视图或者外表,不能为系统表
  • 调用 CatalogTupleDelete 删除 pg_trigger 中的对应元组

Event Trigger

PG 14 文档中 DROP EVENT TRIGGER 语法如下:

DROP EVENT TRIGGER [ IF EXISTS ] name [ CASCADE | RESTRICT ]

删除事件触发器的关键函数是 DropObjectById,这是一个公用的函数,可以删除多种类型的对象。

调用流程如下:

ProcessUtilitySlow-->ExecDropStmt-->RemoveObjects-->performMultipleDeletions-->deleteObjectsInList-->deleteOneObject-->doDeletion-->DropObjectById

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
8月前
|
SQL 关系型数据库 分布式数据库
数据库内核那些事|细说PolarDB优化器查询变换:IN-List变换
本篇文章将对PolarDB的IN-List变换进行深入阐述,从而让我们对PolarDB的查询改写能力有更感性的认知。
|
8月前
|
关系型数据库 MySQL 分布式数据库
|
6月前
|
SQL 关系型数据库 分布式数据库
数据库内核那些事|细说PolarDB优化器查询变换:IN-List变换
数据库内核那些事|细说PolarDB优化器查询变换:IN-List变换
106 0
|
3月前
|
SQL 关系型数据库 分布式数据库
|
6月前
|
缓存 关系型数据库 Serverless
数据库内核那些事,PolarDB HTAP Serverless,打造经济易用的实时分析系统
下本从IMCI Serverless核心优势角度的介绍各优化工作内容。
数据库内核那些事,PolarDB HTAP Serverless,打造经济易用的实时分析系统
|
8月前
|
存储 关系型数据库 数据库
数据库内核那些事|PolarDB X-Engine:如何构建1/10成本的事务存储引擎?
X-Engine引擎是PolarDB为用户提供的低成本,高性价比的解决方案,LSM-tree分层存储结合标准zstd压缩,在性能和成本做到了很好的平衡。在标准sysbench场景下,存储空间相比InnoDB引擎减少60%,读写性能降低10-20%。
数据库内核那些事|PolarDB X-Engine:如何构建1/10成本的事务存储引擎?
|
9月前
|
JSON 关系型数据库 分布式数据库
|
9月前
|
存储 关系型数据库 PostgreSQL
Postgresql内核源码分析-heapam分析
Postgresql内核源码分析-heapam分析
120 1
|
11月前
|
SQL 算法 Cloud Native
数据库内核那些事|细说PolarDB优化器查询变换 - join消除篇
数据库的查询优化器是整个系统的"大脑",一条SQL语句执行是否高效在不同的优化决策下可能会产生几个数量级的性能差异,因此优化器也是数据库系统中最为核心的组件和竞争力之一。阿里云瑶池旗下的云原生数据库PolarDB MySQL版作为领先的云原生数据库,希望能够应对广泛用户场景、承接各类用户负载,助力企业数据业务持续在线、数据价值不断放大,因此对优化器能力的打磨是必须要做的工作之一。 本系列将从PolarDB for MySQL的查询变换能力开始,介绍我们在这个优化器方向上逐步积累的一些工作。
11357 0
|
11月前
|
SQL 关系型数据库 MySQL
深度解析PolarDB DDL锁的优化和演进
DDL是数据库所有SQL操作中最繁重的一种,本文总结介绍了云原生数据库PolarDB中DDL全链路MDL锁治理的经验和进展,持续优化用户的使用体验,为用户打造最佳的云原生数据库。