从导入的规则

时间:2017-07-30 20:32:44

标签: database algorithm

标题非常不精确,但我想避免将整个问题复制到其中。这些集实际上是地图,如第一部分所述,规则在第二部分,问题是生成所有内容将意味着过多的数据,如上一节所述。

当前状态

目前有几十个,很快就有数百个Customer个。他们每个人可能有数千Item和数千Catalog s。每个项目和每个目录只属于一个客户,不同客户的数据不会互动。

项目和目录保持m:n关系。我将目录视为重叠的项目集,并且还有一些其他相关细节。数据来自导入文件,如

catalog1 item1 details11
catalog1 item3 details13
catalog2 item1 details12
catalog2 item2 details22

在数据库中,有一个包含三列的连接表,就像导入文件一样。

在此示例中,我将catalog1的内容检索为{item1: details11, item3: details13}等。检索此表单中目录的内容是唯一重要的查询。到目前为止,它非常简单。

导入每天发生几次,我必须相应地更新数据库内容。从某种意义上说,导入是部分的,即始终只有单个客户的数据被导入,这意味着始终只有 一部分数据受到影响。从导入文件包含给定客户的所有数据的意义上说,导入已满,因此我必须添加新内容,更新更改内容以及删除新导入中缺少的内容文件。还是相当微不足道。

新要求

现在,将介绍群组。每个Item可能是多个ItemGroup的成员,每个Catalog可能是多个CatalogGroup的成员。此信息可单独获得,导入格式几乎不变:代替目录,可能有目录组,而不是项目,可能有项目组。

所以有像

这样的规则
catalog1 item1 details100
catalogGroup1 item1 details101
catalog1 itemGroup1 details102
catalogGroup1 itemGroup1 details102

代替简单的连接表行。这些规则可能并且将会发生冲突,我目前倾向于通过优先考虑早期规则来解决冲突(导入文件的制作者将接受我的决定)。

Details中,可能有一条信息表明相应的项目应从目录中排除,例如

catalog1 item1 EXCLUDE
catalog1 itemGroup1 someDetails

表示catalog1包含itemGroup1以外的所有项目,item1除外(第一个规则获胜)。

问题

我们的连接表已经有将近一百万行,我们刚刚开始。如果没有新要求,它可能会增长到数亿行,这是可以接受的。

根据新要求,此数字可能会快得多,因此存储连接表可能不可行。现在,这个表占用的磁盘空间比所有剩余磁盘空间多。编写一条错误产生数百万行的规则也很容易(肯定会在一天内发生)。

我们所需要的只是能够相当快速地检索目录的内容,即,当它包含数百个项目时,不到半秒。到目前为止,我们不一定需要存储表,一些使用索引的JOIN和一些简单的后处理应该没问题。

许多目录根本没有被查询,但这并不能帮助我们不知道哪些目录。

进口不需要快。目前,他们需要一两秒钟,但几分钟是可以接受的。

所以我想知道我是否应该为catalogcatalogGroupitemitemGroup的每个组合创建四个表格。每个表还包含导入文件中的行号,以便我可以检索与请求的目录匹配的所有规则,并在后处理中解决冲突。

或者更好的是一些hacky解决方案?我有点倾向于创建一个表

catalog, catalogGroup, item, itemGroup, lineNo, details_part1, details_part2, ...

(其中总是正好使用前四列中的两列),因为细节实际上是几个部分的元组,这使得四个表非常重复。我可以在新表中提取细节或者将它们一起填充。

我正在寻找一些有效解决问题的一般性建议。

我想,有些细节遗失了,但这个问题已经太久了。随意问。它是一个使用Java,Hibernate和MySQL的Web应用程序,但省略了标签,因为它几乎不重要。

评论的答案

  

查询是否仍适用于目录内容?

是的,就像以前一样。这些组是一种输入压缩,仅此而已。

  

如果项目已连接到目录或包含查询目录的组,则会返回该项目吗?

或者是这样一个团体的成员。

  

项目组如何运作?

两种群体都是一样的:

包含组的规则等同于规则列表,每个组成员一个。

2 个答案:

答案 0 :(得分:1)

我建议从规范化表和简单连接开始。如果我正确地阅读了您的问题,那么这是一个合理的架构:

CREATE TABLE items (
  id integer PRIMARY KEY,
  name varchar(40)
);

CREATE TABLE catalogs (
  id integer PRIMARY KEY,
  name varchar(40)
);

CREATE TABLE item_groups (
  id integer PRIMARY KEY,
  name varchar(40)
);

CREATE TABLE catalog_groups (
  id integer PRIMARY KEY,
  name varchar(40)
);

