MySQL和Oracle中的半連線測試總結(一)
SQL中的半連線在MySQL和Oracle還是存在一些差距,從測試的情況來看,Oracle的處理要更加全面。
首先我們來看看在MySQL中怎麼測試,對於MySQL方面的測試也參考了不少海翔兄的部落格文章,自己也完整的按照他的測試思路練習了一遍。
首先建立下面的表:
create table users(
userid int(11) unsigned not null,
user_name varchar(64) default null,
primary key(userid)
)engine=innodb default charset=UTF8;
如果要插入資料,可以使用儲存過程的方式。比如先插入20000條定製資料。
delimiter $$
drop procedure if exists proc_auto_insertdata$$
create procedure proc_auto_insertdata()
begin
declare
init_data integer default 1;
while init_data<=20000 do
insert into users values(init_data,concat('user' ,init_data));
set init_data=init_data+1;
end while;
end$$
delimiter ;
call proc_auto_insertdata();
初始化的過程會很快,最後一步即插入資料花費了近6秒的時間。
[test]>source insert_proc.sql
Query OK, 0 rows affected (0.12 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected (5.63 sec)
然後我們使用如下的半連線查詢資料,實際上執行了6秒左右。
select u.userid,u.user_name from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
1999 rows in set (6.36 sec)
為了簡化測試條件和查詢結果,我們使用count的方式來完成對比測試。
[test]>select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (6.38 sec)
然後使用如下的方式來檢視,當然看起來這種結構似乎有些多餘,因為userid<-1的資料是不存在的。
select count(u.userid) from users u
where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (0.06 sec)
但是效果卻好很多。
當然兩種方式的執行計劃差別很大。
第一種效率較差的執行計劃如下:
[test]>explain select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
+----+--------------+-------------+-------+---------------+---------+---------+------+-------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+-------------+-------+---------------+---------+---------+------+-------+----------------------------------------------------+
| 1 | SIMPLE | | ALL | NULL | NULL | NULL | NULL | NULL | NULL |
| 1 | SIMPLE | u | ALL | NULL | NULL | NULL | NULL | 19762 | Using where; Using join buffer (Block Nested Loop) |
| 2 | MATERIALIZED | t | range | PRIMARY | PRIMARY | 4 | NULL | 1998 | Using where |
+----+--------------+-------------+-------+---------------+---------+---------+------+-------+----------------------------------------------------+
3 rows in set (0.02 sec)
第二個執行效率較高的執行計劃如下:
[test]>explain select count(u.userid) from users u where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------+
| 1 | PRIMARY | u | ALL | NULL | NULL | NULL | NULL | 19762 | Using where |
| 3 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables |
| 2 | SUBQUERY | t | range | PRIMARY | PRIMARY | 4 | NULL | 1998 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------+
3 rows in set (0.00 sec)
我們在這個測試中先不解釋更多的原理,只是對比說明。
如果想得到更多的執行效率對比情況,可以使用show status 的方式。
首先flush status
[test]>flush status;
Query OK, 0 rows affected (0.02 sec)
然後執行語句如下:
[test]>select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (6.22 sec)
檢視狀態資訊,關鍵詞是Handler_read.
[test]>show status like 'Handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 2 |
| Handler_read_key | 2 |
| Handler_read_last | 0 |
| Handler_read_next | 1999 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 22001 |
+-----------------------+-------+
7 rows in set (0.04 sec
Handler_read_key這個引數的解釋是根據鍵讀一行的請求數。如果較高,說明查詢和表的索引正確。
Handler_read_next這個引數的解釋是按照鍵順序讀下一行的請求數。如果用範圍約束或如果執行索引掃描來查詢索引列,該值增加。
Handler_read_rnd_next這個引數的解釋是在資料檔案中讀下一行的請求數。如果正進行大量的表掃描,該值較高。通常說明表索引不正確或寫入的查詢沒有利用索引。
這是一個count的操作,所以Handler_read_rnd_next的指標較高,這是一個範圍查詢,所以Handler_read_next 的值也是一個範圍值。
然後執行另外一個子查詢,可以看到show status的結果如下:
[test]>show status like 'Handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 2 |
| Handler_read_key | 20002 |
| Handler_read_last | 0 |
| Handler_read_next | 1999 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 20001 |
+-----------------------+-------+
7 rows in set (0.00 sec)
可以和明顯看到Handler_read_key這個值很高,根據引數的解釋,說明查詢和表的索引使用正確。也就意味著這種方式想必於第一種方案要好很多。
而對於此,MySQL其實也有一些方式方法可以得到更細節的資訊。
一種就是explain extended的方式。
[test]>explain extended select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
。。。。
3 rows in set, 1 warning (0.00 sec)
然後show warnings就會看到詳細的資訊。
[test]>show warnings;
| Note | 1003 | /* select#1 */ select count(`test`.`u`.`userid`) AS `count(u.userid)` from `test`.`users` `u` semi join (`test`.`users` `t`) where ((`test`.`u`.`user_name` = ``.`user_name`) and (`test`.`t`.`userid` < 2000)) |
1 row in set (0.00 sec)
第二個語句的情況如下:
[test]>explain extended select count(u.userid) from users u where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
3 rows in set, 1 warning (0.00 sec)
[test]>show warnings;
| Note | 1003 | /* select#1 */ select count(`test`.`u`.`userid`) AS `count(u.userid)` from `test`.`users` `u` where ((`test`.`u`.`user_name`,`test`.`u`.`user_name` in ( (/* select#2 */ select `test`.`t`.`user_name` from `test`.`users` `t` where (`test`.`t`.`userid` < 2000) ), (`test`.`u`.`user_name` in on where ((`test`.`u`.`user_name` = `materialized-subquery`.`user_name`))))) or (`test`.`u`.`user_name`,`test`.`u`.`user_name` in ( (/* select#3 */ select `test`.`t`.`user_name` from `test`.`users` `t` where 0 ), (`test`.`u`.`user_name` in on where ((`test`.`u`.`user_name` = `materialized-subquery`.`user_name`)))))) |
1 row in set (0.00 sec)
還有一種方式就是使用 optimizer_trace,在5.6可用
set optimizer_trace="enabled=on";
執行語句後,然後透過下面的查詢得到trace資訊。
select *from information_schema.optimizer_trace\G
當然可以看出半連線的表現其實還不夠好,能不能選擇性的關閉呢,有一個引數可以控制,即是optimizer_switch,其實我們也可以看看這個引數的情況。
| optimizer_switch | index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,subquery_materialization_cost_based=on,use_index_extensions=on |
關閉半連線的設定
>set optimizer_switch="semijoin=off";
Query OK, 0 rows affected (0.00 sec)
再次執行原本執行時間近6秒的SQL,執行時間大大降低。
[test]> select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (0.05 sec)
執行第二個語句,情況如下:
[test]>select count(u.userid) from users u where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (0.07 sec)
參考內容如下:
http://blog.chinaunix.net/uid-16909016-id-214888.html
而在Oracle中表現如何呢。
建立測試表
create table users(
userid number not null,
user_name varchar2(64) default null,
primary key(userid)
);
初始化資料,其實一句SQL就可以搞定。遞迴查詢可以換種方式來用,效果槓槓的。
insert into users select level,'user'||level from dual connect by level<=20000;
收集一下統計資訊
exec dbms_stats.gather_table_stats(ownname=>'CYDBA',tabname=>'USERS',cascade=>true);
然後執行和MySQL中同樣的語句。
我們使用trace的方式來檢視,我們僅列出trace的情況。
SQL> set autot trace exp stat
SQL> select u.userid,u.user_name from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
1999 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 771105466
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2003 | 52078 | 21 (5)| 00:00:01 |
|* 1 | HASH JOIN RIGHT SEMI | | 2003 | 52078 | 21 (5)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| USERS | 1999 | 25987 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | SYS_C0042448 | 1999 | | 2 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | USERS | 20000 | 253K| 17 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("U"."USER_NAME"="T"."USER_NAME")
3 - access("T"."USERID"<2000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
205 consistent gets
0 physical reads
0 redo size
52196 bytes sent via SQL*Net to client
1983 bytes received via SQL*Net from client
135 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1999 rows processed
SQL> select u.userid,u.user_name from users u where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
1999 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1012235795
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2004 | 94188 | 22 (5)| 00:00:01 |
|* 1 | HASH JOIN | | 2004 | 94188 | 22 (5)| 00:00:01 |
| 2 | VIEW | VW_NSO_1 | 2000 | 68000 | 4 (0)| 00:00:01 |
| 3 | HASH UNIQUE | | 2000 | 26000 | 4 (25)| 00:00:01 |
| 4 | UNION-ALL | | | | | |
| 5 | TABLE ACCESS BY INDEX ROWID| USERS | 1 | 13 | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | SYS_C0042448 | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| USERS | 1999 | 25987 | 3 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | SYS_C0042448 | 1999 | | 2 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | USERS | 20000 | 253K| 17 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("U"."USER_NAME"="USER_NAME")
6 - access("USERID"<(-1))
8 - access("T"."USERID"<2000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
207 consistent gets
0 physical reads
0 redo size
52196 bytes sent via SQL*Net to client
1983 bytes received via SQL*Net from client
135 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1999 rows processed
從Oracle的表現來看,支援的力度要全面很多。當然半連線的玩法還有很多,比如exists,這些限於篇幅暫沒有展開。而且對於對比測試中的更多知識點分析,我們後期也會逐步補充。
首先我們來看看在MySQL中怎麼測試,對於MySQL方面的測試也參考了不少海翔兄的部落格文章,自己也完整的按照他的測試思路練習了一遍。
首先建立下面的表:
create table users(
userid int(11) unsigned not null,
user_name varchar(64) default null,
primary key(userid)
)engine=innodb default charset=UTF8;
如果要插入資料,可以使用儲存過程的方式。比如先插入20000條定製資料。
delimiter $$
drop procedure if exists proc_auto_insertdata$$
create procedure proc_auto_insertdata()
begin
declare
init_data integer default 1;
while init_data<=20000 do
insert into users values(init_data,concat('user' ,init_data));
set init_data=init_data+1;
end while;
end$$
delimiter ;
call proc_auto_insertdata();
初始化的過程會很快,最後一步即插入資料花費了近6秒的時間。
[test]>source insert_proc.sql
Query OK, 0 rows affected (0.12 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected (5.63 sec)
然後我們使用如下的半連線查詢資料,實際上執行了6秒左右。
select u.userid,u.user_name from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
1999 rows in set (6.36 sec)
為了簡化測試條件和查詢結果,我們使用count的方式來完成對比測試。
[test]>select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (6.38 sec)
然後使用如下的方式來檢視,當然看起來這種結構似乎有些多餘,因為userid<-1的資料是不存在的。
select count(u.userid) from users u
where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (0.06 sec)
但是效果卻好很多。
當然兩種方式的執行計劃差別很大。
第一種效率較差的執行計劃如下:
[test]>explain select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
+----+--------------+-------------+-------+---------------+---------+---------+------+-------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+-------------+-------+---------------+---------+---------+------+-------+----------------------------------------------------+
| 1 | SIMPLE | | ALL | NULL | NULL | NULL | NULL | NULL | NULL |
| 1 | SIMPLE | u | ALL | NULL | NULL | NULL | NULL | 19762 | Using where; Using join buffer (Block Nested Loop) |
| 2 | MATERIALIZED | t | range | PRIMARY | PRIMARY | 4 | NULL | 1998 | Using where |
+----+--------------+-------------+-------+---------------+---------+---------+------+-------+----------------------------------------------------+
3 rows in set (0.02 sec)
第二個執行效率較高的執行計劃如下:
[test]>explain select count(u.userid) from users u where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------+
| 1 | PRIMARY | u | ALL | NULL | NULL | NULL | NULL | 19762 | Using where |
| 3 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables |
| 2 | SUBQUERY | t | range | PRIMARY | PRIMARY | 4 | NULL | 1998 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------+
3 rows in set (0.00 sec)
我們在這個測試中先不解釋更多的原理,只是對比說明。
如果想得到更多的執行效率對比情況,可以使用show status 的方式。
首先flush status
[test]>flush status;
Query OK, 0 rows affected (0.02 sec)
然後執行語句如下:
[test]>select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (6.22 sec)
檢視狀態資訊,關鍵詞是Handler_read.
[test]>show status like 'Handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 2 |
| Handler_read_key | 2 |
| Handler_read_last | 0 |
| Handler_read_next | 1999 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 22001 |
+-----------------------+-------+
7 rows in set (0.04 sec
Handler_read_key這個引數的解釋是根據鍵讀一行的請求數。如果較高,說明查詢和表的索引正確。
Handler_read_next這個引數的解釋是按照鍵順序讀下一行的請求數。如果用範圍約束或如果執行索引掃描來查詢索引列,該值增加。
Handler_read_rnd_next這個引數的解釋是在資料檔案中讀下一行的請求數。如果正進行大量的表掃描,該值較高。通常說明表索引不正確或寫入的查詢沒有利用索引。
這是一個count的操作,所以Handler_read_rnd_next的指標較高,這是一個範圍查詢,所以Handler_read_next 的值也是一個範圍值。
然後執行另外一個子查詢,可以看到show status的結果如下:
[test]>show status like 'Handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 2 |
| Handler_read_key | 20002 |
| Handler_read_last | 0 |
| Handler_read_next | 1999 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 20001 |
+-----------------------+-------+
7 rows in set (0.00 sec)
可以和明顯看到Handler_read_key這個值很高,根據引數的解釋,說明查詢和表的索引使用正確。也就意味著這種方式想必於第一種方案要好很多。
而對於此,MySQL其實也有一些方式方法可以得到更細節的資訊。
一種就是explain extended的方式。
[test]>explain extended select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
。。。。
3 rows in set, 1 warning (0.00 sec)
然後show warnings就會看到詳細的資訊。
[test]>show warnings;
| Note | 1003 | /* select#1 */ select count(`test`.`u`.`userid`) AS `count(u.userid)` from `test`.`users` `u` semi join (`test`.`users` `t`) where ((`test`.`u`.`user_name` = ``.`user_name`) and (`test`.`t`.`userid` < 2000)) |
1 row in set (0.00 sec)
第二個語句的情況如下:
[test]>explain extended select count(u.userid) from users u where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
3 rows in set, 1 warning (0.00 sec)
[test]>show warnings;
| Note | 1003 | /* select#1 */ select count(`test`.`u`.`userid`) AS `count(u.userid)` from `test`.`users` `u` where ((`test`.`u`.`user_name`,`test`.`u`.`user_name` in ( (/* select#2 */ select `test`.`t`.`user_name` from `test`.`users` `t` where (`test`.`t`.`userid` < 2000) ), (`test`.`u`.`user_name` in on where ((`test`.`u`.`user_name` = `materialized-subquery`.`user_name`))))) or (`test`.`u`.`user_name`,`test`.`u`.`user_name` in ( (/* select#3 */ select `test`.`t`.`user_name` from `test`.`users` `t` where 0 ), (`test`.`u`.`user_name` in on where ((`test`.`u`.`user_name` = `materialized-subquery`.`user_name`)))))) |
1 row in set (0.00 sec)
還有一種方式就是使用 optimizer_trace,在5.6可用
set optimizer_trace="enabled=on";
執行語句後,然後透過下面的查詢得到trace資訊。
select *from information_schema.optimizer_trace\G
當然可以看出半連線的表現其實還不夠好,能不能選擇性的關閉呢,有一個引數可以控制,即是optimizer_switch,其實我們也可以看看這個引數的情況。
| optimizer_switch | index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,subquery_materialization_cost_based=on,use_index_extensions=on |
關閉半連線的設定
>set optimizer_switch="semijoin=off";
Query OK, 0 rows affected (0.00 sec)
再次執行原本執行時間近6秒的SQL,執行時間大大降低。
[test]> select count(u.userid) from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (0.05 sec)
執行第二個語句,情況如下:
[test]>select count(u.userid) from users u where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
+-----------------+
| count(u.userid) |
+-----------------+
| 1999 |
+-----------------+
1 row in set (0.07 sec)
參考內容如下:
http://blog.chinaunix.net/uid-16909016-id-214888.html
而在Oracle中表現如何呢。
建立測試表
create table users(
userid number not null,
user_name varchar2(64) default null,
primary key(userid)
);
初始化資料,其實一句SQL就可以搞定。遞迴查詢可以換種方式來用,效果槓槓的。
insert into users select level,'user'||level from dual connect by level<=20000;
收集一下統計資訊
exec dbms_stats.gather_table_stats(ownname=>'CYDBA',tabname=>'USERS',cascade=>true);
然後執行和MySQL中同樣的語句。
我們使用trace的方式來檢視,我們僅列出trace的情況。
SQL> set autot trace exp stat
SQL> select u.userid,u.user_name from users u where u.user_name in (select t.user_name from users t where t.userid<2000);
1999 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 771105466
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2003 | 52078 | 21 (5)| 00:00:01 |
|* 1 | HASH JOIN RIGHT SEMI | | 2003 | 52078 | 21 (5)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| USERS | 1999 | 25987 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | SYS_C0042448 | 1999 | | 2 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | USERS | 20000 | 253K| 17 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("U"."USER_NAME"="T"."USER_NAME")
3 - access("T"."USERID"<2000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
205 consistent gets
0 physical reads
0 redo size
52196 bytes sent via SQL*Net to client
1983 bytes received via SQL*Net from client
135 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1999 rows processed
SQL> select u.userid,u.user_name from users u where (u.user_name in (select t.user_name from users t where t.userid<2000) or u.user_name in (select t.user_name from users t where userid<-1) );
1999 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1012235795
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2004 | 94188 | 22 (5)| 00:00:01 |
|* 1 | HASH JOIN | | 2004 | 94188 | 22 (5)| 00:00:01 |
| 2 | VIEW | VW_NSO_1 | 2000 | 68000 | 4 (0)| 00:00:01 |
| 3 | HASH UNIQUE | | 2000 | 26000 | 4 (25)| 00:00:01 |
| 4 | UNION-ALL | | | | | |
| 5 | TABLE ACCESS BY INDEX ROWID| USERS | 1 | 13 | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | SYS_C0042448 | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| USERS | 1999 | 25987 | 3 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | SYS_C0042448 | 1999 | | 2 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | USERS | 20000 | 253K| 17 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("U"."USER_NAME"="USER_NAME")
6 - access("USERID"<(-1))
8 - access("T"."USERID"<2000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
207 consistent gets
0 physical reads
0 redo size
52196 bytes sent via SQL*Net to client
1983 bytes received via SQL*Net from client
135 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1999 rows processed
從Oracle的表現來看,支援的力度要全面很多。當然半連線的玩法還有很多,比如exists,這些限於篇幅暫沒有展開。而且對於對比測試中的更多知識點分析,我們後期也會逐步補充。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-2125507/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 關於oracle中的半連線Oracle
- 連線和半連線
- Oracle 連線條件中帶有OR的測試Oracle
- 測試 mysql 的最大連線數MySql
- mysql 外連線總結MySql
- ORACLE 半連線與反連線Oracle
- hive表連線和oracle測試對比HiveOracle
- myeclipse 中java連線mysql、查詢測試EclipseJavaMySql
- Oracle 左右連線總結Oracle
- [總結]無線測試
- 【總結】mysql半同步MySql
- MySQL反連線的優化總結MySql優化
- Oracle左右全連線總結Oracle
- 自然連線的一個測試
- 【JDBC】java連線池模擬測試 連線oracleJDBCJavaOracle
- java Jdbc連線oracle資料庫連線測試JavaJDBCOracle資料庫
- Oracle 內外連線 join 總結Oracle
- node+express框架中連線使用mysql經驗總結Express框架MySql
- 【NUMBER】有關Oracle NUMBER型別定義中precision和scale的測試和總結Oracle型別
- Oracle內連線、外連線、右外連線、全外連線小總結Oracle
- 【經典】連線oracle的總結(關於tnsname和監聽)Oracle
- Oracle 左外連線、右外連線、全外連線小總結Oracle
- 測試連線
- 外連線的一些總結
- php7連線mysql測試程式碼PHPMySql
- mysql 連線oracleMySqlOracle
- 【SQL】表連線 --半連線SQL
- oracle 與 mysql 中的函式總結OracleMySql函式
- 內連線、外連線總結
- 對於MySQL遠端連線中出現的一個問題總結MySql
- mysql的JDBC架包下載及簡單測試連線MySqlJDBC
- oracle中的連線Oracle
- Oracle的左連線和右連線Oracle
- [總結] 簡述 MySQL 基準測試工具MySql
- 【總結】簡述 MySQL 基準測試工具MySql
- 測試總結①
- JMeter MQTT 在連線測試場景中的使用JMeterMQQT
- 【MYSQL備庫恢復速度測試 半同步速度測試】MySql