| № | СУБД | Тип | Apr 2021 | Mar 2021 | Apr 2020 |
|---|---|---|---|---|---|
| 1 | Oracle | Relational DBMS | 1274.92 | -46.82 | -70.51 |
| 2 | MySQL | Relational DBMS | 1220.69 | -34.14 | -47.66 |
| 3 | Microsoft SQL Server | Relational DBMS | 1007.97 | -7.33 | -75.46 |
| 4 | PostgreSQL | Relational DBMS | 553.52 | +4.23 | +43.66 |
| 5 | MongoDB | Document store | 469.97 | +7.58 | +31.54 |
| 6 | DB2 | Relational DBMS | 157.78 | +1.77 | -7.85 |
| 7 | Redis | Key-value store | 155.89 | +1.74 | +11.08 |
| 8 | Elasticsearch | Search engine | 152.18 | -0.16 | +3.27 |
| 9 | SQLite | Relational DBMS | 125.06 | +2.42 | +2.87 |
| 10 | Microsoft Access | Relational DBMS | 116.72 | -1.41 | -5.19 |
| Release | General availability | Latest version | Latest release | End of support |
|---|---|---|---|---|
| 5.1 | 14 November 2008; 12 years ago | 5.1.73 | 2013-12-03 | Dec 2013 |
| 5.5 | 3 December 2010; 10 years ago | 5.5.62 | 2018-10-22 | Dec 2018 |
| 5.6 | 5 February 2013; 8 years ago | 5.6.51 | 2021-01-20 | Feb 2021 |
| 5.7 | 21 October 2015; 5 years ago | 5.7.34 | 2021-04-20 | Oct 2023 |
| 8.0 | 19 April 2018; 3 years ago | 8.0.24 | 2021-04-20 | Apr 2026 |
В MySQL различные хранилища объектов реализованы в виде подключаемых модулей.
Это порождает конфликт интересов:
Данная особенность архитектуры MySQL проходит красной нитью через весь функционал.
CHECK TABLE mytable и REPAIR TABLE mytableDELAY_KEY_WRITE
Метаданные дублируются как в ядре MySQL, так и в его хранилище. Возникает проблема с транзакционным обновлении метаданных.
Из-за этого DDL-запросы в MySQL не транзакционны.
То есть, любой DDL-запрос автоматически подтверждает старую транзакцию и начинает новую. Этот факт может сильно усложнять написание скриптов миграции.
По той же причине, в MySQL почти любой ALTER TABLE влечет за собой полное пересоздание таблицы (по крайней мере в InnoDB). В том числе это касается таких операций как удаление CONSTRAINT-ов, удаление столбцов и создание NULL-столбцов.
В большинстве СУБД подобные операции требуют только изменения метаданных и выполняются мгновенно.
С MySQ 5.7.4 появился флаг ALGORITHM=INPLACE для модификации таблицы без копирования её содержимого.
По умолчанию резьтаты полностью извлекаются и сохраняются в памяти. В большинстве случаев это наиболее эффективный способ работы и, благодаря архитектуре MySQL, это проще в реализации. Если вы работаете с наборами результатов, которые имеют большое количество строк и не могут выделить пространство в heap вашей JVM, Можно указать драйверу передавать результаты обратно по одной строке за раз.
Для включения этого функционала нужно создать экземпляр Statement следующим образом:
stmt = conn.createStatement(
java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
В MySQL хранилище и лог транзакций существуют за пределами "движка" СУБД.
Как следствие, в MySQL вместо журнала транзакций для репликации используется отдельный журнал.
Сохраняются непосредственно sql запросы, которые несут информацию об изменениях записей.
Сохраняется информация о конкретных изменениях определенных записей.
В случае DDL-выражений сохраняются сами запросы.
Промежуточный формат, который старается использовать statement, когда возможно, а когда нет — row.
ALTER TABLE foo
ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY (id);
SELECT title, description FROM foo
UNION ALL
SELECT title, description FROM bar
ORDER BY title;
SELECT * FROM (
SELECT title, MIN(description) as desc
FROM film
GROUP BY title
) f
WHERE f.title LIKE 'al%';
SELECT * FROM sakila.film
WHERE film_id
IN (1,23,25,106,277);
SELECT * FROM sakila.film
WHERE film_id = 1
OR film_id = 23
OR film_id = 25
OR film_id = 106
OR film_id = 277;
DELETE FROM t1
WHERE
t1.id IN (SELECT t2.id FROM t2);
DELETE t1
FROM
t1 JOIN t2 ON (t1.id = t2.id);
CREATE TABLE data ( id INT NOT NULL, foo INT NULL, bar NUMERIC(4, 2) ); INSERT INTO data VALUES (1, NULL, 1234.5678);Query OK, 1 row affected, 1 warning (0,00 sec)SELECT * FROM data; +----+------+-------+ | id | foo | bar | +----+------+-------+ | 1 | NULL | 99.99 | +----+------+-------+ 1 rows in set (0,00 sec)
Данная опция включена по-умолчанию с MySQL 5.7.5.
Первый General Availability релиз с данным изменением 5.7.9 вышел 21 октября 2015 года.
ALTER TABLE data MODIFY COLUMN foo INT NOT NULL;Query OK, 1 row affected, 1 warning (0,00 sec)SELECT * FROM data; +----+-----+-------+ | id | foo | bar | +----+-----+-------+ | 1 | 0 | 99.99 | +----+-----+-------+ 1 rows in set (0,00 sec)
SELECT MAX(ai_col) FROM table_name FOR UPDATE;
CREATE TABLE k ( A INT NULL, B NUMERIC (4, 2), C TIMESTAMP );INSERT INTO k (A, B) VALUES (42, 22.7);SELECT * FROM k;+----+-------+---------------------+ | A | B | | +----+-------+---------------------+ | 42 | 22.70 | 2017-04-27 20:27:17 | +----+-------+---------------------+ 1 rows in set (0,00 sec)
SELECT * FROM k; +----+-------+---------------------+ | A | B | | +----+-------+---------------------+ | 42 | 22.70 | 2017-04-27 20:27:17 | +----+-------+---------------------+ 1 rows in set (0,00 sec)UPDATE k SET B = B + 1;SELECT * FROM k;+----+-------+---------------------+ | A | B | | +----+-------+---------------------+ | 42 | 23.70 | 2017-04-27 20:27:47 | +----+-------+---------------------+ 1 rows in set (0,00 sec)
CREATE TABLE k (
A INT NULL,
B NUMERIC (4, 2),
C TIMESTAMP,
D TIMESTAMP
);
Error Code: 1067. Invalid default value for 'D'
CREATE TABLE k (
A INT NULL,
B NUMERIC (4, 2),
C TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
D TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
0 rows updated (0,00 sec)
SELECT A, B, SUM(C)
FROM K
GROUP BY A;
Данная опция так же включена по-умолчанию с MySQL 5.7.5.
В MySQL операция UPDATE не соответствует стандарту SQL92.
13.9 <update statement: positioned>
6) The <value expression>s are effectively evaluated before updating the object row. If a <value expression> contains a reference to a column of T, then the reference is to the value of that column in the object row before any value of the object row is updated.
UPDATE foo SET
a = b,
b = a
WHERE id = 42;
В MySQL есть параметр lower_case_table_names, который приводит имена всех таблиц в нижний регистр и
по-умолчанию включён под Windows.
В результате, если взять базу, у которой имена таблиц не в нижнем регистре, и развернуть её под Windows, то перенести эту базу обратно под Linux уже не получится.
# BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
400
# UPDATE accounts SET balance = balance + 100
$ WHERE name = 'Alice';
UPDATE 1
# COMMIT;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
500
# BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
400
# UPDATE accounts SET balance = balance + 100
$ WHERE name = 'Alice';
ERROR: could not serialize access
due to concurrent update
# SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# BEGIN;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
400
# UPDATE accounts SET balance = balance + 100
$ WHERE name = 'Alice';
Query OK, 1 row affected (0.00 sec)
# COMMIT;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
500
# SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# BEGIN;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
400
# UPDATE accounts SET balance = balance + 100
$ WHERE name = 'Alice';
Query OK, 1 row affected (0.00 sec)
# COMMIT;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
600
# SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# BEGIN;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
400
# UPDATE accounts SET balance = balance + 100
$ WHERE name = 'Alice';
Query OK, 1 row affected (0.00 sec)
# COMMIT;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
500
# SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# BEGIN;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
400
# UPDATE accounts SET balance = balance + 100
$ WHERE name = 'Alice';
Query OK, 1 row affected (0.00 sec)
# COMMIT;
# SELECT balance FROM accounts WHERE name = 'Alice';
balance
---------
600
CREATE TABLE orders_range (
customer_surname VARCHAR(30),
store_id INT,
salesperson_id INT,
order_date DATE,
note VARCHAR(500)
) ENGINE = InnoDB
PARTITION BY RANGE (YEAR (order_date)) (
PARTITION p_old VALUES LESS THAN(2008),
PARTITION p_2008 VALUES LESS THAN(2009),
PARTITION p_2009 VALUES LESS THAN(MAXVALUE)
);
По диапазону значений
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (10),
PARTITION p1 VALUES LESS THAN (20),
PARTITION p3 VALUES LESS THAN (30)
);
По точному списку значений
PARTITION BY LIST(store_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20)
);
По хэшу от какой-либо функции
PARTITION BY HASH(YEAR(hired))
PARTITIONS 10;
Почти то же самое что и HASH, но по ключу
PARTITION BY KEY(s1)
PARTITIONS 10;
MySQL для регистронезависимого сравнения использует COLLATIONS (например: utf8_general_ci):
http://collation-charts.org/mysql60/mysql604.utf8_general_ci.european.html
Библиотека на C++, которая может быть использована в вашем приложении для получения обновлений из MySQL. Libslave не связана на уровне кодов с MySQL-сервером; она собирается и линкуется только с клиентом — libmysqlclient.
key_buffer_1.key_buffer_size = 1G
key_buffer_2.key_buffer_size = 1G
CACHE INDEX t1, t2 IN key_buffer_1;
LOAD INDEX INTO CACHE t1, t2;
Эту SQL-команду можно поместить в файл, выполняемый MySQL на этапе запуска. Имя файла задается с помощью параметра init_file.
В нем может быть несколько SQL-команд, каждая в отдельной строке.
В MySQL есть возможность сохранить состояние кэша, чтобы избежать проблемы с прогревом базы.
SET GLOBAL innodb_buffer_pool_dump_at_shutdown = ON;
SET GLOBAL innodb_buffer_pool_dump_now = ON;
SET GLOBAL innodb_buffer_pool_load_now = ON;
SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status';
SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';
Определяет, когда будут сбрасываться данные на диск.
ALTER TABLE sometable DELAY_KEY_WRITE = 1;
mysql> pager grep sequence
PAGER SET TO 'grep sequence'
mysql> SHOW engine innodb STATUS\G SELECT sleep(60); SHOW engine innodb STATUS\G
Log sequence number 84 3836410803
1 row IN SET (0.06 sec)
1 row IN SET (1 min 0.00 sec)
Log sequence number 84 3838334638
1 row IN SET (0.05 sec)
mysql> SELECT (3838334638 - 3836410803) / 1024 / 1024 AS MB_per_min;
+------------+
| MB_per_min |
+------------+
| 1.83471203 |
+------------+
Размер лога выбираем примерно на 10-60 минут работы сервера.