Bootstrap

MySQL(七)MySQL和Oracle、PostgreSQL的区别


本系列文章:
   MySQL(一)SQL语法、数据类型、常用函数、事务
   MySQL(二)MySQL SQL练习题
   MySQL(三)视图、存储过程、索引
   MySQL(四)存储引擎、锁
   MySQL(五)MySQL架构、数据库优化、主从复制
   MySQL(六)SQL语句优化
   MySQL(七)MySQL和Oracle、PostgreSQL的区别

一、MySQL和Oracle

1.1 基本差别*

  • 数据库类型
      Oracle数据库是一个对象关系数据库管理系统(ORDBMS),MySQL是一个开源的关系数据库管理系统(RDBMS)。

  对象关系数据库管理系统:基于对象模型,存储数据及其方法,数据存储在对象中。拥有对象类、对象标识、多态、封装和继承等特性。用于存储复杂的数据。
  关系数据库管理系统:基于关系模型, 只存储数据,数据存储在实体里面,以包含特定信息的表格的形式存在。用于处理比较简单的数据。

  • 客户规模
      Oracle主要面向大企业级别的用户,而MySQL则更适合中小型企业和个人
  • 成本
      Oracle付费,MySQL免费
  • 可移植性和兼容性
      MySQL可以很容易地在各种平台上运行,并与其他许多开源软件集成。Oracle虽然也有跨平台支持,但更偏向于使用自己的技术堆栈和产品集成。
  • 安全性
      Oracle使用了许多安全功能,如用户名,密码,配置文件,本地身份验证,外部身份验证,高级安全增强功能等。MySQL只使用三个参数来验证用户,即用户名,密码和位置。
  • 内存
      Oracle占有内存空间大(因为面对对象,并且还存储数据的方法);MySQL占有内存空间比较小
  • 性能和扩展性
      由于MySQL的精简设计和管理方式,所以其性能通常比Oracle更高,尤其在读取和写入方面。MySQL的扩展性也相对较好,因为其社区活跃,有许多插件和工具可供选择和使用。
  • 支持并发量
      Oracle使用行级别的锁,不依赖索引来锁定某一行,锁资源的粒度小,所以并发性高,支持大并发访问量
      MySQL只有InnoDb支持行锁,而且必须依赖索引才能用到行锁,否则会使用表锁,所以并发性较低,面对大访问量可以做分表分库优化。
  • 数据量
      Oracle单表数据量,可以千万,甚至上亿的规模Mysql单表数据量,最好控制在百万级别
  • 事务隔离级别
      Oracle默认的是 read commited(读已提交)的隔离级别,会有不可重复读+幻读的问题。
      MySQL默认是 repeatable read(可重复度)的隔离级别,只会有幻读的问题。
  • 临时表
      在MySQL中,临时表是仅对当前用户会话可见的数据库对象,并且一旦会话结束,这些表将自动删除。
      Oracle中临时表的定义与MySQL略有不同,因为临时表一旦创建就会存在,直到它们被显式删除,并且对具有适当权限的所有会话都可见。但是,临时表中的数据仅对将数据插入表中的用户会话可见,并且数据可能在事务或用户会话期间持续存在。
  • sql语句的灵活性
      MySQL对sql语句有很多非常实用而方便的扩展,比如limit功能(分页)、insert可以一次插入多行数据;Oracle在这方面感觉更加稳重传统一些,Oracle的分页是通过伪列和子查询完成的,插入数据只能一行行的插入数据。
  • 对于事务的支持
      Mysql对于事务默认是不支持的,只是有某些存储引擎中如:innodb可以支持;而Oracle对于事物是完全支持的。

  适合Oracle的场景:

  对数据库有高级需求:如果企业对数据库的高级需求较高,如存储复杂数据及其方法,要求高可用性、灾备恢复、安全性等,可以考虑用Oracle。
  大型企业应用:Oracle在处理大规模、复杂的企业级应用方面表现出色。它能够处理海量的数据和高并发的访问请求,同时支持复杂的数据模型和关系。
  项目并发量高:使用Oracle,它是是OLTP(联机事务处理)最好的工具。
  安全性要求高:Oracle使用了许多安全功能,如用户名,密码,配置文件,本地身份验证,外部身份验证,高级安全增强功能等。像金融、银行等对安全性要求高的项目一般都选用Oracle作为数据库。
  高可用性和容灾需求:Oracle提供了强大的高可用性和容灾解决方案,例如集群配置、数据复制和自动故障转移等,能够确保系统的连续性和数据的可靠性。MySQL付费版也支持,但可靠性不如Oracle。

