№ | СУБД | Тип | May 2020 | Apr 2020 | May 2019 |
---|---|---|---|---|---|
1 | Oracle | Relational DBMS | 1345.44 | +0.02 | +59.89 |
2 | MySQL | Relational DBMS | 1282.64 | +14.29 | +63.67 |
3 | Microsoft SQL Server | Relational DBMS | 1078.30 | -5.12 | +6.12 |
4 | PostgreSQL | Relational DBMS | 514.80 | +4.95 | +35.91 |
5 | MongoDB | Document store | 438.99 | +0.57 | +30.92 |
6 | DB2 | Relational DBMS | 162.64 | -2.99 | -11.80 |
7 | Elasticsearch | Search engine | 149.13 | +0.22 | +0.51 |
8 | Redis | Key-value store | 144.17 | -1.33 | -4.93 |
9 | SQLite | Relational DBMS | 123.09 | +0.84 | +0.14 |
10 | Microsoft Access | Relational DBMS | 119.90 | -2.02 | -23.88 |
В MySQL различные хранилища объектов реализованы в виде подключаемых модулей.
Это порождает конфликт интересов:
Данная особенность архитектуры MySQL проходит красной нитью через весь функционал.
CHECK TABLE mytable
и REPAIR TABLE mytable
DELAY_KEY_WRITE
Метаданные дублиются как в ядре MySQL, так и в его хранилише. Возникает проблема с транзакционным обновленим метаданных.
Из-за этого DDL-запросы в MySQL не транзакционны.
То есть, любой DDL-запрос автоматически подтвержает старую транзакцию и начинает новую. Этот факт может сильно усложнять написание скриптов миграции.
По той же причине, в MySQL почти любой ALTER TABLE влечет за собой полное пересоздание таблицы (по крайней мере в InnoDB). В том числе это касается таких операций как удалние CONSTRAINT-ов, удаление стоблцов и создание NULL-столбцов.
В большинстве СУБД подобные операции требуют только изменения метаданных и выполняются мгновенно.
С MySQ 5.7.4 появился флаг ALGORITHM=INPLACE
для модификации таблицы без копирования её содержимого.
By default, ResultSets are completely retrieved and stored in memory. In most cases this is the most efficient way to operate and, due to the design of the MySQL network protocol, is easier to implement. If you are working with ResultSets that have a large number of rows or large values and cannot allocate heap space in your JVM for the memory required, you can tell the driver to stream the results back one row at a time.
To enable this functionality, create a Statement instance in the following manner:
stmt = conn.createStatement(
java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
В MySQL хранилище и лог транзакций существуют за пределами "движка" СУБД.
Как следствие, в MySQL вместо журнала транзакций для репликации используется отдельный журнал.
Сохраняются непосредственно запросы, которые информаци об изменениях записей.
Сохраняется информаци об изменениях записей.
В случае 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)
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 минут работы сервера.