2016-02-14 45 views
11

我正在构建一个移动应用程序,我使用PHP & MySQL来编写后端--REST API。如何在MySQL数据库中存储60个布尔值?

如果我必须在我的移动应用程序中名为“Reports”(用户必须检查表单中的东西)的表中存储50-60个布尔值,我将值(0/1)存储在一个简单的数组中。在我的MySql表中,我应该为每个布尔值创建一个不同的列,还是仅仅使用字符串或Int将它存储为“数字”,如“110101110110111 ...”就足够了?

我得到并把数据与JSON。

更新1:我所要做的就是检查一切是否为1,如果其中一个为0,那么这就是一个“问题”。在两年内,这张桌子将有大约15.000-20.000排,它必须非常快速且尽可能节省空间。

更新2:在速度方面哪个解决方案更快?制作单独的列vs将其存储在字符串/二进制类型中。如果我必须检查哪些是0,该怎么办?如果我将它作为一个“数字”存储在一列中,并且它不是“111..111”,那么将它作为JSON发送给移动应用程序,在此解析数值并在用户设备上分析它,这是否是一个很好的解决方案?假设我必须处理5万行。

在此先感谢。

+2

如果您需要在这些标志的值上搜索(使用像'WHERE bool_a AND NOT bool_b'这样的东西),这会促使您将它们存储在自己的列中。但是您还没有告诉我们您的应用程序需要如何使用这些数据。 –

+0

你说得对。我所要做的就是检查一切是否为1,如果其中一个是0,那么这是一个“问题”。 2年内这个表格将有大约15.000-20.000行,它必须非常快速且尽可能节省空间。 – nethuszar

+0

如果你百分之百肯定你不必在中间添加东西,你可以带着旗子去。你可以使用BINARY类型。 – MartijnK

回答

13

每个值的单独列在搜索时更加灵活。

如果不同的行具有不同的布尔值集合,则单独的键/值表更灵活。

而且,如果

  1. 您的布尔值列表是更多或更少的静态
  2. 所有行中具有所有这些布尔值
  3. 您的性能关键搜索是找到行中任何值都是假的

然后使用像'1001010010'等文本字符串是一种很好的方式来存储它们。您可以像这样搜索

WHERE flags <> '11111111' 

找到您需要的行。

您可以对每个标志使用一个BINARY列。但是如果你使用文本,你的桌子将更容易用于临时查询和眼球检查。在开始存储数百万行之前,使用BINARY而不是CHAR来节省空间并不重要。

编辑不得不说的是:每次我用布尔属性数组构建类似的东西时,我后来对它变得僵化多么失望。例如,假设它是一个灯泡目录。在千年之交,布尔标志可能是这样的东西

screw base 
halogen 
mercury vapor 
low voltage 

然后,事情发生变化,我觉得自己需要更多的布尔标志一样,

LED 
CFL 
dimmable 
Energy Star 

等霎时间我的数据类型不够大,无法容纳我需要的数据。当我写下“你的布尔值列表或多或少是静态的”时,我的意思是你没有合理地期望在你的应用程序的生命周期中有类似灯泡特性的变化。

所以,一个单独的属性表可能是是一个更好的解决方案。它会有这些列:

item_id   fk to item table   -- pk 
    attribute_id  attribute identifier  -- pk 
    attribute_value 

这是最终灵活。你可以添加新的标志。您可以在应用程序的整个生命周期中随时将它们添加到现有项目或新项目中。而且,每个项目不需要相同的标志集合。你可以写下“哪些项目有任何虚假的属性?”查询是这样的:

SELECT DISTINCT item_id FROM attribute_table WHERE attribute_value = 0 

但是,你必须小心,因为查询“什么项目缺少属性”是一个很难写。

+0

怎么样BIT(N)而不是字符串? –

+0

谢谢你的回答。 “每次我用布尔属性数组构建类似的东西时,我后来都感到失望” 您能给我更好的解决方案吗?我很乐意学习新事物。 – nethuszar

+0

绝对是一个新表,它也是标准化的。 https://en.wikipedia.org/wiki/Database_normalization#Minimize_redesign_when_extending_the_database_structure –

11

为了您的特定目的,当任何零标志是一个有问题(例外),大多数条目(如99%)将是“1111 ... 1111”时,我没有看到任何理由来存储它们全部。我宁愿创建一个单独的表,只存储未经检查的标志。该表可能如下所示:uncheked_flags(user_id,flag_id)。在其他表中,您存储了标志定义:flags(flag_id,flag_name,flag_description)

然后你的报告就像SELECT * FROM unchecked_flags一样简单。

更新 - 可能表的定义:

CREATE TABLE `flags` (
    `flag_id` TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `flag_name` VARCHAR(63) NOT NULL, 
    `flag_description` TEXT NOT NULL, 
    PRIMARY KEY (`flag_id`), 
    UNIQUE INDEX `flag_name` (`flag_name`) 
) ENGINE=InnoDB; 

CREATE TABLE `uncheked_flags` (
    `user_id` MEDIUMINT(8) UNSIGNED NOT NULL, 
    `flag_id` TINYINT(3) UNSIGNED NOT NULL, 
    PRIMARY KEY (`user_id`, `flag_id`), 
    INDEX `flag_id` (`flag_id`), 
    CONSTRAINT `FK_uncheked_flags_flags` FOREIGN KEY (`flag_id`) REFERENCES `flags` (`flag_id`), 
    CONSTRAINT `FK_uncheked_flags_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) 
) ENGINE=InnoDB; 
1

可以获得更好的搜索出使用专用列,对于每一个布尔值,但基数很差,即使你索引中的每列将涉及一定程度的遍历或扫描。

如果您只是在寻找高值0xFFF ....然后肯定位图,这解决了你的基数问题(每OP更新)。这并不像你在检查奇偶校验一样......然而,如果这是正常的,那么树会严重倾向于高值,并且可能会产生一个热插入时容易发生节点分裂的热点。

位映射和使用位运算符掩码将节省空间,但需要对齐到一个字节,所以可能会有一个未使用的“提示”(可能为未来的字段设置),因此掩码必须保持长度或该字段用1填充。

这也会增加您的架构的复杂性,这可能需要定制的编码,定制的标准。

您需要对任何搜索的重要性进行分析(您可能通常不希望搜索全部甚至任何离散字段)。

这是非常规的数据非规范化策略,也用于调整特定客户端的服务请求。 (在同一交易中,某些回复比其他回复更为肥胖)。