CREATE TABLE items_in_groups (
  item_id integer REFERENCES items(id),
  item_group_id integer REFERENCES item_groups(id),
  PRIMARY KEY(item_id, item_group_id)
);

CREATE TABLE catalogs_in_groups (
  catalog_id integer REFERENCES catalogs(id),
  catalog_group_id integer REFERENCES catalog_groups(id),
  PRIMARY KEY(catalog_id, catalog_group_id)
);

CREATE TABLE exclusions (
  catalog_id integer REFERENCES catalogs(id),
  item_id integer REFERENCES items(id),
  PRIMARY KEY(catalog_id, item_id)
);

CREATE TABLE connections (
  catalog_group_id integer REFERENCES catalog_groups(id),
  item_group_id integer REFERENCES item_groups(id),
  details varchar(40),
  PRIMARY KEY(catalog_group_id, item_group_id)
);

请注意,items_in_groupscatalogs_in_groups分别为每个项目和目录获取单个条目。也就是说,每个项目由1个元素组表示,并且对于目录表示相同。

现在添加一些数据:

INSERT INTO items VALUES (1, 'Item 1'), (2, 'Item 2'), (3, 'item 3'), (4, 'item 4'), (5, 'item 5'), (6, 'item 6');
INSERT INTO catalogs VALUES (1, 'Catalog 1'), (2, 'Catalog 2'), (3, 'Catalog 3'), (4, 'Catalog 4'),
  (5, 'Catalog 5'), (6, 'Catalog 6');

INSERT INTO item_groups VALUES
  (1, 'Item group 1'), (2, 'Item group 2'), (3, 'Item group 3'), (4, 'Item group 4'), (5, 'Item group 5'),
  (6, 'Item group 6'), (10, 'Item group 10'), (11, 'Item group 11'), (12, 'Item group 12');

INSERT INTO catalog_groups VALUES
  (1, 'Catalog group 1'), (2, 'Catalog group 2'), (3, 'Catalog group 3'), (4, 'Catalog group 4'), 
  (5, 'Catalog group 5'), (6, 'Catalog group 6'), (10, 'Catalog group 10'), (11, 'Catalog group 11'),
  (12, 'Catalog group 12');

