首页 » MySQL/TiDB/GoldenDB » 注意: GreatDB中sysdate并不是oracle的sysdate

注意: GreatDB中sysdate并不是oracle的sysdate

国产库在承接Oracle替换方面做了大量的兼容性,如果仅实现了语法兼容,没有相同的语义,这恐怕比不兼容还糟糕,比如原来的oracle的应用迁移到国产库后执行不报错,但却有可能和oracle得到完全不一样的结果。今天我们以万里开源的GreatDB中的sysdate为例, 对最近同事遇到这个案例简单分享。

事出一条简单的SQL

select * from testdb.tab_log where CLICKDATE>sysdate-0.1;

该表是范围分区表,CLICKDATE列为年月日时分秒的datetime类型,该列上有索引,主键是包含这列在内的4个列混合,在oracle中对于该语句,如果返回的数据量较少(<3%)可能会使用index scan 回表. 在oracle是查询最近0.1天内的数据。但这条SQL在GreateDB中执行时间超长,查看执行计划。

GreatDB Cluster[(none)]> explain select * from testdb.tab_log where CLICKDATE>sysdate-0.1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tab_log
   partitions: P_01,P_02,P_03,P_04,P_05,P_06,P_07,P_08,P_09,P_10,P_11,P_12,P_13,P_14,P_15,P_16,P_17,P_18,P_19,P_20,P_21,P_22,P_23,P_24,P_25,P_26,P_27,P_28,P_29,P_30,P_31,P_AA
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1045527980
     filtered: 33.33
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

Note:

上面使用的FULL TABLE SCAN.

尝试使用force index 选项如oracle的 index hint强制优化器使用索引

GreatDB Cluster[icdpub]> explain select count(*) from testdb.tab_log FORCE INDEX (IX_BSF_MENUCLICKLOG_CLICKDATE)  where CLICKDATE>sysdate-0.1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tab_log
   partitions: P_01,P_02,P_03,P_04,P_05,P_06,P_07,P_08,P_09,P_10,P_11,P_12,P_13,P_14,P_15,P_16,P_17,P_18,P_19,P_20,P_21,P_22,P_23,P_24,P_25,P_26,P_27,P_28,P_29,P_30,P_31,P_AA
         type: index
possible_keys: NULL
          key: IX_BSF_MENUCLICKLOG_CLICKDATE
      key_len: 5
          ref: NULL
         rows: 1045527980
     filtered: 33.33
        Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)

GreatDB Cluster[icdpub]> select count(*) from testdb.tab_log FORCE INDEX (IX_BSF_MENUCLICKLOG_CLICKDATE)  where CLICKDATE>sysdate-0.1;

+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (42 min 39.45 sec) 

Note:
可以使用索引, 但是注意返回0条记录,耗时42分钟。思考一下,索引有效,选择率也不错无返回数据。为什么没有使用索引?关建是不太可能0.1天内无数据,这是个Wrong Result.

对比GreatDB 和oracle 的sysdate运算
先看ORACLE的结果

SYSDATE SYSDATE-0.1 SYSDATE-1 0.1*24*3600 SYSDATE-INTERVAL’8640’SECOND
20230919 15:12:24 20230919 12:48:24 20230918 15:12:24 8640 20230919 12:48:24

NOTE:
oracle后面跟的数值计算是‘天’为单位, 运算后返回的是date类型。

再看GreateDB

 GreatDB Cluster[(none)]> select sysdate,sysdate-0.1;    
+---------------------+------------------+
| sysdate             | sysdate-0.1      |
+---------------------+------------------+
| 2023-09-11 16:52:09 | 20230911165208.9 |
+---------------------+------------------+
1 row in set (0.00 sec)

GreatDB Cluster[(none)]> select now(),now()-0.1,sysdate,sysdate-0.1;
+---------------------+------------------+---------------------+------------------+
| now()               | now()-0.1        | sysdate             | sysdate-0.1      |
+---------------------+------------------+---------------------+------------------+
| 2023-09-13 17:19:07 | 20230913171906.9 | 2023-09-13 17:19:07 | 20230913171906.9 |
+---------------------+------------------+---------------------+------------------+
1 row in set (0.00 sec)

Note:
可见sysdate-0.1返回的并不是原date类型,值也不是0.1天,似乎是0.1秒, 并且sysdate的结果与mysql的now()一样,众所周知GreatDB就是MySQL的衍生产品,那sysdate可能就是now()的同义词,但还不是oracle的sysdate同义,这就是我们开头所说可怕之处。

如何查看返回记录的数据类型?

1,使用–column-type-info

$ mysql --column-type-info  -v
$ select xxx



2,  创建临时表

$ create table test as  select xxx ;
$ dest test


