#MySQL与PostgreSQL新特性对比 - 2024年最新功能分析
#引言
随着数据库技术的不断发展,MySQL和PostgreSQL都在持续推出新功能以满足现代应用的需求。MySQL 8.x版本和PostgreSQL 14+版本都引入了许多创新特性,本文将详细对比这两个主流数据库系统的最新功能,帮助开发者根据具体需求选择最适合的数据库系统。
#1. 版本发展概述
#1.1 MySQL版本演进
MySQL经历了几个重要的发展阶段:
- MySQL 5.7:引入JSON数据类型、多源复制等
- MySQL 8.0:引入窗口函数、CTE、角色管理、不可见索引等
- MySQL 8.0.x:持续优化性能和安全性
#1.2 PostgreSQL版本演进
PostgreSQL同样在不断进化:
- PostgreSQL 10:引入逻辑复制、分区表等
- PostgreSQL 11:增强分区功能、并行处理等
- PostgreSQL 12:改进查询计划、分区表增强等
- PostgreSQL 13:并行处理优化、索引改进等
- PostgreSQL 14:逻辑复制改进、哈希索引等
- PostgreSQL 15:并行处理增强、即时压缩等
- PostgreSQL 16:最新版本,包含多项性能优化
#2. JSON支持对比
#2.1 MySQL JSON特性
#MySQL 8.x JSON功能:
-- JSON数据类型
CREATE TABLE user_profiles (
id INT PRIMARY KEY,
profile JSON
);
-- JSON数据插入
INSERT INTO user_profiles VALUES (
1,
JSON_OBJECT(
'name', 'John Doe',
'age', 30,
'skills', JSON_ARRAY('Python', 'JavaScript', 'SQL'),
'address', JSON_OBJECT(
'city', 'New York',
'zip', '10001'
)
)
);
-- JSON查询
SELECT
id,
JSON_EXTRACT(profile, '$.name') AS name,
JSON_EXTRACT(profile, '$.skills') AS skills
FROM user_profiles
WHERE JSON_EXTRACT(profile, '$.age') > 25;
-- MySQL 8.0.17+支持JSON_TABLE
SELECT jt.*
FROM user_profiles,
JSON_TABLE(
profile,
'$.skills[*]' COLUMNS (
skill_name VARCHAR(50) PATH '$'
)
) AS jt
WHERE jt.skill_name = 'Python';#JSON索引支持:
-- 为JSON字段创建虚拟列和索引
ALTER TABLE user_profiles
ADD COLUMN skill_index VARCHAR(50)
GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(profile, '$.skills[0]'))) STORED;
CREATE INDEX idx_primary_skill ON user_profiles(skill_index);#2.2 PostgreSQL JSON特性
#PostgreSQL JSON功能:
-- JSON和JSONB数据类型
CREATE TABLE user_profiles (
id SERIAL PRIMARY KEY,
profile_json JSON,
profile_jsonb JSONB
);
-- JSONB数据插入(推荐,性能更好)
INSERT INTO user_profiles (profile_jsonb) VALUES (
'{
"name": "John Doe",
"age": 30,
"skills": ["Python", "JavaScript", "SQL"],
"address": {
"city": "New York",
"zip": "10001"
}
}'::jsonb
);
-- JSONB查询
SELECT
id,
profile_jsonb->>'name' AS name,
profile_jsonb->'skills' AS skills
FROM user_profiles
WHERE (profile_jsonb->>'age')::int > 25;
-- JSONB路径查询
SELECT *
FROM user_profiles
WHERE profile_jsonb @> '{"skills": ["Python"]}'::jsonb; -- 包含Python技能
-- JSONB存在查询
SELECT *
FROM user_profiles
WHERE profile_jsonb ? 'address'; -- 包含address字段
-- JSONB路径存在查询
SELECT *
FROM user_profiles
WHERE profile_jsonb ?& ARRAY['name', 'age']; -- 同时包含name和age字段#JSONB索引支持:
-- GIN索引(推荐用于JSONB)
CREATE INDEX idx_profile_gin ON user_profiles USING GIN (profile_jsonb);
-- GIN索引支持复杂的JSON查询
CREATE INDEX idx_skills_gin ON user_profiles USING GIN ((profile_jsonb->'skills'));
-- GiST索引(另一种选择)
CREATE INDEX idx_profile_gist ON user_profiles USING GIST (profile_jsonb);#2.3 JSON功能对比总结
| 特性 | MySQL | PostgreSQL |
|---|---|---|
| JSON标准 | 基本支持 | 严格遵循RFC标准 |
| 性能 | JSON vs JSON_BINARY | JSONB(二进制存储)性能更好 |
| 索引支持 | 通过虚拟列 | GIN/GiST原生支持 |
| 查询语法 | JSON_EXTRACT | ->, ->> 操作符 |
| 复杂查询 | 有限支持 | 强大的路径查询 |
| JSON_TABLE | 8.0.17+支持 | 不直接支持 |
#3. 窗口函数与CTE
#3.1 MySQL窗口函数(8.0+)
-- 窗口函数支持
SELECT
employee_id,
first_name,
last_name,
department_id,
salary,
ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_salary_rank,
RANK() OVER (ORDER BY salary DESC) AS company_rank,
LAG(salary) OVER (PARTITION BY department_id ORDER BY hire_date) AS prev_salary,
AVG(salary) OVER (PARTITION BY department_id) AS dept_avg_salary
FROM employees;
-- 递归CTE(8.0+)
WITH RECURSIVE org_hierarchy AS (
-- 锚点查询
SELECT
employee_id,
first_name,
last_name,
manager_id,
1 as level
FROM employees
WHERE manager_id IS NULL
UNION ALL
-- 递归查询
SELECT
e.employee_id,
e.first_name,
e.last_name,
e.manager_id,
oh.level + 1
FROM employees e
JOIN org_hierarchy oh ON e.manager_id = oh.employee_id
)
SELECT * FROM org_hierarchy ORDER BY level, last_name;#3.2 PostgreSQL窗口函数与CTE
-- 窗口函数(更丰富的功能)
SELECT
employee_id,
first_name,
last_name,
department_id,
salary,
ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_salary_rank,
RANK() OVER (ORDER BY salary DESC) AS company_rank,
DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_dense_rank,
LAG(salary) OVER (PARTITION BY department_id ORDER BY hire_date) AS prev_salary,
AVG(salary) OVER (PARTITION BY department_id) AS dept_avg_salary,
-- PostgreSQL特有
PERCENT_RANK() OVER (ORDER BY salary) AS salary_percentile,
CUME_DIST() OVER (ORDER BY salary) AS cumulative_distribution,
NTILE(4) OVER (ORDER BY salary) AS salary_quartile
FROM employees;
-- 高级CTE功能
WITH RECURSIVE fibonacci(n, fib_n, next_fib) AS (
-- 基础情况
SELECT 1, 1, 1
UNION ALL
-- 递归情况
SELECT n + 1, next_fib, fib_n + next_fib
FROM fibonacci
WHERE n < 10
)
SELECT n, fib_n FROM fibonacci;
-- PostgreSQL特有:MATERIALIZED/NOT MATERIALIZED
WITH large_dataset AS MATERIALIZED (
-- 这个CTE会被物化(计算一次并存储)
SELECT * FROM very_large_table WHERE condition = 'value'
),
processed_data AS (
SELECT * FROM large_dataset WHERE other_condition = 'other_value'
)
SELECT * FROM processed_data;#4. 分区表功能
#4.1 MySQL分区(8.0+)
-- MySQL分区表(8.0+移除了对早期分区语法的支持)
CREATE TABLE sales (
id INT NOT NULL,
sale_date DATE NOT NULL,
amount DECIMAL(10,2),
region VARCHAR(50)
) PARTITION BY RANGE (YEAR(sale_date)) (
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
-- 列分区(8.0+支持)
CREATE TABLE orders (
order_id INT NOT NULL,
customer_id INT,
order_date DATE,
region CHAR(2)
) PARTITION BY LIST COLUMNS(region) (
PARTITION p_north VALUES IN ('NW', 'NE'),
PARTITION p_south VALUES IN ('SW', 'SE'),
PARTITION p_central VALUES IN ('NC', 'SC')
);
-- 哈希分区
CREATE TABLE sessions (
session_id VARCHAR(128) NOT NULL,
user_id INT,
created_at TIMESTAMP
) PARTITION BY HASH(user_id) PARTITIONS 4;#4.2 PostgreSQL分区(10+)
-- PostgreSQL声明式分区(10+)
CREATE TABLE sales (
id SERIAL,
sale_date DATE NOT NULL,
amount DECIMAL(10,2),
region VARCHAR(50)
) PARTITION BY RANGE (sale_date);
-- 创建分区
CREATE TABLE sales_2022 PARTITION OF sales
FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');
CREATE TABLE sales_2023 PARTITION OF sales
FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
CREATE TABLE sales_2024 PARTITION OF sales
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
-- 列表分区
CREATE TABLE orders (
order_id INT,
customer_id INT,
order_date DATE,
region CHAR(2)
) PARTITION BY LIST (region);
CREATE TABLE orders_north PARTITION OF orders
FOR VALUES IN ('NW', 'NE');
CREATE TABLE orders_south PARTITION OF orders
FOR VALUES IN ('SW', 'SE');
-- 哈希分区(PostgreSQL 11+)
CREATE TABLE large_table (
id INT,
data TEXT
) PARTITION BY HASH (id) (PARTITIONS 8);
-- PostgreSQL 11+:分区上的索引
CREATE INDEX idx_sales_date ON sales_2023 (sale_date);
-- 自动传播到所有分区
CREATE INDEX idx_sales_amount ON sales (amount);#5. 并行处理能力
#5.1 MySQL并行处理
MySQL在并行处理方面的改进相对有限:
-- MySQL 8.0+ 并行复制
-- 在配置文件中设置
-- slave_parallel_workers = 4
-- slave_parallel_type = LOGICAL_CLOCK
-- InnoDB并行查询(有限支持)
-- MySQL主要依靠查询优化器进行优化#5.2 PostgreSQL并行处理
PostgreSQL在并行处理方面有显著优势:
-- 并行扫描
EXPLAIN (ANALYZE, BUFFERS)
SELECT COUNT(*) FROM large_table WHERE some_column > 1000;
-- 并行聚合
EXPLAIN (ANALYZE, BUFFERS)
SELECT department_id, COUNT(*), AVG(salary)
FROM employees
GROUP BY department_id;
-- 并行连接
EXPLAIN (ANALYZE, BUFFERS)
SELECT e.*, d.*
FROM large_employees e
JOIN large_departments d ON e.dept_id = d.id;
-- 配置并行处理参数
-- 在postgresql.conf中设置
-- max_worker_processes = 8
-- max_parallel_workers_per_gather = 4
-- max_parallel_workers = 8
-- parallel_setup_cost = 1000
-- parallel_tuple_cost = 0.05#6. 安全特性
#6.1 MySQL安全增强
-- MySQL 8.0+ 密码强度插件
INSTALL COMPONENT 'file://component_validate_password';
SET GLOBAL validate_password.policy = MEDIUM;
SET GLOBAL validate_password.length = 12;
SET GLOBAL validate_password.mixed_case_count = 1;
SET GLOBAL validate_password.number_count = 1;
SET GLOBAL validate_password.special_char_count = 1;
-- 账户管理
CREATE USER 'app_user'@'%'
IDENTIFIED BY 'StrongPassword123!'
PASSWORD EXPIRE INTERVAL 90 DAY
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_LOCK_TIME 2;
-- 角色管理
CREATE ROLE 'app_reader', 'app_writer', 'app_admin';
GRANT SELECT ON company_db.* TO 'app_reader';
GRANT SELECT, INSERT, UPDATE ON company_db.* TO 'app_writer';
GRANT ALL PRIVILEGES ON company_db.* TO 'app_admin';
-- 动态权限(8.0+新增)
CREATE USER 'monitor_user'@'localhost';
GRANT SELECT ON performance_schema.* TO 'monitor_user'@'localhost';
GRANT SHOW_ROUTINE ON *.* TO 'monitor_user'@'localhost';#6.2 PostgreSQL安全特性
-- 行级安全(RLS)
ALTER TABLE employees ENABLE ROW LEVEL SECURITY;
CREATE POLICY employee_isolation_policy ON employees
FOR ALL
TO app_user
USING (department_id = current_setting('app.current_dept')::integer);
-- 列级安全通过视图实现
CREATE VIEW secure_employee_view AS
SELECT employee_id, first_name, last_name, department_id
FROM employees
WHERE current_user IN (
SELECT role_name FROM user_roles
WHERE department_id = employees.department_id
);
-- 透明数据加密(需要外部扩展)
-- 通过pgcrypto扩展实现
CREATE EXTENSION pgcrypto;
-- 加密数据存储
INSERT INTO secure_table (encrypted_data)
VALUES (pgp_sym_encrypt('sensitive data', 'encryption_key'));
-- SSL连接配置
-- 在pg_hba.conf中配置
-- hostssl all all 0.0.0.0/0 md5#7. 性能优化特性
#7.1 MySQL性能优化
-- MySQL 8.0+ 优化特性
-- 不可见索引
CREATE INDEX idx_invisible ON employees (hire_date) INVISIBLE;
-- 直方图统计
ANALYZE TABLE employees UPDATE HISTOGRAM ON salary, department_id;
-- 直方图使用
SELECT * FROM employees WHERE salary BETWEEN 50000 AND 70000;
-- 成本模型优化
SET SESSION optimizer_switch = 'semijoin=on,factorization=on';
-- MySQL 8.0.22+ 增加的优化
-- 哈希连接(在某些情况下)
EXPLAIN FORMAT=TREE
SELECT e.*, d.*
FROM employees e
JOIN departments d ON e.dept_id = d.id;#7.2 PostgreSQL性能优化
-- 即时压缩(PostgreSQL 14+)
-- 在postgresql.conf中设置
-- enable_incremental_sort = on
-- jit_provider = 'llvmjit' -- JIT编译支持
-- 分区剪枝优化
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM sales
WHERE sale_date >= '2023-01-01' AND sale_date < '2024-01-01';
-- 并行处理优化
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT department_id, COUNT(*), AVG(salary)
FROM employees
GROUP BY department_id;
-- 索引优化
-- BRIN索引(适合大表)
CREATE INDEX idx_large_table_brin ON large_table USING BRIN (date_column);
-- 覆盖索引
CREATE INDEX idx_covering ON employees (department_id, salary)
INCLUDE (first_name, last_name);
-- 部分索引
CREATE INDEX idx_active_employees ON employees (hire_date)
WHERE status = 'active';#8. 扩展性和插件系统
#8.1 MySQL扩展
-- 存储引擎插件
-- 安装组件
INSTALL COMPONENT 'file://component_keyring_file';
-- 插件管理
INSTALL PLUGIN audit_log SONAME 'audit_log.so';
UNINSTALL PLUGIN audit_log;
-- 用户定义函数
-- 需要C/C++编写的UDF#8.2 PostgreSQL扩展
-- 丰富的扩展生态系统
CREATE EXTENSION IF NOT EXISTS pg_stat_statements; -- 查询性能监控
CREATE EXTENSION IF NOT EXISTS pg_trgm; -- 文本相似度搜索
CREATE EXTENSION IF NOT EXISTS fuzzystrmatch; -- 模糊匹配
CREATE EXTENSION IF NOT EXISTS uuid-ossp; -- UUID生成
CREATE EXTENSION IF NOT EXISTS hstore; -- 键值对存储
CREATE EXTENSION IF NOT EXISTS citext; -- 大小写不敏感文本
CREATE EXTENSION IF NOT EXISTS ltree; -- 层次数据结构
-- PostGIS(地理信息)
CREATE EXTENSION IF NOT EXISTS postgis;
-- 全文搜索增强
CREATE EXTENSION IF NOT EXISTS pg_bigm;
-- 使用扩展功能
SELECT similarity('PostgreSQL', 'Postgres');
SELECT levenshtein('kitten', 'sitting');
SELECT gen_random_uuid();#9. 复制和高可用
#9.1 MySQL复制
-- MySQL 8.0+ 组复制
-- 配置文件设置
# [mysqld]
# server_id=1
# gtid_mode=ON
# enforce_gtid_consistency=ON
# master_info_repository=TABLE
# relay_log_info_repository=TABLE
# binlog_checksum=NONE
# log_slave_updates=ON
# log_bin=binlog
# binlog_format=ROW
# plugin_load_add='group_replication.so'
# loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
# loose-group_replication_start_on_boot=off
# loose-group_replication_local_address= "host1:33061"
# loose-group_replication_group_seeds= "host1:33061,host2:33061,host3:33061"
# loose-group_replication_bootstrap_group= off
-- 主从复制监控
SHOW SLAVE STATUS\G
SHOW MASTER STATUS;#9.2 PostgreSQL复制
-- 逻辑复制(PostgreSQL 10+)
-- 创建发布者
CREATE PUBLICATION my_publication FOR TABLE users, orders;
-- 创建订阅者
CREATE SUBSCRIPTION my_subscription
CONNECTION 'host=pubserver dbname=mydb'
PUBLICATION my_publication;
-- 监控复制
SELECT * FROM pg_stat_replication;
SELECT * FROM pg_stat_wal_receiver;
-- 流复制监控
SELECT
client_addr,
state,
sent_lsn,
write_lsn,
flush_lsn,
replay_lsn,
write_lag,
flush_lag,
replay_lag
FROM pg_stat_replication;#10. 监控和诊断
#10.1 MySQL监控
-- 性能模式(Performance Schema)
SELECT
event_name,
count_star,
sum_timer_wait/1000000000 as total_time_seconds
FROM performance_schema.events_statements_summary_global_by_event_name
ORDER BY sum_timer_wait DESC
LIMIT 10;
-- 信息模式查询
SELECT
table_schema,
table_name,
table_rows,
data_length,
index_length
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys')
ORDER BY data_length DESC;
-- 慢查询日志分析
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;#10.2 PostgreSQL监控
-- pg_stat_statements扩展
SELECT
query,
calls,
total_time,
mean_time,
rows,
100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
-- 系统统计视图
SELECT
datname,
numbackends,
xact_commit,
xact_rollback,
blks_read,
blks_hit,
tup_returned,
tup_fetched,
tup_inserted,
tup_updated,
tup_deleted
FROM pg_stat_database
WHERE datname = current_database();
-- 表统计信息
SELECT
schemaname,
tablename,
seq_scan,
seq_tup_read,
idx_scan,
idx_tup_fetch,
n_tup_ins,
n_tup_upd,
n_tup_del
FROM pg_stat_user_tables
ORDER BY seq_scan DESC;#11. 新特性对比总结
| 特性 | MySQL 8.x | PostgreSQL 14+ |
|---|---|---|
| JSON支持 | 基础功能,JSON_TABLE | 高级功能,GIN索引 |
| 窗口函数 | 8.0+支持 | 原生支持,功能丰富 |
| CTE | 8.0+支持 | 原生支持,MATERIALIZED |
| 分区表 | 范围/列表/哈希 | 声明式分区,更灵活 |
| 并行处理 | 有限支持 | 强大的并行能力 |
| 行级安全 | 企业版 | 开源支持 |
| 扩展系统 | 有限 | 丰富生态系统 |
| 逻辑复制 | 8.0+支持 | 原生支持 |
| 即时压缩 | 不支持 | 14+支持 |
| JIT编译 | 不支持 | 支持LLVM JIT |
#12. 选择建议
#12.1 选择MySQL的场景
- Web应用开发:与PHP、Python Web框架集成良好
- 云原生环境:AWS RDS、Google Cloud SQL等托管服务
- 简单应用:不需要复杂SQL功能的场景
- 团队熟悉度:已有MySQL运维经验
- 成本考虑:预算有限的项目
#12.2 选择PostgreSQL的场景
- 复杂数据关系:需要高级SQL功能的应用
- 数据分析:复杂查询和分析需求
- 地理信息:PostGIS扩展支持
- 企业级应用:需要高级安全和可靠性
- 开源优先:更开放的许可证
- 数据完整性:严格的ACID合规性
#相关教程
#总结
MySQL和PostgreSQL都在不断演进,各自在不同领域都有优势:
- MySQL:在Web应用、云环境、易用性方面表现出色,适合快速开发
- PostgreSQL:在功能完整性、数据类型丰富性、高级特性方面领先,适合复杂应用
在2024年,两个数据库系统都提供了强大的功能集,选择哪个主要取决于具体的应用场景、团队技能和业务需求。随着技术的发展,两者之间的差距在逐渐缩小,最终选择应基于实际项目需求进行评估。

