Крылья, ноги и хвосты:
Сильные стороны MySQL и когда PostgreSQL завоюет мир
Алексей Копытов
Крылья, ноги и хвосты:
Сильные стороны MySQL и когда PostgreSQL завоюет мир
Алексей Копытов
Вступление
Нет!
Ретроспектива: LAMP
– Почему MySQL популярен сейчас?
– Потому что был популярен раньше!
– А почему был популярен раньше?
– Потому что «хостеры» и MyISAM!
«Рабочая лошадка» LAMP проектов:
MySQL | PostgreSQL | PostgreSQL (сторонние решения) | |
---|---|---|---|
2001 | логическая statement-based (3.23) | ||
2004 | логическая trigger-based (Slony-I) | ||
2006 | логическая statement-based (pgPool-II) | ||
2007 | логическая trigger-based (Bucardo, Londiste) | ||
2008 | логическая row-based (5.1) | ||
2010 | физическая (9.0) |
Репликация в MySQL:
MySQL | PostgreSQL | |
---|---|---|
2000 | встроенный, для MyISAM (3.23.23) | |
2001 | contrib: Tsearch | |
2003 | contrib: Tsearch2 | |
2008 | встроенный (8.3) | |
2013 | встроенный, для InnoDB (5.6) |
За кадром: сравнение функционала, внешние решения (OpenFTS, Sphinx, Lucene, и т.д.)
MySQL | PostgreSQL | |
---|---|---|
2000 | REPLACE INTO , INSERT IGNORE (3.23) |
|
2004 | INSERT … ON DUPLICATE KEY UPDATE (4.1) |
|
2016 | INSERT … ON CONFLICT DO UPDATE/NOTHING (9.5) |
Использование контрольных сумм для проверки целостности данных:
MySQL | PostgreSQL | |
---|---|---|
2001 | страницы данных | |
2002 | журнал REDO в InnoDB | журнал WAL |
2013 | страницы данных¹ |
MySQL | PostgreSQL | |
---|---|---|
2009 | параллельный импорт/экспорт (myloader/mydumper) | параллельный импорт, pg_restore -j (8.4) |
2013 | параллельный экспорт pg_dump -j (9.3) |
|
select count(*) from t; select idx from t where idx > key; select idx from t where idx in (1, 10, 100);
MySQL | PostgreSQL | |
---|---|---|
⩽2000 | да | |
2012 | да, с ограничениями (9.2) |
UPDATE
не трогает индексы при обновлении только неиндексированных колонок:UPDATE metrics SET value = value + 1 WHERE name = 'requests';
MySQL | PostgreSQL | |
---|---|---|
⩽2000 | да (MyISAM, InnoDB) | |
2008 | да, с ограничениями (8.3) |
MySQL | PostgreSQL | |
---|---|---|
1998 | MySQL AB | |
2001? | 2ndQuadrant¹ | |
2004 | EnterpriseDB |
¹ нет упоминаний в сети до 2008г.
PERFORMANCE_SCHEMA
, Pinba)
Плюсы:
Минусы:
Кластеризованные индексы в PostgreSQL:
CLUSTER
делает одноразовую реорганизациюПлюсы:
Минусы:
Стандартная таблица sysbench, 1M записей:
CREATE TABLE sbtest1 ( id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, k INTEGER UNSIGNED DEFAULT '0' NOT NULL, c CHAR(120) DEFAULT '' NOT NULL, pad CHAR(60) DEFAULT '' NOT NULL ); CREATE INDEX k_1 ON sbtest1(k);
CREATE TABLE sbtest1 ( id SERIAL NOT NULL PRIMARY KEY, k INTEGER DEFAULT '0' NOT NULL, c CHAR(120) DEFAULT '' NOT NULL, pad CHAR(60) DEFAULT '' NOT NULL ); CREATE INDEX k_1 ON sbtest1(k);
data | index | total | |
---|---|---|---|
InnoDB | 214.70 | 19.55 | 234.25 |
PostgreSQL | 211.23 | 50.10 | 261.33 |
MySQL:
PostgreSQL (TOAST):
Та же таблица (sbtest1, 1M записей)
data | index | total | |
---|---|---|---|
InnoDB | 214.70 | 19.55 | 234.25 |
PostgreSQL | 211.23 | 50.10 | 261.33 |
InnoDB, zlib | 115.38 | 10.27 | 125.65 |
innodb_page_size = 16K
(4K, 8K, 16K, 32K, 64K)OS_FILE_LOG_BLOCK_SIZE=512
BLCKSZ = 8K
XLOG_BLCKSZ = 8K
(1K, 2K, 4K, 8K, 16K, 32K, 64K)InnoDB:
PostgreSQL:
InnoDB:
PostgreSQL:
select count(*) from pg_settings where name like '%vacuum%'; count ------- 23 (1 row)
O_DIRECT
ALL_O_DIRECT
(в Percona Server, MariaDB/XtraDB)O_DIRECT
(2)
O_DIRECT
в PostgreSQL:
XLOG_BLCKSZ=8
write amplification взлетает до небесshared_buffers
= ~25% RAM)O_DIRECT
(3)MySQL:
PostgreSQL:
O_DIRECT
Jeremy Cole, 2010:
Twitter/Percona/MariaDB, 2012:
numa_interleave
innodb_buffer_pool_populate
flush_caches
Oracle, 2015:
innodb_numa_interleave
= numa_interleave
+ innodb_buffer_pool_populate
PostgreSQL, 2016:
numactl
(плохо!)Атомарная запись данных на устройства хранения FusionIO:
O_DIRECT
)MySQL:
PostgreSQL:
pg_prewarm
(contrib) – загрузить заданную таблицуpg_hibernator
(github) – близко, но ограниченноНа сервере A:
FLUSH TABLES t FOR EXPORT
.ibd
файл на другой серверUNLOCK TABLES
На сервере B:
ALTER TABLE t DISCARD TABLESPACE
ALTER TABLE t IMPORT TABLESPACE
Нет аналогов в PostgreSQL.
Intel® Xeon® E7-58800 v4/v3, 4 x 18 ядер, key/value запросы (SELECT... WHERE pk=const
)
MySQL (источник: блог Дмитрия Кравчука)
PostgreSQL:
fork()/clone()
– достаточно быстрая операция в Linuxpthread_create()
sysbench, connect test, Linux, Xeon E5-2683v4:
connect/disconnect time, ms | |
---|---|
MySQL 5.7.13 с thread cache | 0.20 |
MySQL 5.7.13 без thread cache | 0.40 |
PostgreSQL 9.5.3 | 3.73 |
Медленнее в ~18 раз.
MyRocks и TokuDB:
NDB:
MySQL + NDB:
Типичные области применения:
DISTINCT
и GROUP BY
запросовCREATE TABLE t1m10cp(a int, b int); CREATE INDEX t1m10cp_ab on t1m10cp(a,b); SELECT MIN(b) FROM t1m10cp GROUP BY a;
mysql> explain select min(b) from t1m10cp group by a\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t1m10cp partitions: NULL type: range possible_keys: t1m10cp_ab key: t1m10cp_ab key_len: 10 ref: NULL rows: 11 filtered: 100.00 Extra: Using index for group-by mysql> select min(b) from t1m10cp group by a; +--------+ | min(b) | +--------+ . . . +--------+ 11 rows in set (0.00 sec)
PostgreSQL:
sbtest=# explain select min(b) from t1m10cp group by a; QUERY PLAN ----------------------------------------------------------------------- HashAggregate (cost=21370.00..21370.11 rows=11 width=8) Group Key: a -> Seq Scan on t1m10cp (cost=0.00..16370.00 rows=1000000 width=8) sbtest=# select min(b) from t1m10cp group by a; min ----- . . . (11 rows) Time: 282.493 ms
Пример коррелированного подзапроса:
create table t10 (a int, b int); insert into t10 select a, 1 from ten; select count(*) from t1m10cp where pk in (select b from t10 where t10.a=t1m10cp.a);
MySQL:
mysql> select count(*) from t1m10cp where pk in (select b from t10 where t10.a=t1m10cp.a); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec)
MySQL: DuplicateWeedout стратегия
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: t10 partitions: NULL type: ALL key: NULL rows: 10 filtered: 100.00 Extra: Using where; Start temporary *************************** 2. row *************************** id: 1 select_type: SIMPLE table: t1m10cp partitions: NULL type: eq_ref key: PRIMARY key_len: 4 ref: sbtest.t10.b rows: 1 filtered: 10.00 Extra: Using where; End temporary
PostgreSQL: «наивное» вычисление подзапроса
sbtest=# explain analyze select count(*) from t1m10cp where pk in (select b from t10 where t10.a=t1m10cp.a); QUERY PLAN ----------------------------------------------------------------------------------------------------------------------- Aggregate (cost=583870.00..583870.01 rows=1 width=0) (actual time=1716.412..1716.412 rows=1 loops=1) -> Seq Scan on t1m10cp (cost=0.00..582620.00 rows=500000 width=0) (actual time=1716.411..1716.411 rows=0 loops=1) Filter: (SubPlan 1) Rows Removed by Filter: 1000000 SubPlan 1 -> Seq Scan on t10 (cost=0.00..1.12 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=1000000) Filter: (a = t1m10cp.a) Rows Removed by Filter: 9 Planning time: 0.064 ms Execution time: 1716.439 ms (10 rows)
MySQL
USE INDEX FOR [FOR {JOIN|ORDER BY|GROUP BY}]
IGNORE INDEX [FOR {JOIN|ORDER BY|GROUP BY}]
FORCE INDEX [FOR {JOIN|ORDER BY|GROUP BY}]
MAX_EXECUTION_TIME
, BKA
, MRR
, NO_ICP
,
NO_RANGE_OPTIMIZATION
, SEMIJOIN
, SUBQUERY
SET optimizer_trace="enabled=on"; SELECT ...; # your query here SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE; ... { "transformation": { "select#": 2, "from": "IN (SELECT)", "to": "semijoin", "chosen": true, "evaluating_constant_semijoin_conditions": [ ] } },
MySQL | PostgreSQL | комментарий | |
---|---|---|---|
? | наследование таблиц | встроенное, trigger-based, RANGE , LIST , недекларативное, ручное управление, проблемы с большим кол-вом секций |
|
2008 | декларативное, 5.1 | встроенное, RANGE , LIST , COLUMNS , KEY , HASH |
|
2012 | pg_partman |
внешнее, наследование, но с автоматизация ручной работы, только time и serial ranges | |
2016 | pg_pathman |
внешнее, (beta?), недекларативное | |
??? | декларативное | встроенное, 9.7? |
Логическая репликация в MySQL:
Сильные стороны логической репликации:
Логическая репликация в Booking.com:
PostgreSQL:
Полусинхронная (semi-synchronous) репликация:
synchronous_standby_names
близко по смыслу, но не то)Сравнение возможностей утилит физического резервного копирования:
Percona XtraBackup | pg_basebackup |
barman | |
---|---|---|---|
полные | ✔ | ✔ | ✔ |
кросс-платформенные | ✔ | ||
инкрементальные | ✔ | ✔¹ | |
частичные | ✔ | ✔ | |
параллельные | ✔ | ||
сжатые | ✔ | ||
"компактные" | ✔ | ||
зашифрованные | ✔ | ||
облачные | ✔ |
¹ – очень ограниченно и медленно (rsync)
PERFORMANCE_SCHEMA
pg_stat_*
Планировщик заданий.
MySQL:
PostgreSQL:
mysql.*
)разрешить аутентификацию всем локальным пользователям:
CREATE USER ''@localhost;
данные аутентификации в pg_hba.conf
, авторизации в системных таблицах
local all all trust host all all 127.0.0.1/32 trust host all all ::1/128 trust
Сэкономить время на:
MySQL:
PostgreSQL:
Когда PostgreSQL завоюет мир?
Вопросы, комментарии, истории?