UPDATE多表關聯更新時為什麼會慢
阿新 • • 發佈:2018-12-30
構建環境如下:
Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 Connected as [email protected]:1521/orcl SQL> CREATE TABLE test1 AS SELECT * FROM Dba_Objects; Table created SQL> CREATE TABLE test2 AS SELECT * FROM Dba_Objects; Table created SQL> CREATE TABLE test3 AS SELECT * FROM Dba_Objects; Table created SQL> ALTER TABLE test2 ADD CONSTRAINTS pk_test2 PRIMARY KEY (object_id); Table altered SQL> ALTER TABLE test3 ADD CONSTRAINTS pk_test3 PRIMARY KEY (object_id); Table altered
我們先來看一個查詢的plan
注意ID=1、2、3、4這幾行PLAN。對應的分別就是SQL> explain plan FOR SELECT a.object_name, 2 (SELECT b.object_name FROM test2 b WHERE b.object_id = a.object_id) AS new_name, 3 a.object_type, 4 (SELECT c.object_name FROM test3 c WHERE c.object_id = a.object_id) AS new_type 5 FROM test1 a 6 WHERE EXISTS (SELECT NULL FROM test2 b WHERE b.object_id = a.object_id) 7 AND EXISTS 8 (SELECT NULL FROM test3 c WHERE c.object_id = a.object_id); Explained SQL> select * from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 2412657849 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 56357 | 6384K| 326 (12)| 00 | 1 | TABLE ACCESS BY INDEX ROWID| TEST2 | 1 | 79 | 2 (0)| 00 |* 2 | INDEX UNIQUE SCAN | PK_TEST2 | 1 | | 1 (0)| 00 | 3 | TABLE ACCESS BY INDEX ROWID| TEST3 | 1 | 79 | 2 (0)| 00 |* 4 | INDEX UNIQUE SCAN | PK_TEST3 | 1 | | 1 (0)| 00 | 5 | NESTED LOOPS SEMI | | 56357 | 6384K| 326 (12)| 00 | 6 | NESTED LOOPS SEMI | | 59647 | 5999K| 312 (8)| 00 | 7 | TABLE ACCESS FULL | TEST1 | 80164 | 7045K| 293 (2)| 00 |* 8 | INDEX UNIQUE SCAN | PK_TEST3 | 44380 | 563K| 0 (0)| 00 |* 9 | INDEX UNIQUE SCAN | PK_TEST2 | 71566 | 908K| 0 (0)| 00 -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- 2 - access("B"."OBJECT_ID"=:B1) 4 - access("C"."OBJECT_ID"=:B1) 8 - access("C"."OBJECT_ID"="A"."OBJECT_ID") 9 - access("B"."OBJECT_ID"="A"."OBJECT_ID") Note ----- - dynamic sampling used for this statement (level=2) 28 rows selected
(SELECT b.object_name FROM test2 b WHERE b.object_id = a.object_id) AS new_name,
(SELECT c.object_name FROM test3 c WHERE c.object_id = a.object_id) AS new_type
兩個語句
下面是一個UPDATE的PLAN
注意這兒的ID=7、8、9、10SQL> explain plan for UPDATE test1 a 2 SET a.object_name = 3 (SELECT b.object_name FROM test2 b WHERE b.object_id = a.object_id), 4 a.object_type = 5 (SELECT c.object_type FROM test3 c WHERE c.object_id = a.object_id) 6 WHERE EXISTS (SELECT NULL FROM test2 b WHERE b.object_id = a.object_id) 7 AND EXISTS 8 (SELECT NULL FROM test3 c WHERE c.object_id = a.object_id); Explained SQL> select * from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 2604142680 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| T -------------------------------------------------------------------------------- | 0 | UPDATE STATEMENT | | 56357 | 6384K| 338K (34)| 0 | 1 | UPDATE | TEST1 | | | | | 2 | NESTED LOOPS SEMI | | 56357 | 6384K| 326 (12)| 0 | 3 | NESTED LOOPS SEMI | | 59647 | 5999K| 312 (8)| 0 | 4 | TABLE ACCESS FULL | TEST1 | 80164 | 7045K| 293 (2)| 0 |* 5 | INDEX UNIQUE SCAN | PK_TEST3 | 44380 | 563K| 0 (0)| 0 |* 6 | INDEX UNIQUE SCAN | PK_TEST2 | 71566 | 908K| 0 (0)| 0 | 7 | TABLE ACCESS BY INDEX ROWID| TEST2 | 1 | 79 | 2 (0)| 0 |* 8 | INDEX UNIQUE SCAN | PK_TEST2 | 1 | | 1 (0)| 0 | 9 | TABLE ACCESS BY INDEX ROWID| TEST3 | 1 | 24 | 2 (0)| 0 |* 10 | INDEX UNIQUE SCAN | PK_TEST3 | 1 | | 1 (0)| 0 -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- 5 - access("C"."OBJECT_ID"="A"."OBJECT_ID") 6 - access("B"."OBJECT_ID"="A"."OBJECT_ID") 8 - access("B"."OBJECT_ID"=:B1) 10 - access("C"."OBJECT_ID"=:B1) Note ----- - dynamic sampling used for this statement (level=2) 29 rows selected
對應的分別就是
a.object_name = (SELECT b.object_name FROM test2 b WHERE b.object_id = a.object_id),
a.object_type = (SELECT c.object_type FROM test3 c WHERE c.object_id = a.object_id)
大家仔細對比這兩個語句,看下UPDATE的多表關聯更新是不是與標量子查詢很象。
那麼標題量子查詢慢的時候,對應的UPDATE慢也就不稀奇了。