#### 5.6.3.4线程池调优

本节提供了有关设置线程池系统变量以获得最佳性能的指导原则，这些变量使用诸如每秒事务数之类的指标来衡量。

[`线程池大小`](server-system-variables.html#sysvar_thread_pool_size)是控制线程池性能的最重要参数。只能在服务器启动时设置。我们测试线程池的经验表明：

-   如果主存储引擎[`InnoDB`](innodb-storage-engine.html)，最佳[`线程池大小`](server-system-variables.html#sysvar_thread_pool_size)设定值可能在16到36之间，最常见的最佳值往往在24到36之间。我们没有看到任何情况下的设置是最佳的超过36。在某些特殊情况下，小于16的值可能是最佳值。

    对于DBT2和Sysbench等工作负载，最适合[`InnoDB`](innodb-storage-engine.html)似乎通常在36岁左右。对于写密集型工作负载，最佳设置有时可能更低。

-   如果主存储引擎[`米萨姆`](myisam-storage-engine.html)这个[`线程池大小`](server-system-variables.html#sysvar_thread_pool_size)设置应该相当低。最佳性能通常为4到8之间的值。较高的值往往会对性能产生轻微的负面影响，但不会产生显著的影响。

    另一个系统变量，[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)，对于处理阻塞和长时间运行的语句非常重要。如果所有阻塞MySQL服务器的调用都报告给线程池，那么它总是知道执行线程何时被阻塞。然而，这可能并不总是正确的。例如，块可能出现在未使用线程池回调检测的代码中。对于这种情况，线程池必须能够识别似乎被阻塞的线程。这是通过超时完成的，可以使用[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)系统变量，其值以10ms为单位测量。此参数确保服务器不会完全被阻止。价值[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)具有6秒的上限，以防止服务器死锁的风险。

[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)还允许线程池处理长时间运行的语句。如果允许长时间运行的语句阻止线程组，则分配给该组的所有其他连接都将被阻止，并且在长时间运行的语句完成之前无法开始执行。在最坏的情况下，这可能需要几个小时甚至几天。

价值[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)应选择执行时间超过其值的语句被视为已暂停。暂停的语句会产生大量额外的开销，因为它们涉及额外的上下文切换，在某些情况下甚至涉及额外的线程创建。另一方面，设置[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)参数太高意味着长时间运行的语句会阻塞许多短时间运行的语句，时间超过必要的时间。短等待值允许线程更快地启动。短值对于避免死锁情况也更好。长等待值对于包含长时间运行语句的工作负载很有用，以避免在当前语句执行时启动太多新语句。

假设一台服务器执行一个工作负载，其中99.9%的语句在100毫秒内完成，即使在加载服务器时也是如此，其余语句的时间在100毫秒到2小时之间，分布相当均匀。在这种情况下，设置[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)到10（10×10ms=100ms）。默认值6（60毫秒）适用于主要执行非常简单语句的服务器。

这个[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)参数可以在运行时更改，以使您能够达到适合服务器工作负载的平衡。假设[`tp_线程_组_统计数据`](performance-schema-tp-thread-group-stats-table.html)如果启用了表，则可以使用以下查询来确定暂停的已执行语句的比例：

```
SELECT SUM(STALLED_QUERIES_EXECUTED) / SUM(QUERIES_EXECUTED)
FROM performance_schema.tp_thread_group_stats;
```

这个数字应该尽可能低。要降低语句暂停的可能性，请增加[`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit).

当一条语句到达时，在它真正开始执行之前，它可以延迟的最长时间是多少？假设以下条件适用：

-   低优先级队列中有200条语句。

-   高优先级队列中有10条语句。

-   [`线程\u池\u优先级\u启动\u计时器`](server-system-variables.html#sysvar_thread_pool_prio_kickup_timer)设置为10000（10秒）。

-   [`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)设置为100（1秒）。

    在最坏的情况下，10条高优先级语句代表10个持续执行很长时间的事务。因此，在最坏的情况下，不能将任何语句移动到高优先级队列，因为它总是包含等待执行的语句。10秒后，新语句有资格移动到高优先级队列。然而，在移动它之前，它之前的所有语句也必须移动。这可能还需要2秒钟，因为每秒最多有100条语句被移动到高优先级队列。现在，当语句到达高优先级队列时，前面可能有许多长时间运行的语句。在最坏的情况下，这些语句中的每一个都会暂停，在从高优先级队列检索下一个语句之前，每个语句都需要1秒。因此，在这个场景中，新语句开始执行需要222秒。

    本例显示了应用程序的最坏情况。如何处理它取决于应用程序。如果应用程序对响应时间有很高的要求，它很可能会在更高级别上限制用户。否则，它可以使用线程池配置参数来设置某种最大等待时间。
