【问题标题】:Finding right configuration for a dedicated mariadb server - for huge innodb tables为专用的 mariadb 服务器寻找正确的配置 - 用于巨大的 innodb 表
【发布时间】:2018-08-12 04:34:14
【问题描述】:

我一直在使用单独的服务器来配置 mariadb,但查询仍然需要很长时间才能返回,而且大部分都没有返回。

Mariadb 版本:10.1.31-1 服务器有 50GB 内存和 2200 Ghz * 10 核 Centos7 作为 OP

目标数据库当前有非常大的 innodb 表并且没有很好的索引。没有任何其他表类型,只有 innodb。

目前我正在做一些嵌套的选择查询并将结果保存到另一个空的克隆数据库中插入或替换到。

举个例子:

REPLACE INTO db1.table1
SELECT * FROM db0.table1 WHERE ART_ID IN (
    SELECT ART_ID FROM db0.table2 WHERE BRA_ID IN (
        SELECT BRA_ID FROM db0.table3 WHERE BRAND IN (
            SELECT BRAND FROM db0.table4 WHERE ID IN (... bunch of comma seperated ids)
        )
    )
);

唯一的连接来自本地和/或只有一个远程连接。 服务器的唯一任务是将大量数据过滤到另一个数据库,没有网络服务器等。

我把 /etc/my.cnf 文件放在下面。我对这个文件做了很多测试,所以你可能会看到一些无用的添加。

问题是:cnf文件中是否有遗漏配置;是否有任何其他配置提示等可以在合理的时间内运行这些查询。

它工作得更好,但是在我更改配置或/并更新服务器之后,一切都变得慢了很多。 (是的,我在更新数据库版本后也更新了表格)

# The MySQL server
[mysqld]
performance_schema=0
bind-address = 0.0.0.0
max_connections = 32
socket      = /var/lib/mysql/mysql.sock
skip-external-locking
max_allowed_packet = 1024M

connect_timeout=300
wait_timeout=1200
interactive_timeout=300

key_buffer_size = 2G
bulk_insert_buffer_size=256M
sort_buffer_size = 32M
#read_buffer_size = 8M
#read_rnd_buffer_size = 32M
myisam_sort_buffer_size = 32M
join_buffer_size=32M
#max_heap_table_size= 8G
tmp_table_size=8G
concurrent_insert=2
#external-locking=FALSE
#open_files_limit=50000

default-storage-engine=innodb
innodb_file_per_table=1

#lower_case_table_names=1

# Try number of CPU's*2 for thread_concurrency
innodb_write_io_threads=10
innodb_read_io_threads=20
#innodb_buffer_pool_instances=8
#thread_stack = 1M
#thread_cache_size = -1

innodb_buffer_pool_size = 16G

#query_cache_limit = 1073741824
#query_cache_size = 1073741824
#query_cache_type = 1

query_cache_size=0
query_cache_type=0

#innodb_additional_mem_pool_size = 20M
# Set .._log_file_size to 25 % of buffer pool size

innodb_fast_shutdown=0

#innodb_log_file_size = 1G
#innodb_log_buffer_size = 8M
#innodb_flush_log_at_trx_commit = 1
#innodb_lock_wait_timeout = 0
innodb_lock_wait_timeout = 1073741823
innodb_thread_concurrency=0
innodb_commit_concurrency=0
innodb_flush_method=O_DSYNC
innodb_log_compressed_pages = 0
#innodb_flush_neighbors = 0
#innodb_adaptive_hash_index_partitions = 8


log-bin=mysql-bin
server-id   = 1

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash

[isamchk]
key_buffer = 384M
sort_buffer = 384M
read_buffer = 256M
write_buffer = 256M

[myisamchk]
key_buffer = 384M
sort_buffer = 384M
read_buffer = 256M
write_buffer = 256M

[mysqlhotcopy]
interactive-timeout

我使用了 percona 向导并合并了建议。 当前的 my.cnf 在下面。

我昨天晚上(2018-03-05 22:41:30 UTC)运行了 php 应用程序,但 mysql 仍然无法返回任何结果。

