Oracle和MySQL竟然可以这么写这样的SQL?(r12笔记第99天)

今天看到Franck Pachot?发了一个Twitter,意思是Oracle里的SQL还能这么写。猛一看确实让人有些意外。

禁不住诱惑,自己也尝试了一番。我现在12cR2的环境中测试了一下。

Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

尝试上面的步骤,先来看看dual表。

SQL> select count(*)from dual;
  COUNT(*)
----------
         1

开始测试,这样看起来不规范的SQL照样能够正常解析

SQL> select +count(*) from dual;
 +COUNT(*)
----------
         1

SQL> select -count(*)from dual;
 -COUNT(*)
----------
        -1SQL> select +dummy from dual;
DU
--
X
SQL> select -dummy from dual;
select -dummy from dual
        *
ERROR at line 1:
ORA-01722: invalid number如果对dual表抱有一丝幻想,那么我们换一个数据字典cat

SQL> select count(*)from cat;
  COUNT(*)
----------
      8113

SQL> select +count(*)from cat;
 +COUNT(*)
----------
      8113SQL> select -count(*)from cat;
 -COUNT(*)
----------
     -8113看起来依旧可以,我们换一个堆表。

SQL> create table test_data as select *from user_objects;
Table created.

SQL> select count(*)from test_data;
  COUNT(*)
----------
     51907SQL> select +count(*)from test_data;
 +COUNT(*)
----------
     51907SQL> select -count(*)from test_data;
 -COUNT(*)
----------
    -51907换成object_id字段 

SQL> select -object_id from test_data where rownum<3;
-OBJECT_ID
----------
       -16
       -20SQL> select +object_id from test_data where rownum<3;
 OBJECT_ID
----------
        16
        20  对此如果还有一些疑问,我们可以使用10053来解析一下,看看优化器是如何处理的。       
SQL> alter session set events '10053 trace name context forever,level 12';
SQL>  select -object_id from test_data where rownum<3;
-OBJECT_ID
----------
       -16
       -20
SQL> alter session set events '10053 trace name context off';    
查询转换后的SQL如下:

Final query after transformations:******* UNPARSED QUERY IS *******
SELECT (-"TEST_DATA"."OBJECT_ID") "-OBJECT_ID" FROM "SYS"."TEST_DATA" "TEST_DATA" WHERE ROWNUM<3
*************************

而如果是字符型数据,则使用这种方式的减号就不可行了。

SQL> select  -object_name from test_data where rownum<2;
select  -object_name from test_data where rownum<2
         *
ERROR at line 1:
ORA-01722: invalid number如果你以为是12c里面的一些新特性这类的,其实在10g也是类似的结果。

MySQL篇

如果你认为这是Oracle优化器的强大,其实不然,我们看看MySQL里的表现,假设表为test_tab.

> select -count(*) from test_tab;
+-----------+
| -count(*) |
+-----------+
|   -548650 |
+-----------+
1 row in set (0.39 sec)

使用运算符,可以看到也是支持的。

> select +count(*)from test_tab;
+-----------+
| +count(*) |
+-----------+
|    548650 |
+-----------+
1 row in set (0.39 sec)

如果查询两条数据,进行比对测试。

> select login_account from test_tab limit 2;
+-------------------------------+
| login_account                 |
+-------------------------------+
| 0000000180000000@test.com |
| 000000111000@test.com     |
+-------------------------------+
2 rows in set (0.00 sec)

我们继续使用运算符来处理。

> select -login_account from test_tab limit 2;
+----------------+
| -login_account |
+----------------+
|     -180000000 |
|        -111000 |
+----------------+
2 rows in set, 2 warnings (0.00 sec)

注意这里有两个警告,我们看看警告内容,原来内容都被处理过了。

> show warnings;
+---------+------+-------------------------------------------------------------------+
| Level   | Code | Message                                                           |
+---------+------+-------------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '0000000180000000@test.com' |
| Warning | 1292 | Truncated incorrect DOUBLE value: '000000111000@test.com'     |
+---------+------+-------------------------------------------------------------------+
2 rows in set (0.00 sec)如果我们手动换一种形式,写为0-xxx的形式,结果是一样的。

> select 0-login_account from test_tab limit 2;
+-----------------+
| 0-login_account |
+-----------------+
|      -180000000 |
|         -111000 |
+-----------------+
2 rows in set, 2 warnings (0.01 sec)

这里的结果其实涉及到sql_mode的设置,在此就不再展开了。
回到这个问题,上面的语句竟然可以解析,在优化器中是什么样的呢?可以使用explain extended的方式来解析,结果如下:
> explain extended select -count(*) from test_tab;
+----+-------------+----------+-------+---------------+-----------------------+---------+------+--------+----------+-------------+
|
id | select_type | table    | type  | possible_keys |
key                   | key_len | ref  | rows   | filtered | Extra      
|
+----+-------------+----------+-------+---------------+-----------------------+---------+------+--------+----------+-------------+

1 | SIMPLE      | test_tab | index | NULL          |
ind_tmp_login_account | 303     | NULL | 548474 |   100.00 | Using index
|
+----+-------------+----------+-------+---------------+-----------------------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)解析的结果如下,可以看到原本的count(*)自动转换为了count(0),然后做了运算处理。

