返回顶部
首页 > 资讯 > 数据库 >MySQL和Oracle中的半连接测试总结(一)
  • 376
分享到

MySQL和Oracle中的半连接测试总结(一)

2024-04-02 19:04:59 376人浏览 薄情痞子
摘要

sql中的半连接在Mysql和oracle还是存在一些差距,从测试的情况来看,Oracle的处理要更加全面。 首先我们来看看在mysql中怎么测试,对于MySQL方面的测试也参考了不少海翔兄的博客文章,自己

sql中的半连接在Mysqloracle还是存在一些差距,从测试的情况来看,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 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 count(`test`.`u`.`userid`) AS `count(u.userid)` from `test`.`users` `u` where ((`test`.`u`.`user_name`,`test`.`u`.`user_name` in ( ( 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 `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://dbaplus.cn/news-11-133-1.html
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,这些限于篇幅暂没有展开。而且对于对比测试中的更多知识点分析,我们后期也会逐步补充。
您可能感兴趣的文档:

--结束END--

本文标题: MySQL和Oracle中的半连接测试总结(一)

本文链接: https://lsjlt.com/news/49209.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • MySQL和Oracle中的半连接测试总结(一)
    SQL中的半连接在MySQL和Oracle还是存在一些差距,从测试的情况来看,Oracle的处理要更加全面。 首先我们来看看在MySQL中怎么测试,对于MySQL方面的测试也参考了不少海翔兄的博客文章,自己...
    99+
    2024-04-02
  • 【MySQL】MySQL内连接和外连接详细总结
    目录 多表查询的分类3:内连接VS外连接(重难点)1. 内连接2.外连接3. SQL99语法实现多表查询3.1 SQL99实现内连接3.2 SQL99语法实现外连接3.2.1 左外连...
    99+
    2023-09-04
    mysql 数据库 java sql
  • 接口测试的知识点总结
    这篇文章主要介绍“接口测试的知识点总结”,在日常操作中,相信很多人在接口测试的知识点总结问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”接口测试的知识点总结”的疑惑有所帮助!接...
    99+
    2024-04-02
  • MySQL:测试与查询的连接?
    将任何预定义函数与选择查询一起使用,或者您可以使用选择查询打印一些单词,以测试与查询的连接。语法如下。SELECT yourValue;预定义函数的选择查询如下。语法如下。SELECT anyPredefinedFunctionName()...
    99+
    2023-10-22
  • PHP与MySQL连接的方法总结
    本篇文章给大家带来了关于PHP视频教程的相关知识,其中主要介绍了PHP与MySQL连接的相关内容,PHP与MySQL的连接有三种API接口,分别是:PHP的MySQL扩展 、PHP的mysqli扩展 、PHP数据对象(PDO),下面分别来看...
    99+
    2023-05-14
    php
  • MySQL远程无法连接的一些常见原因总结
    目录前言原因1:原因2:原因3:总结前言 mysql是目前非常流行的数据库之一,也是中小企业持久化存储的首选数据库。 不同于我们日常学习,在实际应用中,MySQL服务都会挂载在某台服务器上。如果MySQL部署在某台云服务...
    99+
    2024-04-02
  • Mysql中常用的几种join连接方式总结
    目录1.内连接2.左连接3.右连接4.查询左表独有数据5.查询右表独有数据6.全连接7.查询左右表各自的独有的数据总结1.首先准备两张表 部门表: 员工表: 以下我们就对这两张表...
    99+
    2024-04-02
  • mysql和oracle的连接数
    orcle的连接数: SQL> select count(*) from v$session #连接数 SQL> Select count(*) from v$session where status="AC...
    99+
    2015-07-14
    mysql和oracle的连接数
  • 如何测试 MySQL SSL 连接的可靠性
    如何测试 MySQL SSL 连接的可靠性概述:MySQL 是一个流行的关系型数据库管理系统,常用于存储和管理大量数据。为了保护敏感信息的安全性,MySQL 提供了 SSL 连接的功能,通过加密通信来传输数据。然而,如何确保 MySQL S...
    99+
    2023-10-22
    MySQL ssl 可靠性
  • MySQL 逻辑备份与恢复测试的相关总结
    目录一、什么样的备份是数据库逻辑备份呢?二、常用的逻辑备份①生成 INSERT 语句备份②生成特定格式的纯文本备份数据文件备份1.通过执行 SELECT ... TO OUTFILE FROM ......
    99+
    2022-05-29
    MySQL 逻辑备份 MySQL 恢复测试
  • 使用Idea连接MySQL的详细步骤总结
    一、创建普通java工程 创建工程跳过了,普通的java工程 二、导入mysql的jar包 mysql jar包下载地址 我使用的是5.1.15版本 创建目录,下载的jar包复制到目...
    99+
    2024-04-02
  • JDBC连接Mysql的5种方式实例总结
    目录测试环境说明第一种方式第二种方式第三种方式第四种方式第五种方式总结测试环境说明 mysql数据库:jdbc:mysql://localhost:3306/test IDE:IDE...
    99+
    2023-05-14
    jdbc连接MySQL代码 jdbc连接mysql的代码 jdbc连接mysql数据库
  • C#连接Oracle数据库的多种方法总结
    目录C# 连接oracle数据库常用的三种方法有三种:Oracle.ManagedDataAccess.Client.dll总结C# 连接oracle数据库常用的三种方法有三种: 一...
    99+
    2023-05-17
    c#连接oracle数据库 c连接oracle数据库 c#Oracle读取数据库
  • ODBC Oracle连接在数据备份容灾测试中的应用
    在数据备份容灾测试中,ODBC Oracle连接可以帮助实现数据库的备份和恢复操作。通过ODBC连接,用户可以将数据从Oracle数据库备份到另一个存储位置,以确保数据的安全性和完整性。此外,ODBC连接还可以帮助用户在灾难发生时快速恢复数...
    99+
    2024-07-16
    oracle
  • MySQL实现批量插入测试数据的方式总结
    目录前言表使用函数生成设置允许创建函数创建存储过程执行存储过程总结使用 Navicat自带的数据生成前言 在开发过程中我们不管是用来测试性能还是在生产环境中页面展示好看一点, 又或者...
    99+
    2023-05-20
    MySQL批量插入测试数据方式 MySQL批量插入数据 MySQL插入数据
  • 怎么在CentOS LAMP环境搭建和测试php与mysql的连接
    这篇文章主要介绍“怎么在CentOS LAMP环境搭建和测试php与mysql的连接”,在日常操作中,相信很多人在怎么在CentOS LAMP环境搭建和测试php与mysql的连接问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法...
    99+
    2023-06-16
  • node连接MySQL数据库的3种方式总结
    目录1.使用mysql包的提供的接口进行连接2.建立数据库连接池总结以下我们将说明node连接数据库的三种方式,并进行利弊说明,以挑选出最适合项目的连接方式。 1.使用mysql包的...
    99+
    2022-11-13
    node连接mysql nodejs mysql nodejs连接数据库
  • mysql连接数据库并测试的方式方法
    这篇文章主要介绍mysql连接数据库并测试的方式方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1.通过maven导入关于mybatis的jar包可以通过阿里云的maven库直接下...
    99+
    2024-04-02
  • MySQL SSL 连接的优化策略与性能测试
    MySQL SSL 连接的优化策略与性能测试摘要:随着数据安全性的重视,越来越多的应用程序使用SSL来加密与数据库的通信。然而,使用SSL加密连接可能会对MySQL的性能产生一定的影响。本文将介绍一些优化策略,帮助提高MySQL SSL连接...
    99+
    2023-10-22
    性能测试 优化策略 SSL连接
  • oracle中内连接和外连接的区别
    oracle 中的连接类型分为内连接和外连接。内连接仅返回匹配行的结果,而外连接返回匹配行和仅出现在一个表中的行。外连接有三种类型:左外连接(返回左侧表所有行)、右外连接(返回右侧表所有...
    99+
    2024-04-30
    oracle
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作