Mysql

MySQL導入innodb數據庫時記憶體不足

  • April 3, 2019

我有一個 512MB RAM 的小型 VPS,沒有交換(不能有任何交換)。

我正在導入一個 1.5GB 的 innodb 數據庫

mysql -u -p < 數據庫.sql

在操作完成之前,它會說:失去與 MySQL 伺服器的連接。那是因為 mysqld 在試圖獲得超過 480MB 的 RAM 時崩潰了。

這是我的 my.cnf

[client]
port            = 3306
socket          = /var/run/mysqld/mysqld.sock

[mysqld_safe]
socket          = /var/run/mysqld/mysqld.sock
nice            = 0

[mysqld]
#
# * Basic Settings
#
user            = mysql
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
port            = 3306
basedir         = /usr
datadir         = /var/lib/mysql
tmpdir          = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address            = 127.0.0.1
#
# * Fine Tuning
#
key_buffer              = 16M
max_allowed_packet      = 16M
thread_stack            = 192K
thread_cache_size       = 8
# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched
myisam-recover         = BACKUP
max_connections        = 4
#table_cache            = 64
#thread_concurrency     = 10
#
# * Query Cache Configuration
#
query_cache_limit       = 1M
query_cache_size        = 16M
#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
# As of 5.1 you can enable the log at runtime!
#general_log_file        = /var/log/mysql/mysql.log
#general_log             = 1
#
# Error log - should be very few entries.
#
log_error = /var/log/mysql/error.log
#
# Here you can see queries with especially long duration
#log_slow_queries       = /var/log/mysql/mysql-slow.log
#long_query_time = 2
#log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
#       other settings you may need to change.
#server-id              = 1
#log_bin                        = /var/log/mysql/mysql-bin.log
expire_logs_days        = 10
max_binlog_size         = 100M
#binlog_do_db           = include_database_name
#binlog_ignore_db       = include_database_name
#
# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
#
innodb_buffer_pool_size=80M
innodb_additional_mem_pool_size=20M

innodb_flush_log_at_trx_commit=0
innodb_log_buffer_size = 8M

[mysqldump]
quick
quote-names
max_allowed_packet      = 16M

[mysql]
#no-auto-rehash # faster start of mysql but no tab completition

[isamchk]
key_buffer              = 16M

更多資訊:

  • 有很多表:30k 表

  • 我在 ubuntu 12.04 上執行 mysql 5.5

  • 我已經閱讀了很多關於 mysql innodb 記憶體使用的資料…我一定遺漏了一些東西,因為他們提供的公式不是在職的

這個腳本

mysql -u admin -p -e "show variables; show status" | awk '
{
VAR[$1]=$2
}
END {
MAX_CONN = VAR["max_connections"]
MAX_USED_CONN = VAR["Max_used_connections"]
BASE_MEM=VAR["key_buffer_size"] + VAR["query_cache_size"] + VAR["innodb_buffer_pool_size"] + VAR["innodb_additional_mem_pool_size"] + VAR["innodb_log_buffer_size"]
MEM_PER_CONN=VAR["read_buffer_size"] + VAR["read_rnd_buffer_size"] + VAR["sort_buffer_size"] + VAR["join_buffer_size"] + VAR["binlog_cache_size"] + VAR["thread_stack"] + VAR["tmp_table_size"]
MEM_TOTAL_MIN=BASE_MEM + MEM_PER_CONN*MAX_USED_CONN
MEM_TOTAL_MAX=BASE_MEM + MEM_PER_CONN*MAX_CONN

printf "+------------------------------------------+--------------------+\n"
printf "| %40s | %15.3f MB |\n", "key_buffer_size", VAR["key_buffer_size"]/1048576
printf "| %40s | %15.3f MB |\n", "query_cache_size", VAR["query_cache_size"]/1048576
printf "| %40s | %15.3f MB |\n", "innodb_buffer_pool_size", VAR["innodb_buffer_pool_size"]/1048576
printf "| %40s | %15.3f MB |\n", "innodb_additional_mem_pool_size", VAR["innodb_additional_mem_pool_size"]/1048576
printf "| %40s | %15.3f MB |\n", "innodb_log_buffer_size", VAR["innodb_log_buffer_size"]/1048576
printf "+------------------------------------------+--------------------+\n"
printf "| %40s | %15.3f MB |\n", "BASE MEMORY", BASE_MEM/1048576
printf "+------------------------------------------+--------------------+\n"
printf "| %40s | %15.3f MB |\n", "sort_buffer_size", VAR["sort_buffer_size"]/1048576
printf "| %40s | %15.3f MB |\n", "read_buffer_size", VAR["read_buffer_size"]/1048576
printf "| %40s | %15.3f MB |\n", "read_rnd_buffer_size", VAR["read_rnd_buffer_size"]/1048576
printf "| %40s | %15.3f MB |\n", "join_buffer_size", VAR["join_buffer_size"]/1048576
printf "| %40s | %15.3f MB |\n", "thread_stack", VAR["thread_stack"]/1048576
printf "| %40s | %15.3f MB |\n", "binlog_cache_size", VAR["binlog_cache_size"]/1048576
printf "| %40s | %15.3f MB |\n", "tmp_table_size", VAR["tmp_table_size"]/1048576
printf "+------------------------------------------+--------------------+\n"
printf "| %40s | %15.3f MB |\n", "MEMORY PER CONNECTION", MEM_PER_CONN/1048576
printf "+------------------------------------------+--------------------+\n"
printf "| %40s | %18d |\n", "Max_used_connections", MAX_USED_CONN
printf "| %40s | %18d |\n", "max_connections", MAX_CONN
printf "+------------------------------------------+--------------------+\n"
printf "| %40s | %15.3f MB |\n", "TOTAL (MIN)", MEM_TOTAL_MIN/1048576
printf "| %40s | %15.3f MB |\n", "TOTAL (MAX)", MEM_TOTAL_MAX/1048576
printf "+------------------------------------------+--------------------+\n"
}'

