字符 "A" 是 Oracle 数据库中的保留关键字吗?
Is the character "A" a reserved keyword in Oracle Database?
场景:
在 Oracle 数据库中,SQL 慢得多:
SELECT *
FROM TBL_MAIN A, TBL_CHILD_1 B, TBL_CHILD_2 C, TBL_CHILD_3 D, TBL_CHILD_4 E
WHERE A.ID_MAIN = B.ID_MAIN
AND A.ID_MAIN = C.ID_MAIN
AND A.ID_MAIN = D.ID_MAIN
AND A.ID_MAIN = E.ID_MAIN;
比那个:
SELECT *
FROM TBL_MAIN X, TBL_CHILD_1 B, TBL_CHILD_2 C, TBL_CHILD_3 D, TBL_CHILD_4 E
WHERE X.ID_MAIN = B.ID_MAIN
AND X.ID_MAIN = C.ID_MAIN
AND X.ID_MAIN = D.ID_MAIN
AND X.ID_MAIN = E.ID_MAIN;
换句话说,当我有 3 个或更多 table 加入时,如果我使用 "A" 作为 "TBL_MAIN" table 的别名,它会导致速度变慢询问。
当我在 table "TBL_MAIN" AS "A".
的内部连接中添加更多 table 时,情况变得最糟
发生了什么事?
简答不。 A 不是保留字。如果它是保留字,则会引发错误。但是,要分析您的性能问题,您需要 post 查询执行的指标。
我发现X
其实比A
快,但是Z
更慢:
Alias A 60.257 seconds
Alias X 57.747 seconds
Alias Y 58.383 seconds
Alias Z 62.157 seconds
老实说,这些差异不足以证明别名之间的差异。
我用 5 个大表(tbl_main 2200 万,tbl_child1700 万等)对其进行了测试。我将 SELECT *
更改为 SELECT COUNT(*)
以确保处理所有行。忽略第一次执行以预热缓存。接下来的三个运行是平均的。
DECLARE
FUNCTION test1(c VARCHAR2) RETURN NUMBER IS
time1 NUMBER; time2 NUMBER; stmt VARCHAR2(3000); n NUMBER;
BEGIN
stmt := q'!
SELECT count(*)
FROM tbl_main #, tbl_child1 B, tbl_child2 C, tbl_child3 D, tbl_child4 E
WHERE #.geb_id = B.geb_id
AND #.geb_id = C.geb_id
AND #.geb_id = D.geb_id
AND #.geb_id = E.geb_id
!';
stmt := REPLACE(stmt, '#', c);
--dbms_output.put_line(stmt);
time1 := dbms_utility.get_time();
EXECUTE IMMEDIATE stmt INTO n;
time2 := dbms_utility.get_time();
return (time2-time1)/100;
END test1;
PROCEDURE test3(c VARCHAR2) IS
ignore NUMBER; seconds NUMBER;
BEGIN
ignore := test1(c);
seconds := (test1(c)+test1(c)+test1(c)) / 3;
DBMS_OUTPUT.PUT_LINE('Alias '||c||' '||round(seconds,3)||' seconds');
END test3;
BEGIN
test3('A');
test3('X');
test3('Y');
test3('Z');
END;
/
是的。它在 12c.
SELECT KEYWORD
FROM V$RESERVED_WORDS
WHERE KEYWORD = 'A'
;
是的。它是一元集合运算符 "IS A SET" 的一部分。在Oracle中有点复杂,为了保证向后兼容Oracle有"reserved words"和"keywords"。其中之一不能用作标识符,而其他可能在某些上下文中具有特殊含义 - 但仍然可以用作标识符。
例如,您仍然可以像
一样使用SQL
select * from commit;
or
select * from join where X is a set;
commit、join、model 等词仍然可以用作标识符。
当然这不能影响SQL评价的速度。特别是当光标被重用时。它可能只会减慢解析速度。
问题自行解决!
现在两个 SQL 时间相同,只是像@wolφi 说的快了一点。
这种情况持续了两天,现在正常了。
我相信关闭后数据库就正常了。
关于此的一件有趣的事情是当问题发生时,SQL Tuning Advisor 为 SQL 提出了一个执行计划,他们使工作正常(快 99.9%)。遗憾的是,我当时没有保存推荐报告来显示这里。
但现在没有任何 SQL 配置文件处于活动状态,SQL 的配置文件处于同一时间。
场景: 在 Oracle 数据库中,SQL 慢得多:
SELECT *
FROM TBL_MAIN A, TBL_CHILD_1 B, TBL_CHILD_2 C, TBL_CHILD_3 D, TBL_CHILD_4 E
WHERE A.ID_MAIN = B.ID_MAIN
AND A.ID_MAIN = C.ID_MAIN
AND A.ID_MAIN = D.ID_MAIN
AND A.ID_MAIN = E.ID_MAIN;
比那个:
SELECT *
FROM TBL_MAIN X, TBL_CHILD_1 B, TBL_CHILD_2 C, TBL_CHILD_3 D, TBL_CHILD_4 E
WHERE X.ID_MAIN = B.ID_MAIN
AND X.ID_MAIN = C.ID_MAIN
AND X.ID_MAIN = D.ID_MAIN
AND X.ID_MAIN = E.ID_MAIN;
换句话说,当我有 3 个或更多 table 加入时,如果我使用 "A" 作为 "TBL_MAIN" table 的别名,它会导致速度变慢询问。
当我在 table "TBL_MAIN" AS "A".
的内部连接中添加更多 table 时,情况变得最糟发生了什么事?
简答不。 A 不是保留字。如果它是保留字,则会引发错误。但是,要分析您的性能问题,您需要 post 查询执行的指标。
我发现X
其实比A
快,但是Z
更慢:
Alias A 60.257 seconds
Alias X 57.747 seconds
Alias Y 58.383 seconds
Alias Z 62.157 seconds
老实说,这些差异不足以证明别名之间的差异。
我用 5 个大表(tbl_main 2200 万,tbl_child1700 万等)对其进行了测试。我将 SELECT *
更改为 SELECT COUNT(*)
以确保处理所有行。忽略第一次执行以预热缓存。接下来的三个运行是平均的。
DECLARE
FUNCTION test1(c VARCHAR2) RETURN NUMBER IS
time1 NUMBER; time2 NUMBER; stmt VARCHAR2(3000); n NUMBER;
BEGIN
stmt := q'!
SELECT count(*)
FROM tbl_main #, tbl_child1 B, tbl_child2 C, tbl_child3 D, tbl_child4 E
WHERE #.geb_id = B.geb_id
AND #.geb_id = C.geb_id
AND #.geb_id = D.geb_id
AND #.geb_id = E.geb_id
!';
stmt := REPLACE(stmt, '#', c);
--dbms_output.put_line(stmt);
time1 := dbms_utility.get_time();
EXECUTE IMMEDIATE stmt INTO n;
time2 := dbms_utility.get_time();
return (time2-time1)/100;
END test1;
PROCEDURE test3(c VARCHAR2) IS
ignore NUMBER; seconds NUMBER;
BEGIN
ignore := test1(c);
seconds := (test1(c)+test1(c)+test1(c)) / 3;
DBMS_OUTPUT.PUT_LINE('Alias '||c||' '||round(seconds,3)||' seconds');
END test3;
BEGIN
test3('A');
test3('X');
test3('Y');
test3('Z');
END;
/
是的。它在 12c.
SELECT KEYWORD
FROM V$RESERVED_WORDS
WHERE KEYWORD = 'A'
;
是的。它是一元集合运算符 "IS A SET" 的一部分。在Oracle中有点复杂,为了保证向后兼容Oracle有"reserved words"和"keywords"。其中之一不能用作标识符,而其他可能在某些上下文中具有特殊含义 - 但仍然可以用作标识符。
例如,您仍然可以像
一样使用SQLselect * from commit;
or
select * from join where X is a set;
commit、join、model 等词仍然可以用作标识符。
当然这不能影响SQL评价的速度。特别是当光标被重用时。它可能只会减慢解析速度。
问题自行解决! 现在两个 SQL 时间相同,只是像@wolφi 说的快了一点。
这种情况持续了两天,现在正常了。
我相信关闭后数据库就正常了。
关于此的一件有趣的事情是当问题发生时,SQL Tuning Advisor 为 SQL 提出了一个执行计划,他们使工作正常(快 99.9%)。遗憾的是,我当时没有保存推荐报告来显示这里。
但现在没有任何 SQL 配置文件处于活动状态,SQL 的配置文件处于同一时间。