暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

和 PostgresSQL 相比,MySQL 真是个阴间数据库

虎之书 2021-06-24
798

MySQL 的傻逼之处真是罄竹难书。


再一次印证,产品的好坏和成功与否是两个维度。


具体而言,弱类型允许瞎转换用户数据类型、时间类型字面量规则复杂模糊且不合理、行为不一致、该细致的地方含糊、该简单的地方弄复杂。


举两个最近被恶心的很厉害的例子。


第一个是关于 time 函数的。


    select time("10:11:1212");
    select time("-1? 10:11:12");


    猜猜上面两句 SQL 在 MySQL 里面执行的结果是啥?


    从正常人的脑回路来看,第一个应该报错吧?10 小时 11 分 1212 秒不应该是个正确的时间长度。如果第一个不报错,那第二个肯定要报错吧?


    答案是,这两个都只会报 warning,而结果是



      mysql> select time("10:11:1212");
      +--------------------+
      | time("10:11:1212") |
      +--------------------+
      | NULL |
      +--------------------+
      1 row in set, 1 warning (0.00 sec)


      mysql> select time("-1? 10:11:12");
      +----------------------+
      | time("-1? 10:11:12") |
      +----------------------+
      | -00:00:01 |
      +----------------------+
      1 row in set1 warning (0.00 sec)


      惊喜不惊喜?


      MySQL 这样搞的原因我大概是理解的,希望尽量容忍用户犯错,但这种定义不清楚、结果不合理的行为最大的问题是有可能造成严重的数据错误。


      此外,这个 time 函数还支持 time(201010) 这种形式,意思是 20:10:10,注意传入的是 int 字面量。


      MySQL 文档中提到:

      MySQL interprets abbreviated TIME values with colons as time of the day. That is, '11:12' means '11:12:00', not '00:11:12'. [...] you might think of '1112' and 1112 as meaning '11:12:00' (12 minutes after 11 o'clock), but MySQL interprets them as '00:11:12' (11 minutes, 12 seconds). Similarly, '12' and 12 are interpreted as '00:00:12'.

      https://dev.mysql.com/doc/refman/5.7/en/time.html

      这种无节制的纵容输入格式,已经让 time 相关的函数实现复杂度爆炸了。感兴趣可以看看 tidb 为了在这方面和 MySQL 兼容所堆出来的屎山(很荣幸我在屎山上捏着鼻子加了不少屎)。


      如果说上面这个例子还算能接受,下面来个更劲爆的。


        create table t2 (a year(4));
        insert into t2 values(2020);
        select * from t2 where a <= 69;


        猜猜上面语句执行结果呗?


        显然表中只有一行 2020。2020 比 69 大,所以应该返回空集对吧。


        然而 MySQL 执行结果如下:


          mysql> select * from t2 where a <= 69;
          +------+
          | a |
          +------+
          | 2020 |
          +------+
          1 row in set (0.00 sec)


          如果你没仔细看过 MySQL 文档,肯定想不明白。


          当然我是看过的,原因在于,对于 YEAR 类型 MySQL 会把整形的 70~99 理解为 1970~1999、把 1~69 理解为 2001~2069,那 0 是什么意思呢?0 是 0000,一个不合法的值……如果你要插入 2000,请用字符串 "00"。


          我吐了。


          如果你捏着鼻子读完冗长的文档,在其中找到了这一条,恭喜你,学到了毫无用处的一点也不合理的规则。


          如果说,MySQL 行为和文档一致也就算了。


          上述是一个 YEAR 类型的列和 int 常量比较,那么当 int 常量落入 MySQL 文档所描述的范围内被默认按规则理解成其他值也就算了。


          但是如果拿一个 YEAR 类型列和 INT 类型列做比较,那么上述规则就完全不起作用。


            create table t3 (y year, a int);
            insert into t3 values (2020, 69);
            select * from t3 where y <= a;


            结果是空集。


            MySQL,我 xxxx。


            MySQL 之于数据库,就像微信之于 IM 软件,简而言之就是“阴间玩意儿”。


            我最近开始对 Postgres 这种阳间数据库产生了兴趣,扒下代码大概看了下,代码结构、里面的 readme 水平,比 MySQL 不知道高到哪里去了。看了些网上对 Postgres 和 MySQL 的对比,几乎一边倒吐槽 MySQL,而 Postgres 则很少看到负面评价。


            产品设计是个大学问,数据库产品也是产品,而且是 mission critical 的产品。


            希望人间多些阳间产品、少些阴间玩意儿。


            逃(

            文章转载自虎之书,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论