1.2 使用区别

  • 1、大小写是否敏感
      Oracle:双引号下大小写敏感,大小写不敏感的前提条件是在没有使用双引号 “” 的前提下(表名、字段名)。
      Oracle创建表默认大写,可以设置为小写。
// 如果创建表的时候是这样写的,那么就必须严格区分大小写
CREATE TABLE "TableName"("id" number); 
// 不仅要区分大小写而且要加双引号,以便和上面的第三种查询方式区分开
SELECT * FROM "TableName"; 

   MySQL创建的表名默认小写

  • 2、常用字段类型
      Oracle常用字段类型:

  数值:number。
  字符串:CHAR,NCHAR,VARCHAR2和NVARCHAR2。
   char:使用数据库字符集来存储数据,长度固定,如果存储的数据没有达到指定长度,自动补足空格。
   nchar:使用国家字符集来存储数据,长度固定,如果存储的数据没有达到指定长度,数据库自动补足空格。
   varchar2: 使用数据库字符集存储数据,长度可变,如果存储数据没有达到指定长度,不自动补足空格。
   nvarchar2:使用国家字符集来存储数据,长度可变,如果存储的数据没有达到指定长度,不自动补足空格。
  日期:date、timestamp。

  oracle的varchar,一般不使用,那个是sql标准的类型,允许空串,oracle自己开发了个类型叫varchar2,不允许存空串,而且可以兼容以后的oracle版本。
  MySQL常用字段类型:

  数值:tinyint、smallint、mediumint、int、bigint、decimal。
  字符串:char、varchar。
  日期:date、time、datetime、timestamp。

  • 3、时间日期
      Oracle对于计算前7天,时间减7就行了;计算前1个小时,时间减1/24就行了,加法同理:
select TO_DATE('2021-05-30 15:51:20', 'yyyy-mm-dd hh24:mi:ss') -7 from dual;
-- 计算前7天,结果:2021-05-23 15:51:20

select TO_DATE('2021-05-30 15:51:20', 'yyyy-mm-dd hh24:mi:ss') - 1/24 from dual;
-- 计算前1个小时,结果:2021-05-30 14:51:20

  MySQL计算前7天,或者前1个小时,需要用不同的关键字:

select date_sub('2021-05-30 21:00:40' ,interval 7 day)
-- 计算前7天,结果:2021-05-23 21:00:40

select date_sub('2021-05-30 21:00:40' ,interval 1 hour)
-- 计算前1个小时,结果:2021-05-30 20:00:40

  Oracle中timestamp类型的字段,相减,结果是多少天、多少小时,多少分钟,多少秒:

SELECT MIN_T, MAX_T, MAX_T - MIN_T 
FROM "T_TIMESTAMP"
-- 结果:2021-07-06 20:29:20.000000	2021-07-07 20:29:22.000000	+000000001 00:00:02.000000

  MySQL中,2个timestamp类型的值相减,如果想要知道相差多少天、多少秒,需要借助函数:

SELECT min_t, max_t, TIMESTAMPDIFF(second,min_t,max_t) FROM `t_timestamp`
-- 结果:
2021-07-03 21:01:22	2021-07-04 21:01:22	86400
2021-07-04 21:02:01	2021-07-04 21:02:06	5
2021-07-04 21:03:58	2021-07-04 21:04:01	3

  Oracle使用to_date()函数,将字符串转时间:

select TO_DATE('2021-05-30 15:51:20', 'yyyy-mm-dd hh24:mi:ss') from dual;
-- 24小时制的转换,结果:2021-05-30 15:51:20

