我有个问题。
我有一张表,里面有大约 80-1 亿条记录。在该表中,我有一个字段,该字段存储了 3 到 16 个不同的“组合”(varchar)。组合是一个 4 位数字、一个冒号和一个 char(A-E), 。例如:'0001:A/0002:A/0005:C/9999:E'
.在这种情况下,有 4 种不同的组合(最多可以有 16 种)。该字段在表的每一行中,绝不为空。
现在的问题:我必须遍历表,找到每一行,看看它们是否相似。
示例行:
0001:A/0002:A/0003:C/0005:A/0684:A/0699:A/0701:A/0707:A/0709:A/0710:D/0711:C/0712:A/0713:A
0001:A/0002:A/0003:C
0001:A/0002:A/0003:A/0006:C
0701:A/0709:A/0711:C/0712:A/0713:A
如您所见,这些行中的每一行都与其他行相似(在某种程度上)。这里需要做的是当你发送
'0001:A/0002:A/0003:C'
通过程序(或 SQL 中的参数),它检查每一行并查看它们是否具有相同的“组”。现在这里的问题是它必须双向进行,并且必须“快速”完成,并且 SQL 需要以某种方式比较它们。所以当你发送
'0001:A/0002:A/0003:C/0005:A/0684:A/0699:A/0701:A/0707:A/0709:A/0710:D/0711:C/0712:A/0713:A'
它必须找到有 3-16 个相同组合的所有字段并返回行。这 3-16 可以通过参数指定,但问题是您需要找到所有可能的组合,因为您可以发送 '0002:A:/0711:C/0713:A'
,如您所见,您可以发送 0002:A
作为第一个参数。但是您不能有索引,因为组合可以在字符串中的任何位置,并且您可以发送未“附加”的不同组合(中间可能有不同的组合)。
所以,发送
'0001:A/0002:A/0003:C/0005:A/0684:A/0699:A/0701:A/0707:A/0709:A/0710:D/0711:C/0712:A/0713:A'
必须返回具有相同 3-16 个字段的所有字段它必须双向,如果您发送“0001:A/0002:A/0003:C”,它必须找到上面的行+相似的行(所有包含所有参数的行)。
我尝试过的一些事情/选项:
还有一个问题,这个表几乎 24/7 都在使用,在 SQL 中进行组合检查它们是否相同太慢了,因为表太大了,可以通过程序或其他东西来完成,但我没有关于如何将其存储在新行中的任何线索,您会以某种方式知道它们是相同的。您可能会计算组合,通过一些哈希码或每行插入的内容存储它们,通过程序计算“哈希”,并检查表,如:
SELECT * FROM TABLE WHERE ROW = "a346adsad"
参数将通过程序发送到哪里。
这个脚本需要非常快地执行,不到 1 分钟,因为表中可能有新的插入,您需要检查。
这样做的重点是查看 SQL 中是否已经存在任何类似的组合,并阻止任何对于插入“相似”的新组合。
我已经处理这个问题 3 天了,没有任何可能的解决方案,最接近的是不同类型的插入/哈希,但我不知道它是如何工作的。
预先感谢您提供任何可能的帮助,或者如果这是可能的!
最佳答案
it checks every row and see if they have the same "group".
恕我直言,如果 群是你的数据结构的一个基本元素,你的数据库结构是有缺陷的:它应该让每个组在它自己的单元格中进行规范化。您描述的结构清楚地表明您在字段中存储了一个复合值。
我会把 table 撕成3个:
这些方面的东西:
CREATE TABLE GRP_SEQUENCE_HEADER (
ID BIGINT PRIMARY KEY,
DESCRIPTION TEXT
);
CREATE TABLE GRP (
ID BIGINT PRIMARY KEY,
GROUP_TXT CHAR(6)
);
CREATE TABLE GRP_GRP_SEQUENCE_HEADER (
GROUP_ID BIGINT,
GROUP_SEQUENCE_HEADER_ID BIGINT,
GROUP_SEQUENCE_HEADER_ORDER INT, /* For storing the order in the sequence */
PRIMARY KEY(GROUP_ID, GROUP_SEQUENCE_HEADER_ID)
);
(当然,添加外键,最重要的是必要的索引)
然后,您只需将输入分成组,并在正确索引的表上执行简单查询。
此外,您可能也可以通过不存储重复项来节省磁盘空间......
用于查找“相似”序列 ID 的示例查询:
SELECT ggsh.GROUP_SEQUENCE_HEADER_ID,COUNT(1)
FROM GRP_GRP_SEQUENCE_HEADER ggsh
JOIN GRP g ON ggsh.GROUP_ID=g.GROUP_ID
WHERE g.GROUP_TXT IN (<groups to check for from the sequence>)
GROUP BY gsh.ID
HAVING COUNT(1) BETWEEN 3 AND 16 --lower and upper boundaries
这将返回与当前序列相似的所有 header ID。
编辑
再考虑一下,您甚至可以将小组分成两部分,但据我所知,您总是要处理完整的小组,因此似乎没有必要。
编辑2 也许如果您想进一步加快该过程,我建议您将使用双射的序列转换为数字数据。例如,将前 4 个数字计算为整数,将其向左移动 4 位(乘以 16,但更快),并将字符的十六进制值添加到最后一个位置。
例子:
0001/A --> 1 as integer, A is 10, so 1*16+10 =26
...
0002/B --> 2 as integer, B is 11, so 2*16+11 =43
...
0343/D --> 343 as integer, D is 13, so 343*16+13 =5501
...
9999/E --> 9999 as integer, E is 14, so 9999*16+14 =159998 (max value, if I understood correctly)
数字值由数据库更有效地处理,因此这应该会带来更好的性能 - 当然是使用新结构。
关于mysql - SQL - 比较 1 亿张表上的文本(组合),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14258710/