我有(我会考虑的)大量纯文本文件,大约 400GB,它们被导入 MySQL 数据库(InnoDB 引擎)。.txt 文件大小从 2GB 到 26GB 不等,每个文件代表数据库中的一个表。我得到了一个解析 .txt 文件并构建 SQL 语句的 Python 脚本。我有一台专门用于此任务的机器,具有以下规格:
- 操作系统 - Windows 10
- 32GB 内存
- 4TB硬盘
- i7 3.40 GHz 处理器
我想优化此导入,使其尽可能快速和肮脏。我已根据堆栈 O 问题、MySQL 文档和其他来源更改了 MySQL my.ini 文件中的以下配置设置:
max_allowed_packet=1073741824;
autocommit=0;
net_buffer_length=0;
foreign_key_check=0;
unique_checks=0;
innodb_buffer_pool_size=8G; (this made a big difference in speed when I increased from the default of 128M)
我错过了配置文件中的其他设置(可能是日志记录或缓存),这些设置会指导 MySQL 使用机器资源的很大一部分?我会错过另一个瓶颈吗?
(旁注:不确定这是否相关 - 当我开始导入时,该mysqld
过程会加速使用大约 13-15% 的系统内存,但是当我停止 Python 脚本继续导入时,它似乎永远不会清除它。我想知道这是否是由于弄乱了日志记录和刷新设置。提前感谢您的帮助。)
(编辑)
这是填充表格的 Python 脚本的相关部分。似乎脚本正在为每 50,000 条记录连接、提交和关闭连接。我可以删除conn.commit()
函数末尾的 并让 MySQL 处理提交吗?下面的评论while (true)
来自脚本的作者,我已经调整了这个数字,使其不会超过 max_allowed_packet 大小。
conn = self.connect()
while (True):
#By default, we concatenate 200 inserts into a single INSERT statement.
#a large batch size per insert improves performance, until you start hitting max_packet_size issues.
#If you increase MySQL server's max_packet_size, you may get increased performance by increasing maxNum
records = self.parser.nextRecords(maxNum=50000)
if (not records):
break
escapedRecords = self._escapeRecords(records) #This will sanitize the records
stringList = ["(%s)" % (", ".join(aRecord)) for aRecord in escapedRecords]
cur = conn.cursor()
colVals = unicode(", ".join(stringList), 'utf-8')
exStr = exStrTemplate % (commandString, ignoreString, tableName, colNamesStr, colVals)
#unquote NULLs
exStr = exStr.replace("'NULL'", "NULL")
exStr = exStr.replace("'null'", "NULL")
try:
cur.execute(exStr)
except MySQLdb.Warning, e:
LOGGER.warning(str(e))
except MySQLdb.IntegrityError, e:
#This is likely a primary key constraint violation; should only be hit if skipKeyViolators is False
LOGGER.error("Error %d: %s", e.args[0], e.args[1])
self.lastRecordIngested = self.parser.latestRecordNum
recCheck = self._checkProgress()
if recCheck:
LOGGER.info("...at record %i...", recCheck)
conn.commit()
conn.close()