如何针对高负载下的性能优化 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 会话不太可能有用。