把Table A 的数据全部复制到Table B, 是不是执行 INSERT INTO B(field1, field2) SELECT field1, field2 FROM A? 当然不是, 这么做不还是锁死了Table A 么, 这里的迁移就是一个需要细分的地方,需要写一个脚本, 让程序每次读取比如5000条数据出来, 插入到Table B里面, 因为Table B 是没有索引的, 所以要当心不要使用多进程来做; 如果是多进程, 要确保插入到B的时候是不会有重复数据的; 如果是1000万的数据,每次5000条, 假设这个操作需要500ms, 那么 2000*200ms = 16 分钟。 这只是一个估值, 具体情况和服务器当时的情况有关, 不好细说。 另外, 我们要记录这个迁移开始的时间点,记为t1;
5 为B建立索引, 待索引全部好了之后, 再继续6
那么这个时候Table A 的数据是不是都进入了Table B 呢, 应当说差不多大部分都进入了, 但5中说, 这大概需要16分钟, 这么长的时间里, 可能有新的数据进入了, 也有可能已有的数据发生了更新, 所以我们要把Table A 中在t1 之后发生变化的数据查找出来, 然后更新到Table B 中, 我们的做法是:
1
2
3
4
5
记录这个操作对应的时间点 t2
BEGIN;
DELETE FROM B WHERE updated_time > t1;
INSERT INTO B(field1, field2) SELECT field1, field2 FROM A WHERE updated_time >t1;
COMMIT;
现在A 和 B 差不多該同步了吧? 差不多了, 但是6 执行完之后, A仍然在写, 子子孙孙无穷尽也 … , 但这个时候 A 和 B 的差异已经非常非常小了, 所以在下一步,我们在一个transaction 里执行下面的操作:
1
2
3
4
5
6
7
BEGIN;
DELETE FROM B WHERE updated_time > t2;
INSERT INTO B(field1, field2) SELECT field1, field2 FROM A WHERE updated_time >t2;
ALTER TABLE A RENAME TO C;
ALTER TABLE B RENAME TO A;
COMMIT;
MySQL Workbech
允许update不where更新
1
SET SQL_SAFE_UPDATES = 0;
客户端提示
1
2
3
4
Error Code: 2013. Lost connection to MySQL server during query
Error Code: 2006. MySQL server has gone away
Go to Edit -> Preferences -> SQL Editor and set to a higher value this parameter: DBMS connection read time out (in seconds). For instance: 86400.
<valuetype="object"struct-name="app.MenuItem"id="com.mysql.wb.menu.query.execute_current_statementwin"><linktype="object"key="owner"struct-name="app.MenuItem">com.mysql.wb.menu.query</link><valuetype="string"key="caption">Execute Current Statement</value><valuetype="string"key="name">query.execute_current_statement</value><valuetype="string"key="command">builtin:query.execute_current_statement</value><valuetype="string"key="itemType">action</value><valuetype="string"key="shortcut">F5</value><valuetype="string"key="platform">windows</value></value>
故障处理
忘记密码
mysql 5.7 Ubuntu 64
1
2
3
4
5
sudo service mysql status
sudo service mysql stop
mkdir-p /var/run/mysqld
chown mysql:mysql /var/run/mysqld
sudo mysqld_safe --skip-grant-tables--skip-networking &
Run it first to see if it’s really slow, note setting SQL_NO_CACHE
Single-table query with where conditions, lock the table with minimum returned records. This means applying all where clauses from the query statement starting from the table with the smallest number of returned records, query each field of the single table separately, and see which field has the highest distinctiveness
Use explain to view the execution plan, whether it matches expectation 1 (query starting from the table with fewer locked records)
For SQL statements in the form of order by limit, prioritize querying the sorted table
Understand the business usage scenario
When adding indexes, refer to the major principles of index creation
Observe results, if not meeting expectations, continue analyzing from 0
vi /etc/mysql/my.cnf
```
[mysqld]
bind-address = 0.0.0.0
```
Modify Large Data Tables
The table to be modified Table A needs a field that records timestamps. This timestamp is a field that updates every time data is updated. This field needs an index. In django, you can use auto_now=True
Create a new temporary table Table B, not tmp_table, but a new table that’s temporarily used. This table has the exact same data structure as the table to be modified, plus the parts you want to modify, such as added fields;
Record Table A’s indexes
Delete all indexes from Table B
Copy all data from Table A to Table B. Should we execute INSERT INTO B(field1, field2) SELECT field1, field2 FROM A? Of course not, wouldn’t that still lock Table A? The migration here is a place that needs subdivision. Write a script to have the program read, say, 5000 records at a time, and insert them into Table B. Because Table B has no indexes, be careful not to use multi-process; if multi-process, ensure there’s no duplicate data when inserting into B; if it’s 10 million records, 5000 at a time, assuming this operation takes 500ms, then 2000*200ms = 16 minutes. This is just an estimate, specific situations depend on the server’s condition at the time, hard to detail. Also, we need to record the time point when this migration starts, denoted as t1;
Build indexes for B, wait until all indexes are ready, then continue with 6
So at this point, has all Table A’s data entered Table B? Should say most of it has, but as mentioned in 5, this takes about 16 minutes. In such a long time, new data may have entered, or existing data may have been updated. So we need to find data in Table A that changed after t1, then update it to Table B. Our approach is:
1
2
3
4
5
Record the time point corresponding to this operation t2
BEGIN;
DELETE FROM B WHERE updated_time > t1;
INSERT INTO B(field1, field2) SELECT field1, field2 FROM A WHERE updated_time >t1;
COMMIT;
Now A and B should be pretty much synced, right? Pretty much, but after 6 executes, A is still writing, descendants endless… But at this point, the difference between A and B is very, very small. So in the next step, we execute the following operations in a transaction:
1
2
3
4
5
6
7
BEGIN;
DELETE FROM B WHERE updated_time > t2;
INSERT INTO B(field1, field2) SELECT field1, field2 FROM A WHERE updated_time >t2;
ALTER TABLE A RENAME TO C;
ALTER TABLE B RENAME TO A;
COMMIT;
MySQL Workbench
Allow update without where
1
SET SQL_SAFE_UPDATES = 0;
Client Tips
1
2
3
4
Error Code: 2013. Lost connection to MySQL server during query
Error Code: 2006. MySQL server has gone away
Go to Edit -> Preferences -> SQL Editor and set to a higher value this parameter: DBMS connection read time out (in seconds). For instance: 86400.
Change to F5 Execute Currently Selected Statement
Method: Modify content in C:\Program Files\MySQL\MySQL Workbench 6.3 CE\data\main_menu.xml
1
2
3
4
5
6
7
8
9
10
<valuetype="object"struct-name="app.MenuItem"id="com.mysql.wb.menu.query.execute_current_statementwin"><linktype="object"key="owner"struct-name="app.MenuItem">com.mysql.wb.menu.query</link><valuetype="string"key="caption">Execute Current Statement</value><valuetype="string"key="name">query.execute_current_statement</value><valuetype="string"key="command">builtin:query.execute_current_statement</value><valuetype="string"key="itemType">action</value><valuetype="string"key="shortcut">F5</value><valuetype="string"key="platform">windows</value></value>
Troubleshooting
Forgot Password
mysql 5.7 Ubuntu 64
1
2
3
4
5
sudo service mysql status
sudo service mysql stop
mkdir-p /var/run/mysqld
chown mysql:mysql /var/run/mysqld
sudo mysqld_safe --skip-grant-tables--skip-networking &
Alibaba Cloud’s RDS, when the disk is full, will show --rds-read-drop-only status. At this time, you can only read data or delete the database (after all, upgrading the disk requires a restart).
The fastest solution at this time is to delete the database.
Second best, transfer the database, then delete it.
Or optimize the data table structure during business low periods
この操作に対応する時点t2を記録
BEGIN;
DELETE FROM B WHERE updated_time > t1;
INSERT INTO B(field1, field2) SELECT field1, field2 FROM A WHERE updated_time >t1;
COMMIT;
BEGIN;
DELETE FROM B WHERE updated_time > t2;
INSERT INTO B(field1, field2) SELECT field1, field2 FROM A WHERE updated_time >t2;
ALTER TABLE A RENAME TO C;
ALTER TABLE B RENAME TO A;
COMMIT;
MySQL Workbench
whereなしでupdateを許可
1
SET SQL_SAFE_UPDATES = 0;
クライアントのヒント
1
2
3
4
Error Code: 2013. Lost connection to MySQL server during query
Error Code: 2006. MySQL server has gone away
Edit -> Preferences -> SQL Editorに移動し、このパラメータをより高い値に設定します:DBMS connection read time out(秒単位)。例:86400。
<valuetype="object"struct-name="app.MenuItem"id="com.mysql.wb.menu.query.execute_current_statementwin"><linktype="object"key="owner"struct-name="app.MenuItem">com.mysql.wb.menu.query</link><valuetype="string"key="caption">Execute Current Statement</value><valuetype="string"key="name">query.execute_current_statement</value><valuetype="string"key="command">builtin:query.execute_current_statement</value><valuetype="string"key="itemType">action</value><valuetype="string"key="shortcut">F5</value><valuetype="string"key="platform">windows</value></value>
トラブルシューティング
パスワードを忘れた
mysql 5.7 Ubuntu 64
1
2
3
4
5
sudo service mysql status
sudo service mysql stop
mkdir-p /var/run/mysqld
chown mysql:mysql /var/run/mysqld
sudo mysqld_safe --skip-grant-tables--skip-networking &
Сначала запустите, чтобы увидеть, действительно ли это медленно, обратите внимание на установку SQL_NO_CACHE
Запрос к одной таблице с условиями where, заблокируйте таблицу с минимальным количеством возвращённых записей. Это означает применение всех предложений where из запроса, начиная с таблицы с наименьшим количеством возвращённых записей, отдельный запрос каждого поля одной таблицы, чтобы увидеть, какое поле имеет наивысшую различимость
Используйте explain для просмотра плана выполнения, соответствует ли он ожиданию 1 (запрос, начинающийся с таблицы с меньшим количеством заблокированных записей)
Для SQL-запросов в форме order by limit дайте приоритет запросу отсортированной таблицы
Поймите сценарий использования бизнеса
При добавлении индексов обращайтесь к основным принципам создания индексов
Наблюдайте результаты, если не соответствует ожиданиям, продолжайте анализ с 0
Советы по запросам MySQL
Анализ запросов
1
explainselectsleep(1);
explain может анализировать производительность запроса
sleep секунд
Присвоение переменных
1
2
set @current =0;
select @current :=@current +1;
В запросах вы можете переназначить переменные, используя :=
vi /etc/mysql/my.cnf
```
[mysqld]
bind-address = 0.0.0.0
```
Изменение больших таблиц данных
Таблица для изменения Table A нуждается в поле, которое записывает временные метки. Эта временная метка — это поле, которое обновляется каждый раз при обновлении данных. Это поле нуждается в индексе. В django вы можете использовать auto_now=True
Создайте новую временную таблицу Table B, не tmp_table, а новую таблицу, которая временно используется. Эта таблица имеет точно такую же структуру данных, как таблица для изменения, плюс части, которые вы хотите изменить, такие как добавленные поля;
Запишите индексы Table A
Удалите все индексы из Table B
Скопируйте все данные из Table A в Table B. Должны ли мы выполнить INSERT INTO B(field1, field2) SELECT field1, field2 FROM A? Конечно нет, разве это не заблокирует Table A? Миграция здесь — это место, которое требует подразделения. Напишите скрипт, чтобы программа читала, скажем, 5000 записей за раз, и вставляла их в Table B. Поскольку Table B не имеет индексов, будьте осторожны, чтобы не использовать многопроцессорность; если многопроцессорность, убедитесь, что нет дублирующихся данных при вставке в B; если это 10 миллионов записей, 5000 за раз, предполагая, что эта операция занимает 500ms, то 2000*200ms = 16 минут. Это всего лишь оценка, конкретные ситуации зависят от состояния сервера в то время, трудно детализировать. Кроме того, нам нужно записать момент времени, когда начинается эта миграция, обозначенный как t1;
Постройте индексы для B, подождите, пока все индексы будут готовы, затем продолжите с 6
Итак, в этот момент, все ли данные Table A вошли в Table B? Следует сказать, что большая часть вошла, но, как упоминалось в 5, это занимает около 16 минут. За такое долгое время могли войти новые данные, или существующие данные могли быть обновлены. Поэтому нам нужно найти данные в Table A, которые изменились после t1, а затем обновить их в Table B. Наш подход:
1
2
3
4
5
Запишите момент времени, соответствующий этой операции t2
BEGIN;
DELETE FROM B WHERE updated_time > t1;
INSERT INTO B(field1, field2) SELECT field1, field2 FROM A WHERE updated_time >t1;
COMMIT;
Теперь A и B должны быть почти синхронизированы, верно? Почти, но после выполнения 6, A всё ещё пишет, потомки бесконечны… Но в этот момент разница между A и B очень, очень мала. Итак, на следующем шаге мы выполняем следующие операции в транзакции:
1
2
3
4
5
6
7
BEGIN;
DELETE FROM B WHERE updated_time > t2;
INSERT INTO B(field1, field2) SELECT field1, field2 FROM A WHERE updated_time >t2;
ALTER TABLE A RENAME TO C;
ALTER TABLE B RENAME TO A;
COMMIT;
MySQL Workbench
Разрешить обновление без where
1
SET SQL_SAFE_UPDATES = 0;
Советы клиента
1
2
3
4
Error Code: 2013. Lost connection to MySQL server during query
Error Code: 2006. MySQL server has gone away
Перейдите в Edit -> Preferences -> SQL Editor и установите более высокое значение для этого параметра: DBMS connection read time out (в секундах). Например: 86400.
Изменить на F5 Выполнить текущий выбранный оператор
Метод: Измените содержимое в C:\Program Files\MySQL\MySQL Workbench 6.3 CE\data\main_menu.xml
1
2
3
4
5
6
7
8
9
10
<valuetype="object"struct-name="app.MenuItem"id="com.mysql.wb.menu.query.execute_current_statementwin"><linktype="object"key="owner"struct-name="app.MenuItem">com.mysql.wb.menu.query</link><valuetype="string"key="caption">Execute Current Statement</value><valuetype="string"key="name">query.execute_current_statement</value><valuetype="string"key="command">builtin:query.execute_current_statement</value><valuetype="string"key="itemType">action</value><valuetype="string"key="shortcut">F5</value><valuetype="string"key="platform">windows</value></value>
Устранение неполадок
Забыли пароль
mysql 5.7 Ubuntu 64
1
2
3
4
5
sudo service mysql status
sudo service mysql stop
mkdir-p /var/run/mysqld
chown mysql:mysql /var/run/mysqld
sudo mysqld_safe --skip-grant-tables--skip-networking &
RDS Alibaba Cloud, когда диск заполнен, будет показывать статус --rds-read-drop-only. В это время вы можете только читать данные или удалить базу данных (в конце концов, обновление диска требует перезапуска).
Самое быстрое решение в это время — удалить базу данных.
Второй вариант — перенести базу данных, затем удалить её.
Или оптимизировать структуру таблицы данных в периоды низкой нагрузки бизнеса