如何针对高负载下的性能优化 mysql 查询?
How to optimize mysql queries for performance under high load?
我对如何优化我的 SQL 查询有点困惑。我有一个中等复杂的查询,其中一些连接到 运行 每秒一百到一千次(SSD 上有两个 table,RAM 中有一个 table,4 个 JOIN)
如何最大程度地减少执行开销?有什么方法可以预编译一个查询,这样 MySQL 就不需要每次都分析、优化和编译查询了吗?
我知道我可以使用准备好的语句预编译一个查询,然后在同一会话中多次执行该查询。但是,如果您有多个会话并且每个会话只有一个查询怎么办?准备好的语句是否在不同的会话中缓存?我不这么认为。
然后我认为存储过程是最好的方法,因为据说它们是预编译的。现在我读到这个假设是完全错误的,它们实际上是 not 预编译的。
是否可以在 MySQL 中共享客户端会话,例如在后续会话继承的第一个会话中使用准备好的语句?
最后一个想法是编写一个多线程套接字服务器来充当 MySQL 客户端代理。但这对我来说似乎有点夸张。 ;-)
我使用 PHP 作为 Apache2 模块。是否有机会 "store" 共享内存中的 MySQL 会话,以便以下 HTTP 请求可以使用现有的 MySQL 会话而不是启动新会话?以便我可以在不同的 HTTP 请求中使用准备好的语句?
我想说,这样做的最佳做法之一是避免基于 O(n) 时间的查询和函数。为了能够在高负载数据下表现良好,所有的查询都必须在 O(1) 的额外时间内。这实际上意味着,无论您要获取多少数据,查询总是需要相同的时间。 (线性方程)
我的意思是,如果您将 IDS 存储在 $_SESSION
var 中,您以后可以在需要将查询时间从 O(n) 减少到 O(1) 时使用它。
问: 有没有办法"re-use"建立MySQL连接,以便后续请求可以使用现有连接?
A: 是。 您可以使用 连接池 实现。这是 Java 熟悉的模式,有几种可用的实现。
对于 PHP 中的连接池实现,您可以使用 PHP 扩展 mysqldnd-ms
.
参考:http://php.net/manual/en/mysqlnd-ms.pooling.php
注意:我没有使用此 PHP 扩展的个人经验。
您问的其他一些问题...
问: 我怎样才能最小化执行开销?有什么方法可以预编译一个查询,这样 mysql 就不需要每次都分析、优化和编译查询了吗?
A: 在 MySQL 5.6 中,您可以使用服务器端 prepared statements。准备语句的执行计划缓存在会话中,因此重复调用同一个 SQL 语句可以重新使用之前准备的执行计划。 (此功能在 5.6 之前的 MySQL 版本中不可用。)
减少“connection churning** 的数量将减少MySQL开销。连接和断开与数据库服务器的连接是服务器必须做的工作。测试和比较性能很简单。在一个进程,打开一个连接,并做一些重复的工作(重复执行一个简单的语句,比如SELECT NOW()
,然后断开连接。在另一个进程中,运行同样重复执行SELECT,但每次执行都会连接和断开连接。
问:准备好的语句是否在不同的会话中缓存?
A: 否。语句缓存在 语句 会话级别。
问: 有什么方法可以在 mysql 中共享客户端会话,例如在后续会话继承的第一个会话中使用准备好的语句?
A: 不。要做到这一点的唯一方法是 不 断开与数据库的连接,并且将该会话的句柄传递给请求连接的后续客户端。我们通过实施 连接池 .
来实现这一点
如果您在读取方面陷入困境,从属可以允许几乎无限的读取缩放。
其他问题:
- 批量插入有很大帮助。
- InnoDB 更擅长并发访问。
- 跨国延迟会导致延迟,而延迟可以通过存储过程(和其他技术)来缓解。
- 通常,您询问的开销不如查询优化重要。
- SP 有时会因为延迟较少而有所帮助。
- *Nix 优于 Windows。
- 太多 'simultaneous' 连接可能会适得其反。
- PHP 会话不太可能有用。
我对如何优化我的 SQL 查询有点困惑。我有一个中等复杂的查询,其中一些连接到 运行 每秒一百到一千次(SSD 上有两个 table,RAM 中有一个 table,4 个 JOIN)
如何最大程度地减少执行开销?有什么方法可以预编译一个查询,这样 MySQL 就不需要每次都分析、优化和编译查询了吗?
我知道我可以使用准备好的语句预编译一个查询,然后在同一会话中多次执行该查询。但是,如果您有多个会话并且每个会话只有一个查询怎么办?准备好的语句是否在不同的会话中缓存?我不这么认为。
然后我认为存储过程是最好的方法,因为据说它们是预编译的。现在我读到这个假设是完全错误的,它们实际上是 not 预编译的。
是否可以在 MySQL 中共享客户端会话,例如在后续会话继承的第一个会话中使用准备好的语句?
最后一个想法是编写一个多线程套接字服务器来充当 MySQL 客户端代理。但这对我来说似乎有点夸张。 ;-)
我使用 PHP 作为 Apache2 模块。是否有机会 "store" 共享内存中的 MySQL 会话,以便以下 HTTP 请求可以使用现有的 MySQL 会话而不是启动新会话?以便我可以在不同的 HTTP 请求中使用准备好的语句?
我想说,这样做的最佳做法之一是避免基于 O(n) 时间的查询和函数。为了能够在高负载数据下表现良好,所有的查询都必须在 O(1) 的额外时间内。这实际上意味着,无论您要获取多少数据,查询总是需要相同的时间。 (线性方程)
我的意思是,如果您将 IDS 存储在 $_SESSION
var 中,您以后可以在需要将查询时间从 O(n) 减少到 O(1) 时使用它。
问: 有没有办法"re-use"建立MySQL连接,以便后续请求可以使用现有连接?
A: 是。 您可以使用 连接池 实现。这是 Java 熟悉的模式,有几种可用的实现。
对于 PHP 中的连接池实现,您可以使用 PHP 扩展 mysqldnd-ms
.
参考:http://php.net/manual/en/mysqlnd-ms.pooling.php
注意:我没有使用此 PHP 扩展的个人经验。
您问的其他一些问题...
问: 我怎样才能最小化执行开销?有什么方法可以预编译一个查询,这样 mysql 就不需要每次都分析、优化和编译查询了吗?
A: 在 MySQL 5.6 中,您可以使用服务器端 prepared statements。准备语句的执行计划缓存在会话中,因此重复调用同一个 SQL 语句可以重新使用之前准备的执行计划。 (此功能在 5.6 之前的 MySQL 版本中不可用。)
减少“connection churning** 的数量将减少MySQL开销。连接和断开与数据库服务器的连接是服务器必须做的工作。测试和比较性能很简单。在一个进程,打开一个连接,并做一些重复的工作(重复执行一个简单的语句,比如SELECT NOW()
,然后断开连接。在另一个进程中,运行同样重复执行SELECT,但每次执行都会连接和断开连接。
问:准备好的语句是否在不同的会话中缓存?
A: 否。语句缓存在 语句 会话级别。
问: 有什么方法可以在 mysql 中共享客户端会话,例如在后续会话继承的第一个会话中使用准备好的语句?
A: 不。要做到这一点的唯一方法是 不 断开与数据库的连接,并且将该会话的句柄传递给请求连接的后续客户端。我们通过实施 连接池 .
来实现这一点如果您在读取方面陷入困境,从属可以允许几乎无限的读取缩放。
其他问题: - 批量插入有很大帮助。 - InnoDB 更擅长并发访问。 - 跨国延迟会导致延迟,而延迟可以通过存储过程(和其他技术)来缓解。 - 通常,您询问的开销不如查询优化重要。 - SP 有时会因为延迟较少而有所帮助。 - *Nix 优于 Windows。 - 太多 'simultaneous' 连接可能会适得其反。 - PHP 会话不太可能有用。