应用程序仅添加限制 10000 和偏移量(我不想从头开始,我目前正在跟踪最后一个偏移量并从该点开始。)

目前我正计划删除并重新安装 mariadb :( (会是情绪反应)

# Generated by Percona Configuration Wizard (http://tools.percona.com/) version REL5-20120208

[mysql]

# CLIENT #
port                           = 9999
socket                         = /var/lib/mysql/mysql.sock

[mysqld]

# GENERAL #
port                           = 9999
user                           = mysql
default-storage-engine         = InnoDB
socket                         = /var/lib/mysql/mysql.sock
pid-file                       = /var/lib/mysql/mysql.pid

# MyISAM # - there is no myisam table
key-buffer-size                = 32M
myisam-recover-options         = FORCE,BACKUP

# SAFETY #
max-allowed-packet             = 16M
max-connect-errors             = 1000000
skip-name-resolve

# DATA STORAGE #
datadir                        = /var/lib/mysql/

# BINARY LOGGING #
log-bin                        = /var/lib/mysql/mysql-bin
expire-logs-days               = 14
sync-binlog                    = 1

# CACHES AND LIMITS #
tmp-table-size                 = 32M
max-heap-table-size            = 32M
query-cache-type               = 0
query-cache-size               = 0
max-connections                = 30
#thread-cache-size              = 16
open-files-limit               = 65535
table-definition-cache         = 1024
table-open-cache               = 2048

# INNODB #
innodb-flush-method            = O_DIRECT
innodb-log-files-in-group      = 2
innodb-log-file-size           = 5G
innodb-flush-log-at-trx-commit = 1
innodb-file-per-table          = 1
innodb-buffer-pool-size        = 42G
innodb-buffer-pool-instances   = 42


thread_cache_size=100
innodb_lru_scan_depth=100
innodb_purge_threads=4
innodb_read_io_threads=64
innodb_write_io_threads=64
innodb_thread_concurrency=0
max_seeks_for_key=32
max_write_lock_count=16
thread_concurrency=35

innodb_fast_shutdown=0
innodb_file_per_table=1
default-storage-engine=innodb
concurrent_insert=2
join_buffer_size=32M
tmp_table_size=8G
read_buffer_size = 8M

# LOGGING #
log-error                      = /var/lib/mysql/mysql-error.log
log-queries-not-using-indexes  = 0
slow-query-log                 = 1
slow-query-log-file            = /var/lib/mysql/mysql-slow.log

【问题讨论】:

标签: mysql optimization mariadb centos7 configure


【解决方案1】:

使用 2018 年 3 月 15 日发布的数据为您的 my.cnf-ini [mysqld] 部分提供建议

thread_cahce_size=40  # from 20, 8 required for overhead, room to wiggle
innodb_io_capacity=400  # from 200   new iostat -x will confirm use
# read_buffer_size=8388608  # lead with # for default of 128K - extreme at 8M
read_rnd_buffer_size=128K  # from 256K will affect handler_read_rnd_next 
sync_binlog=32  # from 1 sec frequency, unless you fear recovery required
# join_buffer_size=4M  # lead with # for default of 128K
key_buffer_size=1M  # from 32M less than 1M used - primarily Innodb tables
innodb_adapative_max_sleep_delay=15  # from 150000 (15 secs - n0 other users)
innodb_buffer_pool_instances=8  # from 42 to minimize mgmt. overhead
innodb_buffer_pool_size=40G  # from 44G allow OS a little breathing room
innodb_change_buffer_max_size=3  # from 25% - no need to set aside 10G when not changing anything significant
innodb_doublewrite=OFF  # from ON you are not a PROD effort - crash recovery NA for run of this instance
innodb_print_all_deadlocks=ON  # from OFF you always need in error log
innodb_read_ahead_threshold=8  # from 56, why wait to read NXT extent?
innodb_stats_sample_pages=32  # from 8 for more accurate index cardinality 
log_warnings=2  # from 1 to record addl connection error details
max_join_size=1000000000  # from more huge number to 1B rows max for join
sql_select_limit=1000000000  # from more huge number to 1B rows selected
query_alloc_block_size=32K  # from 16K - minimize RAM alloc AvgQrySz 20K
query_cache_type=0  # for OFF, not used
query_cache_size=0  # from 8M  not needed for one time selections
query_cache_limit=1K  # from 256K, just to keep the framework, in case QC needed
query_cache_min_res_unit=512  # from 2K for optimal QC storage when QC used
query_prealloc_size=32K  # from 24K to minimize RAM alloc for parsing 
transaction_alloc_block_size=32K  # from 8K to minimize RAM alloc
transaction_prealloc_size=32K  # from 4K to minimize RAM alloc
updatable_views_with_limit=NO  # from YES to reduce handler_external_lock count

这个可能不得不回到 YES - 它是动态变量

请找到您的一个 com_stmt_prepare 代码并确保它在离开会话之前已关闭,以便根据 refman PREPARE 或 mysql_stmt_prepare for API 释放资源。

运行后,在运行有问题的查询之前,请考虑使用 ALTER TABLE tbl_name 引擎=INNODB 让每个表利用额外的页面来获得更好的基数, 然后尝试您的长时间运行的查询。

【讨论】:

  • 谢谢;我得到了 innodb_adapative_max_sleep_delay、sql_select_limit 的错误,但是用这些进行了测试。
  • @erce 把它们排除在外,这样您就可以继续进行时序测试。我仍然认为要匹配的一长串数字需要另一种技术。将在下周之前我有替代或更长时间。
  • @erce 在 EXPLAIN 中避免二进制嵌套循环,请检查此链接以获取替代方法,使用临时表存储您的一长串 ID 以适应 = 而不是 IN SELECT 处理。 pastebin 链接是pastebin.com/ZYYidKZK
【解决方案2】:

我想我需要更改选择查询样式,我会尝试提供的查询替代方案,因为它不起作用,查询仍然很慢(我假设)

但这些是当前服务器统计数据(49GB 内存,10 核),mysqls 虚拟内存约为 47~GB,这很好,没有任何其他应用程序正在运行。我觉得还可以吧?

tuning-primer.sh
https://pastebin.com/bcjS1PWf

mysqltuner.pl
https://pastebin.com/mXUTLPQ6

my.cnf
https://pastebin.com/9jMLzhZS

【讨论】:

  • 请使用 = 而不是 IN 发布您尝试的查询,我会查看查询,看看是否可以提供帮助。如果您将 SHOW GLOBAL VARIABLES; 的当前结果发布到 pastebin,我将能够继续对所有 GV 进行分析。
  • 要查找“连接无法正确使用索引”的查询,此组合将只为您提供这些类型的查询。 LONG_QUERY_TIME=10000000 # 不会有多少查询会运行这么长 SLOW_QUERY_LOG=1 # 从 OFF 到 ON LOG_QUERIES_NOT_USING_INDEXES=1 # 从 off 到 ON
【解决方案3】:

性能问题主要在于查询的制定,不一定在于调优或索引。

查询公式

一般情况下,将IN ( SELECT ... ) 转为JOIN

最后一步:

SELECT  bra_id
    FROM  t3
    JOIN  t4  ON  t3.brand = t4.brand
    WHERE  t4.id IN (...commalist...)

带索引:

t4: INDEX(id, brand)
t3: INDEX(brand, bra_id)

这从 t4 开始,查找各种 ID,然后将它们映射到品牌。然后按品牌进入t3获取bra_id。

我会让你通过接下来的两个步骤来练习,从 t2 到 t1。

调整建议

不要盲目的在my.cnf中增加值,会惹上麻烦的。

innodb_buffer_pool_size = 35G  -- the most important

42G 可能没问题 - 如果您没有太多其他应用程序在同一台服务器上运行。 42 实例可能有效。有人说最多 16 个实例。

其余的可调参数可能可以不用管。

max_heap_table_size= 8G
tmp_table_size=8G

这些值高得危险。有了它们,每个连接可以分配一次(或多次)8GB。但是您只有 50GB 的 RAM。最好将它们设置为不超过 RAM 的 1%(500M 或更少;32M 应该没问题)。

#lower_case_table_names=1

离开注释掉。任何覆盖操作系统所需内容的尝试都可能让您陷入困境。

port                           = 9999

默认的 3306 有什么问题?

其他

“应用程序在 6 小时内抓取了 10000 个项目。对于经过 8 小时的下一个项目块”——请提供 SHOW CREATE TABLE 以获取正在读取的 4 个表以及正在写入的表。告诉我们桌子有多大。我怀疑您正在对目标表中的索引更新感到不安。有一个简单的解决方案。

检查mysqld是否正在交换。

【讨论】:

  • 谢谢,正如我所说,这是服务器仅用于该数据库。没有安装不相关的应用程序。除了专用于按块抓取和保存的 php 应用程序。关于更改默认端口,我建议大家,在服务器获得新的 IP 地址后 5 分钟内,自动 ssh 攻击开始类似的攻击,有时会达到 3306,我不想回答它们。我的表实际上没有多少最大的表有 164M 行,最近的 2 有 75M,其余的大约有 1-5M
【解决方案4】:

@erce

这三行需要删除(就在 LOGGING 区域之前)

join_buffer_size=32M
tmp_table_size=8G
read_buffer_size = 8M

记录

tmp_table_size 早先与 max_heap_table_size 准确匹配。 这条线稍后会负责并让你失去平衡,这很糟糕。

join_buffer_size 和 read_buffer_size 正在占用您的 RAM 空间。 请使用 mysqlcalculator.com 了解原因。

【讨论】:

  • 看起来好多了,最终应用程序在 6 小时内抓取了 10000 个项目。对于下一个项目块 8 小时过去了,但还没有结果。我应该完全删除并重新安装 mariadb 吗?
  • @erce 我不会删除/替换。但这就是我。你什么时候能收到这个较早的请求?请发布您完整的慢查询日志。对于上面的查询,将第一行替换为 EXPLAIN EXTENDED SELECT 发布完整的输出。什么都不会被替换,只是寻找使用的表,行计数...... – Wilson Hauck 3 月 5 日,12:19
  • 有了 50GB 的 RAM,我认为这些设置并不坏。
【解决方案5】:

我使用了 percona 向导并合并了建议。当前的 my.cnf 在下面。

我昨天晚上(2018-03-05 22:41:30 UTC)运行了 php 应用程序,但 mysql 仍然无法返回任何结果。

应用程序仅添加限制 10000 和偏移量(我不想从头开始,我目前正在跟踪最后一个偏移量并从该点开始。)

[mysql]

# CLIENT #
port                           = 9999
socket                         = /var/lib/mysql/mysql.sock

[mysqld]

# GENERAL #
port                           = 9999
user                           = mysql
default-storage-engine         = InnoDB
socket                         = /var/lib/mysql/mysql.sock
pid-file                       = /var/lib/mysql/mysql.pid

# MyISAM # - there is no myisam table
key-buffer-size                = 32M
myisam-recover-options         = FORCE,BACKUP

# SAFETY #
max-allowed-packet             = 16M
max-connect-errors             = 1000000
skip-name-resolve

# DATA STORAGE #
datadir                        = /var/lib/mysql/

# BINARY LOGGING #
log-bin                        = /var/lib/mysql/mysql-bin
expire-logs-days               = 14
sync-binlog                    = 1

# CACHES AND LIMITS #
tmp-table-size                 = 32M
max-heap-table-size            = 32M
query-cache-type               = 0
query-cache-size               = 0
max-connections                = 30
#thread-cache-size              = 16
open-files-limit               = 65535
table-definition-cache         = 1024
table-open-cache               = 2048

# INNODB #
innodb-flush-method            = O_DIRECT
innodb-log-files-in-group      = 2
innodb-log-file-size           = 5G
innodb-flush-log-at-trx-commit = 1
innodb-file-per-table          = 1
innodb-buffer-pool-size        = 42G
innodb-buffer-pool-instances   = 42


thread_cache_size=100
innodb_lru_scan_depth=100
innodb_purge_threads=4
innodb_read_io_threads=64
innodb_write_io_threads=64
innodb_thread_concurrency=0
max_seeks_for_key=32
max_write_lock_count=16
thread_concurrency=35

innodb_fast_shutdown=0
innodb_file_per_table=1
default-storage-engine=innodb
concurrent_insert=2
join_buffer_size=32M
tmp_table_size=8G
read_buffer_size = 8M

# LOGGING #
log-error                      = /var/lib/mysql/mysql-error.log
log-queries-not-using-indexes  = 0
slow-query-log                 = 1
slow-query-log-file            = /var/lib/mysql/mysql-slow.log

【讨论】:

  • 请发布您完整的慢查询日志。对于上面的查询,将第一行替换为 EXPLAIN EXTENDED SELECT 发布完整的输出。什么都不会被替换,只是寻找 TABLES USED,row counts .....没有这个,我们只能想象请求什么。我们会错的。
  • 我做了一些小改动,这是慢日志pastebin.com/Fr9bKEJZ,这些是变量和环境细节pastebin.com/gDSUtvv4
  • 以 EJZ 结尾的 pastebin.com 似乎只是查询的解释。请发布您用于此说明的完整查询。另一方面,一切看起来都不错,除了 Mysqltuner 报告在 Performance Metrics 之前缺少第一行,请发布整个报告。感谢您与我合作。
  • 抱歉,我刚刚意识到您的连接攻击的严重性。我的第一个检查是 MAX_CONNECT_ERRORS,在将此垃圾攻击者添加到阻止列表之前,您可以容忍 100 万次。我是怎么错过的,我不知道。请将您的 ini 设置为 MAX_CONNECT_ERRORS=10,我怀疑这个问题会得到解决。关闭并重新启动后,他们将能够重试,但只能尝试 10 次。
【解决方案6】:

Question 中的 my.cnf 数据与 SHOW GLOBAL VARIABLES 不匹配;价值观。

请使用此链接
https://mariadb.com/kb/en/library/configuring-mariadb-with-mycnf/
帮助获得准确的匹配值以获得帮助。

那么,为您的 my.cnf [mysqld] 部分考虑的建议包括:

innodb_buffer_pool_size=8G  # from > 40G (95% of RAM will not work well)
innodb_lru_scan_depth=100  # from 1024  see refman every second digging too deep
log_warnings=2  # from 1 to include connection errors more detail
max_connect_errors=10  # from 1,000,000 no need to waste a million cycles
thread_cache_size=100  # from 16  CAP per V8 MySQ to be prepared for volume
have_symlink=NO  # to protect you server, unless you NEED it
innodb_purge_threads=4  # from 1  to accommodate when needed
innodb_read_io_threads=64  # from 4 see dba.stackexhange.com Q 5666 9/12/11 Rolando
innodb_write_io_threads=64  # from 4  per Rolando to use multi-core
innodb_thrad_concurrency=0  # another part of multi-core enabling
max_seeks_for_key=32  # from huge number, not found in 32, will not be found
max_write_lock_count=16  # give RD opportunity after nn locks
thread_concurrency=35  # to limit concurrent processing load

@Erce,请在正确的活动 my.cnf 中应用。撤回我重做你的 mysqld 部分的提议。

【讨论】:

  • 根据您的建议,我更改了 my.cnf,但我有一个快速的疑问 thread-cache-size 和 thread_cache_size 有什么区别?明天我会整天测试谢谢你的建议让我们看看这是否有帮助:)
  • 很可能会在几年前使用连字符来识别下划线,请查看 REFMAN 了解您的版本以获取详细信息。
猜你喜欢
  • 2021-06-02
  • 2017-08-26
  • 1970-01-01
  • 2017-10-25
  • 1970-01-01
  • 2022-11-12
  • 1970-01-01
  • 2017-09-30
  • 2018-01-20
相关资源
最近更新 更多