INSERT INTO items_in_groups VALUES
  (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (2, 10), (4, 10),
  (6, 10), (1, 11), (3, 11), (5, 11), (1, 12), (2, 12), (3, 12), (6, 12);

INSERT INTO catalogs_in_groups VALUES
  (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (2, 11), (4, 11),
  (6, 11), (1, 10), (3, 10), (5, 10), (3, 12), (4, 12), (5, 12), (6, 12);

INSERT INTO exclusions VALUES (5, 1), (6, 3);

INSERT INTO connections VALUES (1, 10, 'Details 1-10'), (11, 2, 'Details 11-2'), (12, 12, 'Details 12-12');

并查询:

SELECT cig.catalog_id, iig.item_id, c.details FROM connections AS c
INNER JOIN item_groups AS ig ON c.item_group_id = ig.id
INNER JOIN catalog_groups AS cg ON c.catalog_group_id = cg.id
INNER JOIN items_in_groups AS iig ON iig.item_group_id = ig.id
INNER JOIN catalogs_in_groups AS cig ON cig.catalog_group_id = cg.id
WHERE NOT EXISTS (
  SELECT NULL
  FROM exclusions e
  WHERE iig.item_id = e.item_id AND cig.catalog_id = e.catalog_id)
ORDER BY cig.catalog_id, iig.item_id;

结果:

 catalog_id | item_id |    details
------------+---------+---------------
          1 |       2 | Details 1-10
          1 |       4 | Details 1-10
          1 |       6 | Details 1-10
          2 |       2 | Details 11-2
          3 |       1 | Details 12-12
          3 |       2 | Details 12-12
          3 |       3 | Details 12-12
          3 |       6 | Details 12-12
          4 |       1 | Details 12-12
          4 |       2 | Details 11-2
          4 |       2 | Details 12-12
          4 |       3 | Details 12-12
          4 |       6 | Details 12-12
          5 |       2 | Details 12-12
          5 |       3 | Details 12-12
          5 |       6 | Details 12-12
          6 |       1 | Details 12-12
          6 |       2 | Details 11-2
          6 |       2 | Details 12-12
          6 |       6 | Details 12-12
(20 rows)

您可以将itemscatalogs添加到联接中以查找相应的名称,而不是使用ID停止。

SELECT cat.name, item.name, c.details FROM connections AS c
INNER JOIN item_groups AS ig ON c.item_group_id = ig.id
INNER JOIN catalog_groups AS cg ON c.catalog_group_id = cg.id
INNER JOIN items_in_groups AS iig ON iig.item_group_id = ig.id
INNER JOIN catalogs_in_groups AS cig ON cig.catalog_group_id = cg.id
INNER JOIN catalogs AS cat ON cat.id = cig.catalog_id
INNER JOIN items AS item ON item.id = iig.item_id
where NOT EXISTS (
  SELECT NULL
  FROM exclusions e
  WHERE iig.item_id = e.item_id AND cig.catalog_id = e.catalog_id)
ORDER BY cig.catalog_id, iig.item_id;

像这样...

   name    |  name  |    details    
-----------+--------+---------------
 Catalog 1 | Item 2 | Details 1-10
 Catalog 1 | item 4 | Details 1-10
 Catalog 1 | item 6 | Details 1-10
 Catalog 2 | Item 2 | Details 11-2
 Catalog 3 | Item 1 | Details 12-12
 Catalog 3 | Item 2 | Details 12-12
 Catalog 3 | item 3 | Details 12-12
 Catalog 3 | item 6 | Details 12-12
 Catalog 4 | Item 1 | Details 12-12
 Catalog 4 | Item 2 | Details 11-2
 Catalog 4 | Item 2 | Details 12-12
 Catalog 4 | item 3 | Details 12-12
 Catalog 4 | item 6 | Details 12-12
 Catalog 5 | Item 2 | Details 12-12
 Catalog 5 | item 3 | Details 12-12
 Catalog 5 | item 6 | Details 12-12
 Catalog 6 | Item 1 | Details 12-12
 Catalog 6 | Item 2 | Details 11-2
 Catalog 6 | Item 2 | Details 12-12
 Catalog 6 | item 6 | Details 12-12
(20 rows)

如您所见,存在重复的目录/项目ID对以及相应的详细信息。我想这就是你所说的冲突。"调整查询以遵守优先级规则以选择其中一种替代方案并不困难。

获取特定目录的商品只是一个额外的AND原因:

SELECT cat.name, item.name, c.details FROM connections AS c
INNER JOIN item_groups AS ig ON c.item_group_id = ig.id
INNER JOIN catalog_groups AS cg ON c.catalog_group_id = cg.id
INNER JOIN items_in_groups AS iig ON iig.item_group_id = ig.id
INNER JOIN catalogs_in_groups AS cig ON cig.catalog_group_id = cg.id
INNER JOIN catalogs AS cat ON cat.id = cig.catalog_id
INNER JOIN items AS item ON item.id = iig.item_id
WHERE NOT EXISTS (
  SELECT NULL
  FROM exclusions e
  WHERE iig.item_id = e.item_id AND cig.catalog_id = e.catalog_id)
AND cat.id = 3
ORDER BY cig.catalog_id, iig.item_id;

和...

   name    |  name  |    details    
-----------+--------+---------------
 Catalog 3 | Item 1 | Details 12-12
 Catalog 3 | Item 2 | Details 12-12
 Catalog 3 | item 3 | Details 12-12
 Catalog 3 | item 6 | Details 12-12
(4 rows)

像往常一样,还有其他几种编写查询的方法。我没有SQL向导,但SO有很多。如果这第一次黑客不够好,请回来问问。非规范化和疯狂的预处理和后处理方案剥夺了未来的灵活性。

答案 1 :(得分:0)

您可以像这样建立目录关系表

目录关系表

+--------------------------------------+
| Id |  catalog   | ref_catalog        |
+----+------------+--------+-----------+
| 1  | 'catalog1' |   'catalog1'       |
| 2  | 'catalog1' |   'catalogGroup1'  |
| 3  | 'catalog2' |   'catalog2'       |
| 4  | 'catalog2' |   'catalogGroup1'  |
+--------------------------------------+

当计算catalog1的内容时,您可以搜索目录为catalog1`的行。假设这个数量不大。

目录项目表<​​/ p>

+--------------------------------------+
| Id |  catalog        | ref_item      |
+----+-----------------+---+-----------+
| 1  | 'catalog1'      |   'item1'     |
| 2  | 'catalogGroup1' |   'itemGroup2'|
| 3  | 'catalog1'      |   'item2'     |
| 4  | 'catalogGroup2' |   'itemGroup2'|
+--------------------------------------+

然后搜索目录项表。

之后,将itemGroup替换为单独的项目。

我认为这不会是O(n x n)而是O(n)。

我建议您在rails模型上使用ruby来提高性能。

如果没有硬算法,您可以使用belongs_to&amp ;;轻松制作表格的嵌套结构。 has_many