这是我第一个与可伸缩性相关的问题。
为了简化问题,我将使用宾果游戏的想法:
我们有一个宾果应用程序。每个用户都有一张包含15个随机数的门票。每周都会举行宾果游戏以找到获胜者。在获胜者之前,数字会被直播。例如:
哪种方式更好/更快地表示表中的数据和搜索该表?表将有超过10万行
表门票
id user_id week ticket created
====================================================================================================
1 100022312 1 1,3,5,7,9,14,15,77,78,79,80,81,82,83,84 <timestamp>
2 102232123 1 2,5,9,22,33,44,55,66,77,,78,79,80,88,89 <timestamp>
3 201141028 1 7,8,9,11,22,33,34,35,37,39,51,55,58,63,66 <timestamp>
...
9.000.000 126387125 1 8,18,28,38,48,58,68,78,79,80,81,82,83,84,85 <timestamp>
10.000.000 126387126 1 1,4,14,24,34,45,56,66,67,68,79,80,81,82,83 <timestamp>
腓
$drawn_numbers = '1,2,3,4,5,6,7,89,10,11,12,13,14,15,16,17,18,19,20,21,22, ...';
$result = query("SELECT * FROM Tickets WHERE sksf('$drawn_numbers')");
其中sksf
将是MySql中完成的某种子串函数/ regex / LIKE。
表门票
id user_id week n1 n2 n3 ... n15 created
=============================================================================
1 100022312 1 11 32 52 ... 76 <timestamp>
2 102232123 1 22 52 55 78 <timestamp>
3 201141028 1 77 82 83 ... 89 <timestamp>
...
9.000.000 126387125 1 81 55 32 ... 10 <timestamp>
10.000.000 126387126 1 12 42 13 ... 77 <timestamp>
腓
$drawn_numbers = '1,2,3,4,5,6,7,89,10,11,12,13,14,15,16,17,18,19,20,21,22, ...';
$result = query("SELECT * FROM Tickets WHERE contidion1 AND condition2 AND ...");
不幸的是,在这里我仍然对这些条件一无所知。
我选择所有故障单,通过检查所绘制的数字是否包含任何故障单来迭代它们。
$drawn_numbers = '1,2,3,4,5,6,7,89,10,11,12,13,14,15,16,17,18,19,20,21,22, ...';
$all_tickets = query("SELECT * FROM Tickets");
foreach ($all_tickets as $ticket) {
if $drawn_numbers.contains($ticket['ticket'])
return $ticket['id'];
}
无论如何,排序的数字会有帮助吗? (这15个数字和绘制的数字)
第2周到来会发生什么?我应该使用相同的表格,添加条件WHERE week=2
,还是每张桌子只有1周更好?
在原始游戏中,一张票有3行15个数字,每行有5个数字。在实时绘制每个数字之后,他们还能够计算在绘制的数字中找到一行的票证(他们也知道具有2行的票证)。在抽取的数字中找到3行的票证将意味着中奖票。
这些信息让我觉得代表看起来像是:
表门票
id user_id week row1 row2 row3 created
===============================================================================================================
1 100022312 1 1, 3, 5, 7, 9 14,15,77,78,79, 80,81,82,83,84 <timestamp>
2 102232123 1 2, 5, 9,22,33, 44,55,66,77,78, 79,80,87,88,89 <timestamp>
3 201141028 1 7, 8, 9,11,22, 33,34,35,37,39, 51,55,58,63,66 <timestamp>
...
9.000.000 126387125 1 8,18,28,38,48, 58,68,78,79,80, 81,82,83,84,85 <timestamp>
10.000.000 126387126 1 1, 4,14,24,34, 45,56,66,67,68, 79,80,81,82,83 <timestamp>
__ 13 __ 33 40 __ __ 70 __
2 __ 22 37 __ 52 62 __ 81
__ 19 23 __ 44 __ 63 __ 89
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 19, 23, 44, 63, 89
-> there is a winner, no more numbers are drawn.
-> Our ticket did not win jackpot, but we won one row [19, 23, 44, 63, 89] (free ticket)
-> One can win also 2 rows.
答案 0 :(得分:2)
我会使用两个BIGINT
列,并且每个位代表一个宾果值(1..90)。构建一组球需要一些操作,但搜索将很容易,存储将 更紧凑等等。
我们有两列,一列是数字1..60,另一列是61..90。 (选择有点随意,但可以很容易地进行可视化。)现在我们可以使用一个BIGINT
和一个INT
来完成。
IF($value <= 60, 1 << $value, 0) -- the bit for the BIGINT
IF($value > 60, 1 << ($value - 60), 0) -- the bit for the INT
现在或者在一起比特会给你一对数字来代表中奖彩票。使用|
运算符执行此任务。
每个玩家当前的球也将被或 - 每次比赛后都会打开一个新位。
然后测试变成这样:
-- The balls owned by a user:
user_60 BIGINT,
user_30 INT
-- winning balls (12 rows, a total of 5 bits on for each row)
win_60 BIGINT,
win_30 INT
-- Note: FREE SPACE should be pre-populated in both structures
BIT_COUNT(user_60 & win_60) +
BIT_COUNT(user_30 & win_30) = 5 -- he's a winner!
我遗漏了一个重要的步骤 - 在每个用户的主板上安排数字。这将需要一些前期工作,特别是因为15个数字只能在卡片的第一列。等
你的回答是从位而不是其他结构。
另一个想法是有5 SMALLINT UNSIGNED
,每张卡上有一个。
(将来,在MySQL 8.0中,BINARY(16)
将允许单个列表示一组90个值,从而使代码更清晰。)
重新构思4
构建3位模式 - 每个“行”一个,带有5个数字。将它们与发行的票证进行比较:Foreach票,比较3种模式;算一下多少匹配。
答案 1 :(得分:0)
都不是。
一种方法是use a bitmap票号。您需要2个BIGINT来存储值。如果票号和所选号码的AND返回与票号相同的值,则表示您匹配。但你不能使用索引。
如果仅通过匹配某些数字来赢得胜利,那么您引用的两种方法都会非常低效 - 您需要规范化数据:
create table ticket (
id integer auto_increment,
user_id /* appropriate type for FK to your data about users */,
week_number integer,
PRIMARY KEY (id),
);
create table numbers (
number integer not null,
ticket_id integer not null,
FOREIGN KEY ticket_id references ticket(id)
);
这看起来像是一个精心设计的场景来测试可扩展性方法 - 您是否要求我们在这里做作业?