> show warnings;
+-------+------+----------------------------------------------------------+
| Level | Code | Message                                                  |
+-------+------+----------------------------------------------------------+
| Note  | 1003 | select -(count(0)) AS `-count(*)` from `test`.`test_tab` |
+-------+------+----------------------------------------------------------+
1 row in set (0.00 sec)

时间: 2024-10-23 19:54:17

Oracle和MySQL竟然可以这么写这样的SQL?(r12笔记第99天)的相关文章

MySQL中的批量初始化数据的对比测试(r12笔记第71天)

  一直以来对于MySQL的存储过程性能还是颇有微词的,说实话够慢的.有时候想做一些对比测试,存储过程初始化几万条数据都得好一会儿,这功夫Oracle类似的测试早都做完了,今天就赶个晚班车,把这个没做完的任务完成了.     我大体测试了一下,以100万数据为基准,初始化性能的提升会从近8分钟提升到10多秒钟.      我自己尝试了以下4种方案.      1.存储过程批量导入(近8分钟)      2.存储过程批量导入内存表,内存表导入目标表(近5分钟)      3.使用shell脚本生成

MySQL中的double write(二)(r12笔记第17天)

    MySQL里的double write是InnoDB的三大闪亮特性,另外两个是insert buffer 和自适应哈希,其实还有几个比如异步IO,Flush neighbour Page(刷新邻接页),这个和系统层面的关联性较高,所以三大亮点还是更有针对性的.    当然一说到MySQL里的double write,其实主要是要应对一个很自然的问题,那就是partial write. 经典的partial write问题    这个问题比较经典,很多数据库设计中都需要考虑到这样一个临界点

MySQL主从不一致发现的细小问题分析(r12笔记第63天)

   今天和同事一起看了一个问题,她在一个主从环境中发现了数据不一致,存在主键冲突.     show slave status的报错信息大概是下面的样子. Last_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 0 failed executing transaction '0e454161-3169-11e7-98f6

MySQL自增列主从不一致的测试(r12笔记第37天)

    MySQL里面有一个问题尤其值得注意,那就是自增列的重复值问题,之前也简单分析过一篇,但是在后续我想了下,还有很多地方需要解释,一个就是从库的自增列是如何维护的,是否重启从库,自增列会受到影响.    我们继续来测试一下.首先复现这个问题.    创建表t1,插入3行数据. use test; [test]> drop table if exists t1; Query OK, 0 rows affected, 1 warning (0.01 sec) > create table t

Oracle Data Guard压缩归档测试(二)(r12笔记第27天)

昨天对Data Guard的归档压缩进行了一个初步的测试,我今天又做了一些补充.    1.昨天测试的是默认50M的redo,如果redo增大,在IO bound的场景中,是否有很大的变化    2.对于归档压缩来说,数据量如果增大,是否会有较大的抖动,昨天测试的是20G的数据量,初始化了50%    3.对于整个数据初始化的过程中,主备的延迟到底有多大,是否有延迟回落的现象.    我们一个一个来做解答. 首先是redo的大小调整,我们需要设置redo大小为200M,备库的standby lo

分分钟搭建MySQL Group Replication测试环境(二)(r12笔记第41天)

   之前总结过一篇,是分分钟搭建MySQL MGR环境的,但是有一个地方还有待改善,那就是那个脚本仅仅支持single-primary模式,不支持多主模式,而官方文档中这部分信息还比较少.    我觉得这部分内容一方面和本身MGR的多主支持还不够成熟也有关系,需要一个过渡.但是如果想测试测试也是完全可以的,所以我决定改进我的脚本.    大体来说,如果要开启多主模式,如果能够轻松搭建出单主,读写分离的架构,那么搭建多主是很简单的一件事情. 在原来单主模式的主节点执行操作如下: stop GRO

MySQL 5.6, 5.7并行复制测试(r12笔记第9天)

   对于主从延迟,其实一直以来就是一个颇有争议的话题,在MySQL阵营中,如果容忍一定的延迟的场景,通过主从来达到读写分离是个很不错的方案,但是延迟率到底有多高可以接受,新版本中的并行复制效果怎么样,在不同的版本中是否有改变,我们能否找到一些参考的数据来佐证,这一点上我们可以通过一些小测试来说明.    首先来为了基本按照同一个参考标准,我们就在同一台服务器上安装了5.6,5.7的MySQL服务,另外一台服务器上搭建了从库.    数据库版本为5.6.23 Percona分支, 5.7.17

多个数据库-c3p0同时配置Oracle和MySQL,JBDCUtil应如何写

问题描述 c3p0同时配置Oracle和MySQL,JBDCUtil应如何写 我想通过配置c3p0.xml文件在我需要时可以连接oracle或者MySQL数据库,但我不知道jdbcutil该怎么写

PHP将数据从Oracle向Mysql数据迁移实例

为什么要迁移? 首先从运营成本考虑,用Mysql可以节约不少的费用.另一方面,Mysql的稳定性及功能不断地提高与 增强,基本上可以满足客户的需求,如支持多 节点部署,数据分区等.还有就是Mysql使用方便,比 Oracle简单易用.故客户就要求将已有的Oracle数据表与内容迁移到Mysql来. 为什么要自己写脚本? 迁移的表与数据都蛮多的,有几百张表.因此手工完成不太方便.也尝试了一些免费的迁移工具, 如:MySQLMigrationTool等,发现转移 的字段类型不太符合要求(可能是原来的