此过程是此目标应用程序中最常访问的过程。假设并发操作,并且 t.value 总是在变化。
-- Table is MySQL InnoDB
-- let's call this MainSelect
SELECT t.Id
FROM table t
WHERE t.A = conditionA AND t.B = conditionB AND t.value > 0
ORDER BY RAND()
LIMIT 1 INTO vIndex FOR UPDATE;
-- IF vIndex THEN
UPDATE table SET value = value - 1 WHERE id = vIndex
目标是修改此查询以使用这种随机行选择方法的一种形式来提高速度。这里是为了完整性。这是这篇文章的主要问题。
SELECT name
FROM random AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
讨论:
MainSelect 中的总行数如何确定?
如果这个问题的答案是创建 MainSelect 子查询,将 FOR UPDATE 移动到最外面的查询,那么在外部 SELECT 用 FOR UPDATE 锁定该行之前,随机选择的行的 t.value 可能变为 0。就像是:
SELECT * FROM (firstquery) s ...random selection logic.. FOR UPDATE;
如果这种考虑是准确的,那么问题就在于应该在一开始就设置哪个交易级别。
谢谢
编辑- 工作时的注意事项:
也许http://en.wikipedia.org/wiki/Reservoir_sampling,因为计数未知。我想避免高隔离级别,因为我预计会降低吞吐量。
也许可以存储和索引一个随机数,而不是计算。然后选择一个随机数,根据限制文档,随机选择一个非常快。这样做的问题是结果集将不统一。
如果将 LIMIT row_count 与 ORDER BY 一起使用,MySQL 会在找到排序结果的第一个 row_count 行后立即结束排序,而不是对整个结果进行排序。如果使用索引进行排序,则速度非常快。