0

我需要将一组与实体相关的标志存储到数据库中。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 中运行。

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

4

3 回答 3

4

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

假设一个存储实体的表以及与另一个表的关系 1->N(例如:标志表:entId(fk)、标志、位置),并且该表将具有标志和位置的索引。

这里的问题是在一个简单的列中获取这些标志,这可以在 java 甚至数据库中完成(但是很难对此进行跨平台查询)

于 2014-01-15T12:20:13.613 回答
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=invalid的列1=valid(Hibernate 将 a 映射BooleanTINYINTMySQL 中的 a)。

我添加了一个查找表

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_ID和上都有索引ERROR。这代表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操作符中比在 a中更快JOIN,即使有索引

Excel图表

当然,

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

于 2014-01-23T07:56:52.037 回答
0

如果您想要一种独立于数据库的合理方法来存储此类标志,请使用典型的 SQL 数据类型。对于二进制标志,您可以使用bitor boolean(这在数据库中有所不同)。对于其他标志,您可以使用tinyintsmallint

做位摆弄不会是可移植的。如果不出意外,用于从数据中提取特定位的函数在数据库之间是不同的。

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

听起来你想变得过于聪明。您应该首先让应用程序使用合理的数据结构工作。然后,您将了解性能问题在哪里,并可以着手解决这些问题。

于 2014-01-15T12:12:59.770 回答