select TO_DATE('2021-05-30 下午 11:51:20', 'yyyy-mm-dd am hh12:mi:ss') from dual;
-- 12小时制的转换,结果:2021-05-30 23:51:20

  MySQL的字符串转时间,使用str_to_date()函数:

select STR_TO_DATE('2021-05-30 15:51:20','%Y-%m-%d %H:%i:%s');
-- 结果:2021-05-30 15:51:20
-- tip: myql的这个格式,也不难记,Y、m、d、H、i、s

  Oracle使用to_char()函数,将时间转字符串:

select to_char(current_date, 'yyyy-mm-dd hh24:mi:ss') from dual;
-- 24小时制的转换,结果:2021-05-30 16:06:52

select to_char( TO_DATE('2021-05-30 15:51:20', 'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd am hh12:mi:ss') from dual;
-- 12小时制的转换,结果:2021-05-30 下午 03:51:20

  MySQL使用date_format()函数:

select DATE_FORMAT(current_timestamp,'%Y-%m-%d %H:%i:%s');
-- 结果:2021-05-30 16:10:14

  Oracle查询当前的日期+时间示例:

select CURRENT_TIMESTAMP from dual;
-- 结果:2021-05-30 16:19:10.640466 +08:00

select current_date from dual;
-- 结果:2021-05-30 16:16:54

select SYSDATE from dual;
-- 结果:2021-06-07 20:54:57

  MySQL查询当前的日期+时间示例:

select CURRENT_TIMESTAMP;
-- 结果:2021-05-30 16:21:16

select now();
-- 结果:2021-05-30 16:17:41
-- 我一般用这个,比较简单,好记忆

select sysdate()
-- 结果:2021-06-07 20:55:38
  • 4、建表和插入数据
-- Oracle
create table t_student(
    sid int primary key ,
    sname varchar2(10) not null ,
    enterdate date,
    gender char(2),
    mail unique,
    age number check (age>19 and age<30)
)
insert into t_student values(stuseq.nextval,'Test',to_date('1990-3-4','YYYY-MM-DD'),'男','[email protected]',20);
commit;

--MySQL
create table t_student(
    sid int primary key auto_increment,
    sname varchar(1) not null ,
    enterdate date,
    gender char(1),
    age int,
    mail varchar(10) UNIQUE
)
insert into t_student values(null,'Test','1990-3-4','男',30,'[email protected]')
  • 5、事务
      Oracle:完全支持事务,默认不自动提交,需要用户手动提交,提交可以通过以下几个命令实现:

  BEGIN:事务块开始的标志。事务块里的SQL语句要么全部执行成功,要么全部失败回滚。
  COMMIT:提交事务。执行成功时,事务将被提交,并且对数据库的修改是可见的。
  ROLLBACK:用于取消尚未提交的事务,并将数据库恢复到事务开始之前的状态。当ROLLBACK语句执行成功时,事务中的所有修改都将被撤销。
  SAVEPOINT:用于在事务中创建一个保存点,以便在事务执行过程中可以回滚到该保存点。它可以在事务中设置一个中间点,以便在需要时回滚到该点。
  SET TRANSACTION:SET TRANSACTION用于设置事务的属性。通过该命令,可以设置事务的隔离级别、读写权限等属性。

  示例:

BEGIN
    SAVEPOINT sp;
    
    -- 向学生表插入数据
    INSERT INTO student_table (student_name, student_age) VALUES ('John', 18);
    INSERT INTO student_table (student_name, student_age) VALUES ('Emma', 19);
    
    -- 向班级表插入数据
    INSERT INTO class_table (class_name, class_size) VALUES ('Class A', 30);
    INSERT INTO class_table (class_name, class_size) VALUES ('Class B', 28);
    
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK TO sp;
        RAISE;
END;

  MySQL:仅innoDB支持事务,默认自动提交。

-- 关闭事务提交
set AutoCommit = 0;
-- 手动提交事务
START TRANSACTION;        -- 开始事务
INSERT INTO student (name,age) VALUES ('Tom',18); -- 执行一些数据操作
INSERT INTO score (student_id,score) VALUES (1,90);
COMMIT;       -- 手动提交事务
  • 6、分页
      Oracle:需要用rownum和子查询来做。示例:
-- 查第10-20条记录。10、20个数字表示记录的行号
select * from (
	SELECT emp.*, rownum as rowno from emp
)t_target
where rowno >= 10 and rowno < 20

  MySQL:通过limit关键字分页。示例:

-- 查第10-20条记录。第一个10表示起始下标,第二个10表示取多少条记录
SELECT * FROM `tb_user`
limit 10, 10
  • 7、id递增的处理
      Oracle需要通过手动新建1个序列+触发器来实现:
-- 第一步:创建序列(ps: 也可以通过navicat创建)
create sequence SEQ_T_LOCALOBTMIND
-- 验证序列是否能成功取到值
select SEQ_T_LOCALOBTMIND.nextval from dual

-- 第二步:设置触发器(ps: 请确保表名、字段都是大写的,否则触发器执行会失败)
create or replace trigger T_LOCALOBTMIND_INSERT_ID
before insert on "T_LOCALOBTMIND" for each row
begin
	select SEQ_T_LOCALOBTMIND.nextval into:NEW.ID from dual;
end;

-- 第三步:测试
INSERT INTO "T_LOCALOBTMIND"("DDATETIME", "OBTID", "WDIDF") VALUES (TO_DATE('2021-06-03 08:22:04', 'SYYYY-MM-DD HH24:MI:SS'), 'G1121', '11.34');

  MySQL则自带自动自增的功能。

  • 7、字符处理
      Oracle的字符串只能用单引号包裹。
select concat('%', 'G1120') from dual
-- 结果:%G1120

  MySQL的字符串可以用单引号,也可以用双引号包裹。

select concat("%", 'G1120')
-- 结果:%G1120

  oracle中不允许有空字符串的存在,如果update某个字段为’',则会发现这个字段值变成null了。mysql中允许空字符串。

  • 8、多条件判断
      Oracle惯用decode()函数,另外支持case when的用法:
-- decode()函数
select DECODE(2, 
1, '风速',
2, '雨量',
3, '浪高',
null)
from dual;
-- 结果:
-- 雨量

-- case when的写法1:公式匹配

select sal, CASE 
	when sal >= 5000 then '高薪'
	when sal >= 2000 then '中薪'
	WHEN sal > 800 THEN '低薪'
	ELSE '其它'
END as cn
from emp;
-- 结果:800	其它
-- 1600	低薪
-- 1250	低薪
-- 2975	中薪

-- case when的写法2:值匹配
select sal, CASE sal
	when 5000 then '高薪'
	when 1600 then '中薪'
	WHEN 800 THEN '低薪'
	ELSE '其它'
END as cn
from emp;
-- 结果:
-- 800	低薪
-- 1600	中薪
-- 1250	其它
-- 2975	其它

  MySQL,一般也用case when。

  • 9、小数格式化
      Oracle使用to_char()函数:
select to_char(211.125456,'99999999999990.99') from dual;
-- 需要四舍五入的情况,结果:211.13
select to_char(211.1,'99999999999990.99') from dual;
-- 小数位不够2位的情况,结果:211.10
select to_char(0,'99999999999990.99') from dual;
-- 特殊值0的情况,结果:0.00

  MySQL使用format()函数:

select FORMAT(211.125,2);
-- 需要四舍五入的情况,结果:211.13
select FORMAT(211.1,2);
-- 小数位不够2位的情况,结果:211.10
select FORMAT(0,2);
-- 特殊值0的情况,结果:0.00
  • 10、查询语句
      Oracle的查询必须带from:
select current_date from dual;
-- 结果:2021-05-30 16:16:54

  MySQL的查询,就没强制要求带from关键字,但是查询dual表也支持:

select now();
-- 结果:2021-05-30 16:17:41

二、MySQL和PostgreSQL

  PostgreSQL是一个企业级的关系数据库,允许关系和非关系查询,支持:Java、.net、Go、C、C++等。PostgreSQL通常用作网站、地理空间和分析应用程序的主要数据存储或仓库。

2.1 基本差别*

  • PostgreSQL的优势
      1、功能强大。PostgreSQL对正则表达式的支持强,内置函数也丰富
      2、性能优化工具与度量信息丰富。PostgreSQL数据库中有大量的性能视图,可以方便地定位问题。此外,PostgreSQL还设计了专门架构和进程用于收集性能数据视图,比如可以看打卡正在执行的SQL、哪条记录被锁定等。
      3、在线操作功能好。PostgreSQL增加空值列时,本质上只是在系统表上把列定义上,无须对物理结构做更新。PostgreSQL还支持在线建索引的功能,在创建索引的过程中,可以不锁更新操作。
      4、支持数据仓库。MySQL对SQL语法支持的功能较弱,基本上不适合做数据仓库。PostgreSQL不仅支持复杂的SQL,还有大量的分析函数,非常适合做数据仓库。
      5、移动互联网特征。PostgreSQL中还有一些支持移动互联网的新功能,比如:空间索引。
      综上,PostgreSQL是一个功能强大、又带有移动互联网的开源数据库。
  • MySQL的优势
      1、MySQL的事务回滚机制较好。InnoDB的基于回滚实现的MVCC机制,相对于PG新老数据一起存放的基于XID的MVCC机制,是占优的。
      2、MySQL采用索引组织表。这种存储方式非常适用于主键匹配的查询、删改操作,但是对表结构设计存在约束。
      3、MySQL的优化器比较简单。系统表、运算符、数据类型的实现都很精简,非常适合简单的查询操作
      4、MySQL分区表的实现要优于PG。
      5、MySQL的存储引擎插件化机制。使得它的应用场景更加广泛,比如除了InnoDB适合事务处理场景外,MyIsam适合静态数据的查询场景。
  • 两者的选择
      如果仅仅是想把数据库作为一个简单的存储软件,比如一些大型互联网公司就是这样,一些比较复杂的功能都放在应用中,那么MySQL是合适的。
      如果应用的数据访问很简单,比如大多数的博客系统,那么后端使用MySQL也是合适的。
      如果应用不像博客系统那么简单,又不像耗费太多的开发资源,那么使用PostgreSQL是合适的。

2.2 使用差别

  • 1、格式区别
      和Oracle一样,PostgreSQL也是严格区分大小写。
  • 2、自增区别
      MySQL中使用auto_increment ,在需要的列指定自增;而PostgreSQL中需要设置自增序列。
      PostgreSQL的自增序列设置:
-- 创建表时
CREATE table infisa_template_config(id serial );
-- 表已存在
<--设置序列从1开始,自增1-->
CREATE SEQUENCE user_id_seq START WITH 1  
INCREMENT BY 1  NO MINVALUE  NO MAXVALUE  CACHE 1;
<--设置序列-->
ALTER table user ALTER column id SET DEFAULT nextval('user_id_seq');
  • 3、时间转化
      时间转字符串:
-- MySQL
date_format(a.tag_create_date,'%Y-%m-%d %H:%i:%s')
-- PostgreSQL
to_char(a.tag_create_date,'yyyy-mm-dd HH:MM:SS')

  字符串转时间:

-- MySQL
STR_TO_DATE('2021-05-30 15:51:20','%Y-%m-%d %H:%i:%s')
-- PostgreSQL
to_date(a.tag_create_date,'yyyy-mm-dd HH:MM:SS')
  • 4、字段为null时返回指定值
-- MySQL
IFNULL(a.idm,'')
-- PostgreSQL
COALESCE(a.id,'')
  • 5、获取当前日期
-- MySQL
SELECT sysdate()
-- PostgreSQL
SELECT now()
  • 6、limit
-- MySQL
select id,name from hospital.ods_user_basic limit 10,2;
-- PostgreSQL
select id,name from hospital.ods_user_basic limit 10 offset 2;
;