如何有效地存储和搜索巨大的MySQL彩票数据库

时间:2014-02-13 20:08:05

标签: php mysql

每周超过100万张门票。用户选择1到49之间的6个数字。所有数字(票证)将无限期保留。每周都必须选出获胜者。

在一个表格中,我拥有ID号和唯一电子邮件的所有用户。在故障单表中,我有唯一的故障单ID,引用用户ID的外键,所选的数字字段和时间戳。在某些情况下,一个用户在一周内可以拥有多张票。

  1. 存储此类数据的最有效方法是什么?更具体地说,存储数字的数据类型,记住会有大量的条目,还需要不时地进行搜索。

  2. 根据您提出的数据结构,选择当前一周中选出4个中奖号码,5 ..和6的所有用户的有效方法是什么。

  3. 我看到了将它存储为二进制的想法,因此3,6将是001001 ......鉴于我认为自己是一名普通的程序员,这对我来说似乎是天才。易于搜索,似乎要存储几个字节(虽然我不知道MySql如何准确存储其数据)。 有没有更好的办法?我看到这种方法的唯一缺点是它不容易被人类阅读。

    更新:链接到二进制构思:https://stackoverflow.com/a/1931286/2374034

2 个答案:

答案 0 :(得分:1)

  1. 整数存储效率很高。 TINYINT UNSIGNED列使用一个字节,可以存储1到255之间的整数。我假设保持选择号码的顺序正确,并且总共有6个。因此,我建议您使用6个TINYINT UNSIGNED列作为数字。这可能比二进制更好。

  2. 我建议使用week.id,week.name,win.id,win.week_id,win.user_id,win.match_count的周表和win表。

答案 1 :(得分:1)

如果要单独存储六个值,则每个数字需要TINYINT,因此总共需要六个1字节列。这是您的最佳选择。

通过将列声明为NOT NULL,可以为每列节省一点额外的开销。

其他选择并不紧凑:

  • 虽然每个数字实际上并不需要8位,但如果数字的范围是1-49。每个数字只需要6位(以6位存储0-48)。

    所以你可以在36位中存储六个数字1-49。 INT UNSIGNED是32位,因此它太小但BIGINT可以存储64位。在32位和64位之间没有INT类型。

    要将六个数字存储在一个BIGINT中,请将每个数字移位6位并按位或将它们组合在一起。

    INT = (A-1) | ((B-1)<<6) | ((C-1)<<12) | ((D-1)<<18) | ((E-1)<<24) | ((F-1)<<30)
    

    结果不会是人类可读的,但至少它是紧凑的。

  • 要使用SET存储1-49范围内的六个选项的位域,您需要至少49位(每个可能的数字选择一位),因此您需要至少7个字节。 MySQL的SET以1,2,4或8字节为增量存储,具体取决于不同SET元素的数量。这个需要8字节大小。

  • MySQL还有BIT数据类型,您可以声明BIT(36)列。但是这种数据类型以4字节为增量使用空间,所以无论如何你最终都会使用每张票64位。

最终,你每售出一张票就说TicketID + UserID + 6xTINYINT,所以每行大概16个字节。但是有一些开销。我刚刚测试了将1048576行插入到具有此定义的表中。存储大约需要40MB。

因此,您可以指望每年需要大约40MB * 52周= 2058MB。但是现在,你几乎买不到500GB以下的硬盘,所以我觉得你会好的。当你填满平均驱动器时,无论如何都应该升级到量子计算机。 : - )


重新评论:

是的,您可以在日期定义索引并使搜索非常有效。定义正确的索引必须由您需要运行的查询确定。

或者您可以使用PARTITION BY定义表格,并使用日期(或周)作为分区键。但要小心分区,它并不总是万能的。你应该仔细阅读它的limitations


  

你如何从6个数字中提取出4张所有票?

在MySQL中,布尔条件产生1或0,然后可以在算术中使用。

SELECT * FROM tickets
WHERE (A=?) + (B=?) + (C=?) + (D=?) + (E=?) + (F=?) >= 4

这必然会导致表扫描,但无论您使用什么解决方案存储数据,都会受到影响。