這是輸出

+------------------------------------------+--------------------+
|                          key_buffer_size |          16.000 MB |
|                         query_cache_size |          16.000 MB |
|                  innodb_buffer_pool_size |          80.000 MB |
|          innodb_additional_mem_pool_size |          20.000 MB |
|                   innodb_log_buffer_size |           8.000 MB |
+------------------------------------------+--------------------+
|                              BASE MEMORY |         140.000 MB |
+------------------------------------------+--------------------+
|                         sort_buffer_size |           2.000 MB |
|                         read_buffer_size |           0.125 MB |
|                     read_rnd_buffer_size |           0.250 MB |
|                         join_buffer_size |           0.125 MB |
|                             thread_stack |           0.188 MB |
|                        binlog_cache_size |           0.031 MB |
|                           tmp_table_size |          16.000 MB |
+------------------------------------------+--------------------+
|                    MEMORY PER CONNECTION |          18.719 MB |
+------------------------------------------+--------------------+
|                     Max_used_connections |                  1 |
|                          max_connections |                  4 |
+------------------------------------------+--------------------+
|                              TOTAL (MIN) |         158.719 MB |
|                              TOTAL (MAX) |         214.875 MB |
+------------------------------------------+--------------------+

但是在頂部,我可以看到 mysqld 記憶體使用量達到 481m,然後 mysql 崩潰。

我缺少什麼配置來限制記憶體使用?!謝謝

解決方法

BigDump http://www.ozerov.de/bigdump/

它只執行大轉儲的一小部分並自行重新啟動。下一個會話從上次停止的地方開始,以防止您遇到伺服器的限制。BigDump 網站上提供了使用說明。基本上,您將 SQL 文件與 bigdump.php 文件一起放在伺服器上的文件夾中。您使用數據庫資訊編輯該文件,然後訪問伺服器上的頁面並將導入設置為進行。這是一個相當快的過程,可以為您節省大量時間。

SQLDumpSpliter http://www.rusiczki.net/2007/01/24/sql-dump-file-splitter/

創建拆分,然後將它們上傳到伺服器上的目錄。

如果要恢復轉儲,必須先執行 yourdatabase_DataStructure.sql,因為它包含 Tables 結構。之後,您可以執行其他 .sql 文件,因為它們包含現有表的數據。再次使用 SSH,CD 到您的目錄,並確保首先發送:

mysql -u db_user -p db_name &lt; yourbackup_DataStructure.sql

然後你的分裂:

mysql -u db_user -p db_name &lt; yourbackup_1.sql
mysql -u db_user -p db_name &lt; yourbackup_2.sql

資料來源:http ://www.ontwerps.nl/methods-importing-large-sql-files

我認為 Rick James 是在正確的軌道上,許多 30k 表句柄正在干擾記憶體。

在 MySQL 5.5 中,InnoDB 使用系統表空間,它將所有表數據放在單個 OS 文件中。這意味著單個內部表數據分配以及句柄管理髮生在 MySQL 內部(也就是說,完全在 RAM 中,因為您沒有交換空間),沒有主機作業系統(Ubuntu 12)的幫助。

我會嘗試啟用innodb_file_per_table

https://dev.mysql.com/doc/refman/5.5/en/tablespace-enabling.html

innodb_file_per_table 選項從 MySQL 5.6.6 開始預設啟用,因此您必須在 5.5 伺服器上啟用它:

[mysqld]
innodb_file_per_table
...

(請注意,設置沒有給出值,鍵的存在啟用了該功能)

這允許 MySQL InnoDB 使用更多的作業系統和磁碟資源進行表管理,有望減少堆使用和記憶體管理抖動。

您可能希望從全新安裝開始(沒有預先存在的表數據),或者至少關閉 MySQL 並刪除 datadir 中的 ibdata* 和 ib_log* 文件,因為 MySQL 不會將現有表轉換為每個文件格式。MySQL 將在啟動時重建失去的 ib* 文件,預計會看到相關的錯誤消息。

使用innodb_file_per_table,MySQL 將單獨的表文件(.fmt 和 .ibd)儲存在 datadir 的子目錄中,其中每個目錄是一個 mysql table_schema。如果您將所有 30k 表放入一個模式/文件夾中,您可能會在作業系統級別遇到同樣的問題,因為 Ubuntu 會嘗試將整個目錄索引載入到記憶體中。如果可能的話,將你的表組織成幾個單獨的模式/文件夾,我會盡量保持每個模式的表數不超過 1000。

引用自:https://dba.stackexchange.com/questions/60888