我有一个包含7列的mysql表,每行包含整数值。
我有一个简单的站点,它接收用户的值,我必须尝试查看用户发送的值是否与表中的任何行匹配或类似。
所以用户写道,例如1 2 3 4 5 6 7
作为输入。
我必须知道我的表中的任何行是否与没有顺序的行相似。所以1 2 3 4 5 6 7 = 7 6 5 4 3 2 1
等等。该表包含超过40,000行数据。
我还必须看看他们是否共享至少5
,6
或7
位数。
这意味着使用排列来查找所有可能的组合。然而,这种问题的最佳方法是什么?
从用户那里获取输入并获取所有排列并匹配第一行,第二行等,并报告是否找到?或者,反过来,从表中获取一行并获得所有排列并根据用户输入进行匹配?
当经历这么多排列的大桌子时,内存和CPU使用情况怎么样?
答案 0 :(得分:3)
在完整规范化架构中,这是一个具有查询的单一
让我们假设您的表格为pk:
create table T1
( pk char (1), a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int);
insert into T1 values
('a',1,2,3,4,5,6,7),
('b',2,3,4,5,6,7,8),
('z',10,11,12,13,14,15,16);
目前,我们可以将数据标准化为:
select
pk,
case a
when 1 then a1
when 2 then a2
when 3 then a3
when 4 then a4
when 5 then a5
when 6 then a6
when 7 then a7
end
as v
from T1
cross join
(select 1 as a from dual union all
select 2 as a from dual union all
select 3 as a from dual union all
select 4 as a from dual union all
select 5 as a from dual union all
select 6 as a from dual union all
select 7 as a from dual ) T2
在上一个查询中,您可以轻松地将您的要求与具有以下内容的单个匹配:
select pk
from
(
select
pk,
case a
when 1 then a1
when 2 then a2
when 3 then a3
when 4 then a4
when 5 then a5
when 6 then a6
when 7 then a7
end
as v
from T1
cross join
(select 1 as a from dual union all
select 2 as a from dual union all
select 3 as a from dual union all
select 4 as a from dual union all
select 5 as a from dual union all
select 6 as a from dual union all
select 7 as a from dual ) T2
) T
where
T.v in ( 4,5,6,7,8,9,10)
group by pk
having <-- The Having
count( pk ) > 4
| PK |
------
| b |
答案 1 :(得分:1)
一种轻量级方法可能是在数据库中添加一个额外的字段,这是所有7个字段组合的数字排序版本。
例如。如果数据库中的数据是2 4 7 6 5 1 3,则组合字段将为1234567
然后在比较时,以数字方式对用户响应进行排序,并与数据库中的组合字段进行比较。
根据您的工作情况,您可以像这样编写查询
select * from table where combination like '12%' or combination like '123%'
如果您知道匹配号码的最小数量是多少,那将会减轻查询次数
了解他们写的与数据库中的内容有多相似。您可以使用levenshtein PHP函数:http://php.net/manual/en/function.levenshtein.php
$result = levenshtein($input,$combination);
答案 2 :(得分:0)
我担心你无法真正有效地建立对这类问题的查询。
您可以构建WHERE
子句,如:
(`1` IN ARRAY(1,2,3,4,5,6,7)
AND `2` IN ARRAY(1,2,3,4,5,6,7)
AND `3` IN ARRAY(1,2,3,4,5,6,7)
AND `4` IN ARRAY(1,2,3,4,5,6,7)
AND `5` IN ARRAY(1,2,3,4,5,6,7))
OR
(`1` IN ARRAY(1,2,3,4,5,6,7)
AND `2` IN ARRAY(1,2,3,4,5,6,7)
AND `3` IN ARRAY(1,2,3,4,5,6,7)
AND `4` IN ARRAY(1,2,3,4,5,6,7)
AND `6` IN ARRAY(1,2,3,4,5,6,7))
-- Each combination
但那将是一个条件的地狱。另一方面,您可以尝试使用以下组合:
首先检查列1
是否包含信息:
IF( `1` IN ARRAY(1,2,3,4,5,6,7), 1, 0)
然后总结所有这些数据:
SELECT (
IF( `1` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
IF( `2` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
IF( `3` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
IF( `4` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
IF( `5` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
IF( `6` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
IF( `7` IN ARRAY(1,2,3,4,5,6,7), 1, 0)
) AS `matches_cnt`
FROM t1
HAVING `matches_cnt` >= 5
这将迭代所有行,条件非常复杂(因此床性能)。
您也可以尝试用二进制字符串替换值,例如:
1,2,7 = 01000011
然后在已检查记录和数据库之间计算Hamming distance,但这只会降低条件的复杂性,但需要迭代所有记录将保持不变。
使用以下方法在mysql中实现:
将替换第一部分:
SELECT (
$MAX_NUMBER$ - BIT_COUNT( XOR( `binary_representation`, $DATA_FROM_USER$))
) AS `matches_cnt`