在SQL列中存储标志并为其编制索引

时间:2014-01-15 12:07:18

标签: sql multi-database

我需要将一组与实体相关的标志存储到数据库中。 Flags可能不是最好的词,因为它们不是二进制信息(开/关),而是一组待定义的代码。

通常情况下,您会将每个信息(比如每个标记值)存储在一个不同的列中,但我正在探索将这些信息存储在不同于每列一列的数据结构中的机会,以防止显着增加在列映射中。由于每个标志对实体的每个属性都有效,因此您了解对于本质需要大量列的大型实体,列总数可能会增长为2n。

最终,这些代码可以映射到位置字符串。

我正在考虑这样的事情:02A不被解释为dec 42而是被解释为:

  • 在位置1标记0(如果您愿意,则为零)。
  • 位置2的旗帜2
  • 位置3的旗帜A

以这种方式格式化的数据可以通过高级编程语言轻松处理,因为PL / SQL超出了问题的范围,所有这些值都应该由Java处理

现在真正的问题

我的一个规格是优化搜索。我被要求找到一种方法(比如说,一种有效的方法)来寻找在给定位置显示某个标志(或特殊0标志)的实体。

通常,在SQL中,给定特定于RDBMS的子字符串函数,您将

SELECT * FROM ENTITIES WHERE SUBSTRING(FLAGS,{POSITION},1) = {VALUE};

这样可行,但我担心在所有平台上可能会有点慢,但Oracle,AFAIK,支持创建映射到子字符串的二级索引。

但是,由于Hibernate,我的解决方案必须在MySQL,Oracle,SQL Server和DB2中工作。

鉴于这样的设计,是否存在一些我可能缺少的跨平台索引策略?

3 个答案:

答案 0 :(得分:4)

如果性能是一个问题,我会在这里寻找一些不同的模型。

说一个表将实体和关系1-> N存储到另一个表(例如:flags table:entId(fk),flag,position),这个表将有一个标志和位置的索引。

这里的问题是将这个标志放在一个简单的列中,可以在java中完成,甚至可以在数据库中完成(但是很难对它进行交叉平台查询)

答案 1 :(得分:0)

如果您想要一种与数据库无关的合理方法来存储此类标志,那么请使用典型的SQL数据类型。对于二进制标志,您可以使用bitboolean(这在数据库之间有所不同)。对于其他标记,您可以使用tinyintsmallint

进行比特操作是而不是是可移植的。如果不出意外,用于从数据中提取特定位的函数在数据库之间是不同的。

其次,如果性能是一个问题,那么您可能需要创建索引以避免全表扫描。您可以在普通SQL数据类型上创建索引(尽管某些数据库可能不允许对位进行索引)。

听起来你正试图过于聪明。您应该首先使用合理的数据结构使应用程序工作。然后,您将了解性能问题的位置,并可以解决它们。

答案 2 :(得分:0)

我改进了设计并执行了基准,并找到了一个有趣的结果。

我创建了一个虚拟人口统计实体,包含名字/姓氏列,生日,出生地,电子邮件,SSN ......

然后在版本1

我添加了一个列VALIDATION VARCAHR(40) NULL DEFAULT NULL,上面有索引。

新列包含无序 代码的集合,而不是位置标志,每个代码代表特定的格式错误(例如A01表示"最后名称未指定"等。)。每个代码都以冒号:符号终止。

示例列看起来像

NULL
'A01:A03:A10:'
'A05:'

典型的查询是:

SELECT * FROM ENTITIES WHERE VALIDATION IS {NOT} NULL

搜索有效/无效的实体(NULL =没问题)

SELECT * FROM ENTITIES WHERE VALIDATION LIKE '%AXX:';

选择具有特定问题的实体

然后在版本1

我添加了一个VALID TINYINT NOT NULL列,其索引为0=invalid1=valid(Hibernate将Boolean映射到MySQL中的TINYINT

我添加了一个查找表

CREATE TABLE ENTITY_VALIDATION (
    ID BIGINT NOT NULL PRIMARY KEY,
    PERSON_ID LONG NOT NULL, --REFERENCES PERSONS(ID) --Omitted for performance
    ERROR CHAR(3) NOT NULL
)

PERSON_IDERROR都有索引。这代表1:N关系

查询:

SELECT * FROM ENTITIES WHERE VALIDATION = {0|1}

选择无效/有效实体

SELECT * FROM ENTITIES JOIN ENTITY_VALIDATION ON ENTITIES.ID = ENTITY_VALIDATION.PERSON_ID WHERE ERROR = 'Axx';

选择具有给定问题的实体

然后我进行了基准测试

通过JUnit + JDBC的count(*)函数。因此,您在上面看到的相同查询会将*替换为COUNT(*)

我做了几个基准测试,实体表包含100k,250k,500k,750k,1M实体,平均比率entity:flag1:3(每个实体平均有3个错误)。

结果

显示如下。虽然正确/不正确的实体查找同样有效,但看起来MySQL在LIKE运算符中比在JOIN中更快,即使有索引

Excel graph

当然,

这只是MySQL的基准。虽然该方法是跨平台的,但基准测试(还)比较不同DBMS中的性能