假设我们在 HANA 中有一个表 BASE:
CREATE COLUMN TABLE BASE
("CLIENT" NVARCHAR(3) DEFAULT '000' NOT NULL ,
"KEY" DECIMAL(21,7) CS_FIXED DEFAULT 0 NOT NULL ,
"VALUE_FIELD" NVARCHAR(100) DEFAULT '' NOT NULL,
CONSTRAINT "BASE~0" PRIMARY KEY ("CLIENT", "KEY"));
然后我们创建一个日志表来捕获 BASE 表中更改记录的键:
CREATE COLUMN TABLE LOG_TABLE
("CLIENT" NVARCHAR(3) DEFAULT '000' NOT NULL ,
"KEY" DECIMAL(21,7) CS_FIXED DEFAULT 0 NOT NULL ,
"LOG_TIMESTAMP" DECIMAL(21,7) CS_FIXED DEFAULT 0 NOT NULL ,
"DB_OPERATION" NVARCHAR(1) DEFAULT '' NOT NULL,
CONSTRAINT "LOG_TABLE~0" PRIMARY KEY ("CLIENT", "KEY", "LOG_TIMESTAMP"));
这里我们不关心值字段,只关心键。我有一个触发代码生成器,具体取决于记录特定客户端或所有客户端中的更改的必要性。现在,我想出了这个解决方案:
CREATE OR REPLACE TRIGGER "trg_BASE_D"
AFTER DELETE ON "BASE"
REFERENCING OLD ROW AS R
FOR EACH ROW
BEGIN
INSERT INTO "LOG_TABLE" (CLIENT, KEY, LOG_TIMESTAMP, DB_OPERATION)
SELECT :R.CLIENT, :R.KEY, TO_NUMBER(TO_CHAR(CURRENT_UTCTIMESTAMP, 'YYYYMMDDHH24MISS.FF7')), 'D'
FROM DUMMY
WHERE :R.CLIENT IN ('010', '020');
END;
当然,为插入和更新创建了类似的触发器。 问题:这种从
dummy
中选择的解决方案比更明确的 IF
解决方案有什么优势吗?也就是说,使用 dummy
和使用 IF
时对性能有影响吗?
比较:
CREATE OR REPLACE TRIGGER "trg_BASE_D_IF"
AFTER DELETE ON "BASE"
REFERENCING OLD ROW AS R
FOR EACH ROW
BEGIN
IF :R.CLIENT = '010' OR :R.CLIENT = '020' THEN
INSERT INTO "LOG_TABLE" (CLIENT, KEY, LOG_TIMESTAMP, DB_OPERATION)
VALUES (:R.CLIENT, :R.KEY, TO_NUMBER(TO_CHAR(CURRENT_UTCTIMESTAMP, 'YYYYMMDDHH24MISS.FF7')), 'D');
END IF;
END;
IF
自动导致 SQL 脚本连续,但同时,它直接使用值,而不使用 dummy
。此外,这里没有什么可以并行的,因为触发器是基于 ROW 的; WHERE
解决方案不使用IF
,而是从dummy
中进行选择。它将如何影响触发器性能?或者根本没有区别,在这种情况下取决于个人喜好?我更喜欢基于 WHERE
的解决方案,因为它更容易以编程方式生成;然而,两者都很容易实现,所以我对其中任何一个都持开放态度。
抱歉,我无法访问实际的 HANA 数据库来运行性能测试 - 我只在 ABAP 中生成触发代码...
如果我不得不猜测,我会假设过程 IF 变体更好,因为它不需要准备和执行子查询 - 但差异可能很小,并且可能小于其他潜在影响。
我更担心的是批量插入到包含许多行的表中。为每行循环和执行单个插入可能会显着减慢速度。我猜想使用
FOR EACH STATEMENT
变体与 NEW TABLE
可能会更好,因为日志表中的插入可以批量完成:
CREATE OR REPLACE TRIGGER "trg_BASE_D"
AFTER DELETE ON "BASE"
REFERENCING OLD TABLE AS R
FOR EACH STATEMENT
BEGIN
INSERT INTO "LOG_TABLE" (CLIENT, KEY, LOG_TIMESTAMP, DB_OPERATION)
SELECT CLIENT, KEY, TO_NUMBER(TO_CHAR(CURRENT_UTCTIMESTAMP, 'YYYYMMDDHH24MISS.FF7')), 'D'
FROM :R
WHERE CLIENT IN ('010', '020');
END;