Note:
总之计算后的数据类型为数值型, 和整数运算返回是bigint, 与小数运算返回的decimal. 并不是和oracle一样的datetime类型, 如果类型不一样,在查询时需要隐士转换,可能导致无法使用索引。

GreatDB sysdate – X,  真的是’秒’为单位吗?

SQL> select now(),NOW()-3600;
now() NOW()-3600
2023-09-19 14:33:44 20230919139744

NOTE:
1小时3600秒,但是我们减去3600,并不是和当前时间差1小时。139744也不是有效的时分秒.

interval 小数 day

select now(),now()-0.1,now()-1,now() - interval 0.6 day,now() - interval 0.1 day;
now() now()-0.1 now()-1 now() – interval 0.6 day now() – interval 0.1 day
2023-09-19 14:33:44 20230919143343.9 20230919143343 2023-09-18 14:33:44 2023-09-19 14:33:44
SELECT now(),DATE_SUB(NOW(), INTERVAL 0.5 DAY) AS c2,DATE_SUB(NOW(), INTERVAL 0.1 DAY) c3 ;
now() c2 c3
2023-09-19 14:33:44 2023-09-18 14:33:44 2023-09-19 14:33:44

Note:
– interval X day 和date_sub  interval X day的X还是四舍五入法,不足0.5 当0, 否则当1 ‘天’。

DATE_SUB 改写

Oracle

select to_date('2023-09-19 14:33:44','yyyy-mm-dd hh24:mi:ss')-0.1;
TO_DATE(‘2023-09-1914:33:44′,’YYYY-MM-DDHH24:MI:SS’)-0.1
20230919 12:09:44

GreatDB/MySQL

select now(),now()-0.1*24*60*60, DATE_SUB(NOW(), INTERVAL  0.1*24*60*60 second) ;
now() now()-0.1*24*60*60 DATE_SUB(NOW(), INTERVAL 0.1*24*60*60 second)
2023-09-19 14:33:44 20230919134704.0 2023-09-19 12:09:44.0

改写SQL后再看最补业务SQL的执行计划

select * from testdb.tab_log where CLICKDATE> DATE_SUB(now(),INTERVAL 0.1*24*60*60 second)\G

GreatDB Cluster[(none)]> explain select * from testdb.tab_log where CLICKDATE> DATE_SUB(now(), INTERVAL  0.1*24*60*60 second)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tab_log
   partitions: P_01,P_02,P_03,P_04,P_05,P_06,P_07,P_08,P_09,P_10,P_11,P_12,P_13,P_14,P_15,P_16,P_17,P_18,P_19,P_20,P_21,P_22,P_23,P_24,P_25,P_26,P_27,P_28,P_29,P_30,P_31,P_AA
         type: range
possible_keys: IX_BSF_MENUCLICKLOG_CLICKDATE
          key: IX_BSF_MENUCLICKLOG_CLICKDATE
      key_len: 5
          ref: NULL
         rows: 10
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

Note:
现在默认已可以使用index range scan. 响应时间回到了ms级。 属于理想的性能。

GoldenDB是否存在相同问题?
和GreatDB一样同根MySQL的另一国产库GoldenDB同样也实现了sysdate兼容,我们测试一下GoldenDB是否存在相同的问题?

MySQL [(none)]> select now(),now()-0.1,sysdate,sysdate-0.1;
--------------
select now(),now()-0.1,sysdate,sysdate-0.1
--------------

Field   1:  `NOW()`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       DATETIME
Collation:  binary (63)
Length:     19
Max_length: 19
Decimals:   0
Flags:      NOT_NULL BINARY 

Field   2:  `NOW()-0.1`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       NEWDECIMAL
Collation:  binary (63)
Length:     18
Max_length: 16
Decimals:   1
Flags:      NOT_NULL BINARY NUM 

Field   3:  `SYSDATE`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       DATETIME
Collation:  binary (63)
Length:     19
Max_length: 19
Decimals:   0
Flags:      NOT_NULL BINARY 

Field   4:  `SYSDATE-0.1`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       DATETIME
Collation:  binary (63)
Length:     19
Max_length: 19
Decimals:   0
Flags:      BINARY 


+---------------------+------------------+---------------------+---------------------+
| NOW()               | NOW()-0.1        | SYSDATE             | SYSDATE-0.1         |
+---------------------+------------------+---------------------+---------------------+
| 2023-09-20 08:23:34 | 20230920082333.9 | 2023-09-20 08:23:34 | 2023-09-20 05:59:34 |
+---------------------+------------------+---------------------+---------------------+
1 row in set (0.00 sec)

Note:
在GoldenDB中sysdate的表现和Oracle一样。 对于两款数据库并不是对比好坏, 只是说明在sysdate这个常用函数上,GoldenDB至少是认真对待了。

— over —

打赏

,

对不起,这篇文章暂时关闭评论。