优化MySQL并行导入海量数据文件。每表1个连接

时间:2011-03-15 13:25:44

标签: mysql import parallel-processing

我正在为大型网站迁移做一些准备工作。

数据库大小约为10GB,有几个表包含> 1500万条记录。不幸的是,由于我的职权范围之外的客户关系,这只出现在SQL格式的大型单个mysqldump文件中,但是你知道这是怎么回事。我的目标是最大限度地减少停机时间,从而尽可能快地导入数据。

我试图使用标准的MySQL CLI界面,如下所示:

$mysql database_name < superhuge_sql_file -u username -p
然而,这是超级慢的。

为了尝试加快速度,我已经使用awk将文件拆分为包含相关数据的每个表的块,并构建了一个小的shell脚本来尝试并行导入表,就像这样;

#!/bin/sh

awk '/DROP TABLE/{f=0 ;n++; print >(file="out_" n); close("out_" n-1)} f{ print > file}; /DROP TABLE/{f=1}'  superhuge.sql

for (( i = 1; i <= 95; i++ )) 
do
    mysql -u admin --password=thepassword database_name < /path/to/out_$i &
done

值得一提的是,这是一个“使用一次并销毁”脚本(脚本中的密码等)。

现在,这可行,但目前在四核服务器上完成其他任何事情仍需要3个多小时才能完成。这些表确实并行导入,但不能同时导入所有这些表,并且在此过程中尝试通过CLI获取MySQL服务器信息非常慢。我不确定为什么但是在尝试使用相同的mysql用户帐户访问表时会挂起。 max_user_connections无限制。

我已在my.cnf中将max connections设置为500,但在此服务器上没有配置MySQL。

我有一个很好的搜索但是想知道是否有任何MySQL配置选项可以帮助加快这个过程,或者我错过的任何其他方法会更快。

3 个答案:

答案 0 :(得分:4)

如果您可以考虑使用GNU parallel,请查看wardbekker gist:上的此示例

# Split MYSQL dump file
zcat dump.sql.gz | awk '/DROP TABLE IF EXISTS/{n++}{print >"out" n ".sql" }'
# Parallel import using GNU Parallel http://www.gnu.org/software/parallel/
ls -rS *.sql | parallel --joblog joblog.txt mysql -uXXX -pYYY db_name "<"

将大文件拆分为单独的SQL文件,然后运行parallel进行并行处理。

因此,要在GNU parallel中运行10个线程,您可以运行:

ls -rS data.*.sql | parallel -j10 --joblog joblog.txt mysql -uuser -ppass dbname "<"

在OS X上,它可以是:

gunzip -c wiebetaaltwat_stable.sql.gz | awk '/DROP TABLE IF EXISTS/{n++}{filename = "out" n ".sql"; print > filename}'

来源:wardbekker/gist:964146

相关:Unix.SE上的Import sql files using xargs

答案 1 :(得分:0)

将转储文件导入服务器

$ sudo apt-get install pigz pv
$ zcat /path/to/folder/<dbname>_`date +\%Y\%m\%d_\%H\%M`.sql.gz | pv | mysql --user=<yourdbuser> --password=<yourdbpassword> --database=<yournewdatabasename> --compress --reconnect --unbuffered --net_buffer_length=1048576 --max_allowed_packet=1073741824 --connect_timeout=36000 --line-numbers --wait --init-command="SET GLOBAL net_buffer_length=1048576;SET GLOBAL max_allowed_packet=1073741824;SET FOREIGN_KEY_CHECKS=0;SET UNIQUE_CHECKS = 0;SET AUTOCOMMIT = 1;FLUSH NO_WRITE_TO_BINLOG QUERY CACHE, STATUS, SLOW LOGS, GENERAL LOGS, ERROR LOGS, ENGINE LOGS, BINARY LOGS, LOGS;"

可选:用于连接的命令参数

--host=127.0.0.1 / localhost / IP Address of the Import Server
--port=3306

可选软件包有助于更快地导入数据库SQL文件

with a progress view (pv)
Parallel gzip (pigz/unpigz) to gzip/gunzip files in parallel

更快地压缩输出

或者,您确实有一系列

的MySQL选项。

导出

https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html

导入

https://dev.mysql.com/doc/refman/5.7/en/mysql-command-options.html

配置

https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html

这是我的服务器SSD四核上运行的示例my.cnf,通常会在8小时内导入100GB的DB文件。但是您可以调整服务器的设置,以帮助其更快地编写。

使用上面的链接检查每个配置变量,以将您的MySQL Server与变量和值进行匹配。

# Edit values to as per your Server Processor and Memory requirements.
[mysqld]
# Defaults
pid-file = /var/run/mysqld/mysqld.pid
socket   = /var/run/mysqld/mysqld.sock
log-error = /var/log/mysql/error.log
datadir = /var/lib/mysql
log_timestamps = SYSTEM
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci

# InnoDB
innodb_buffer_pool_size = 48G
innodb_buffer_pool_instances = 48
innodb_log_file_size = 3G
innodb_log_files_in_group = 4
innodb_log_buffer_size = 256M
innodb_log_compressed_pages = OFF
innodb_large_prefix = ON
innodb_file_per_table = true
innodb_buffer_pool_load_at_startup = ON
innodb_buffer_pool_dump_at_shutdown = ON
innodb_autoinc_lock_mode = 2
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 360
innodb_flush_neighbors = 0
innodb_flush_method = O_DIRECT
innodb_io_capacity = 2500
innodb_io_capacity_max = 5000
innodb_read_io_threads = 64
innodb_write_io_threads = 64
innodb_monitor_enable = all
performance_schema = ON

key_buffer_size = 32M
wait_timeout = 30
interactive_timeout = 3600
max_connections = 1000
table_open_cache = 5000
open_files_limit = 8000
tmp_table_size = 32M
max_heap_table_size = 64M

# Slow/Error
log_output = file
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow_query.log
long_query_time = 10
log_queries_not_using_indexes = ON
log_slow_rate_limit = 100
log_slow_rate_type = query
log_slow_verbosity = full
log_slow_admin_statements = ON
log_slow_slave_statements = ON
slow_query_log_always_write_time = 1
slow_query_log_use_global_control = all

# Query
join_buffer_size = 32M
sort_buffer_size = 16M
read_rnd_buffer_size = 8M
query_cache_limit = 8M
query_cache_size = 8M
query_cache_type = 1

# TCP
max_allowed_packet = 1G

答案 2 :(得分:-1)

转储中的sql是否插入了多行?转储是否使用多行插入? (或者你可以预先处理它?)

This guy涵盖了很多基础知识,例如:

  • 禁用使导入速度提高许多倍的索引。
  • 禁用MySQL索引,因此在导入运行之前:

    ALTER TABLE `table_name` DISABLE KEYS;
    

    然后在导入后将其更改回来:

    ALTER TABLE `table_name` DISABLE KEYS;
    
  • 使用MyISAM表类型时,请使用MySQL的INSERT DELAYED命令,这样可以鼓励MySQL在数据库空闲时将数据写入磁盘。

  • 对于InnoDB表,请使用这些额外命令以避免大量磁盘访问:

    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    

    最后这些:

    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;