我一直在研究 SQL_BUFFER_RESULT 的用法。大多数情况下,它被称为有助于减少表锁定问题。
使用它似乎是一个不错的选择。
但是,我似乎找不到任何缺点。它是大多数时候应该使用的选项吗?
Aar*_*own 10
SQL_BUFFER_RESULT
在服务器上为每个结果集创建一个临时表。这不是一个临时表CREATE TEMPORARY TABLE
——它是一个隐式临时表,当使用 GROUP BY 子句或子查询时会创建。因此,所有相同的规则都适用。
首先,让我们谈谈SQL_BUFFER_RESULT
旨在解决的问题:
当客户端从服务器请求数据时,在整个结果集被传输到客户端之前,查询仍在“运行”并且可能仍然持有一些锁。在传输数据时,它会出现在Sending data
状态中。它取决于客户端是否在执行查询时立即获取所有数据,或者它是否在您选择行时滴入,但问题的示例如下:
resultset = conn["SELECT * FROM bigtable"]
resultset.each do |row|
data[:value] = row[:value]
sleep 10 # do something expensive here
end
Run Code Online (Sandbox Code Playgroud)
显然是人为的,但是在上面的情况下如果有 1000 行,查询仍然会主动运行 10,000 秒。这似乎有些牵强,但许多应用程序在获取每一行之间都有“思考时间”,因为它们会进行一些处理。这是“一件非常糟糕的事情”。可能发生这种类型涓流效应的另一种情况是通过慢速连接产生大的结果集。最终,问题是将数据传输到客户端导致查询保持活动状态。 SQL_BUFFER_RESULT
通过首先将结果缓冲到一个临时表中来解决这个问题,这使得查询结束得更快,从而释放它的所有锁(什么锁?)。结果集然后从临时表而不是查询本身提供给客户端。
听起来不错!
但...
SQL_BUFFER_RESULT
从字面上看,每个查询都包括“使用临时”,(几乎)一直。我的一点测试表明,即使有这个提示,MySQL 在某些情况下也不使用临时表,但它们是有限的(主键上的单行查找似乎是唯一的情况)。下面举几个例子来说明效果:
-- unindexed lookup w/out SQL_BUFFER_RESULT
mysql> explain select * from actor where first_name = 'THORA'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: actor
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 203
Extra: Using where
1 row in set (0.00 sec)
-- unindexed lookup w/SQL_BUFFER_RESULT
mysql> explain select sql_buffer_result * from actor where first_name = 'THORA'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: actor
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 203
Extra: Using where; Using temporary
1 row in set (0.00 sec)
-- indexed lookup w/out SQL_BUFFER_RESULT
mysql> explain select * from actor where last_name = 'TEMPLE'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: actor
type: ref
possible_keys: idx_actor_last_name
key: idx_actor_last_name
key_len: 137
ref: const
rows: 4
Extra: Using where
1 row in set (0.00 sec)
-- indexed lookup w/SQL_BUFFER_RESULT
mysql> explain select sql_buffer_result * from actor where last_name = 'TEMPLE'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: actor
type: ref
possible_keys: idx_actor_last_name
key: idx_actor_last_name
key_len: 137
ref: const
rows: 4
Extra: Using where; Using temporary
1 row in set (0.00 sec)
-- primary key lookup w/SQL_BUFFER_RESULT
mysql> explain select sql_buffer_result * from actor where actor_id = 200\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: actor
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 2
ref: const
rows: 1
Extra:
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
解决的问题是什么?“锁。” 由于这是对 SELECT 查询的提示,除非您使用 FOR UPDATE 或 LOCK IN SHARED MODE,否则读取时使用的锁很少,而且速度非常快,因此您主要是在解决不存在的问题。异常总是存在,但是为几乎每个查询创建一个临时表的开销将远远超过使锁更快消失所带来的任何好处。
MySQL 的建议是在通过SQL_BUFFERED_RESULT
与客户端的网络连接检索非常大的结果集时使用提示。我看不到在其他上下文中使用它的任何价值。
话虽如此,您可以通过在每个会话开始时设置sql_buffer_result =1 来“全局”测试和设置它。在具有任何并发性的环境中,我会预测结果不佳。
归档时间: |
|
查看次数: |
5466 次 |
最近记录: |