15

我在带有 InnoDB 引擎的 MySQL 中有一个表 v_ext:
- id:主键
- 代码:预先生成的代码列表(比如随机生成 1000 个代码)
- user_id:最初为 NULL

当用户购买商品时,他们会收到一个代码。我需要更新表以填充 user_id 列。我有两个选择:

START TRANSACTION;
SELECT id FROM v_ext WHERE user_id IS NULL LIMIT 1 FOR UPDATE; -- return id 54 for ex.
UPDATE v_ext SET user_id=xxx WHERE id=54;
COMMIT;

或者

UPDATE v_ext SET user_id=xxx WHERE user_id IS NULL LIMIT 1;

如果我有成千上万的用户同时购买,第二种选择是否安全?如果是这样,假设第二个选项对性能更好,因为它只需要一个查询是正确的吗?

4

1 回答 1

18

由于我没有得到答案,我开始做基准测试。我的标准如下:

  • 20,000 个预生成代码
  • ab使用20,000 个请求,100 个并发的 Apache命令:ab -n 20000 -c 100
  • Servlet -> EJB (JPA 2.0 EclipseLink, JTA) 在 DB 中执行更新(因为在实际情况下它将通过 JSF 操作)
  • Servlet 的 2 个版本,一个带有选项 1(SELECT ... FOR UPDATE),一个带有选项 2(UPDATE ... LIMIT 1)
  • 停止 Glassfish,手动点击 5 次测试的 Servlet 使其预热,将所有设置为 NULL 到 user_id
  • 测试每次运行 3 次并提供平均值

结果:

选择...更新;更新 ... :

Concurrency Level:      100
Time taken for tests:   758.116 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Row updated:            20000

更新....限制1:

Concurrency Level:      100
Time taken for tests:   773.659 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Row updated:            20000

所以至少在我的系统上,带有 2 个查询的选项似乎比一个查询更有效。我没想到:)

于 2012-12-27T06:00:31.763 回答