如何比较具有不同数量值的数据

How to compare data with varying number of values

我会尽力解释我的问题。

我必须比较相同类型的数据,这些数据保存在 MySql 数据库中但包含不同数量的值。

我这样构建我的数据库(可能不是最好的):

--
-- Table structure for table `amount`
--

CREATE TABLE `amount` (
  `id` tinyint(1) UNSIGNED NOT NULL,
  `value` tinyint(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `amount`
--

INSERT INTO `amount` (`id`, `value`) VALUES
(34, 1),
(22, 2),
(30, 6),
(21, 7),
(9, 8),
(17, 9),
(10, 10),
(15, 11),
(3, 12),
(4, 13),
(8, 14),
(5, 15),
(16, 16),
(13, 17),
(6, 18),
(20, 19),
(7, 20),
(23, 21),
(18, 22),
(19, 23),
(24, 24),
(14, 25),
(25, 26),
(26, 27),
(28, 28),
(29, 29),
(11, 30),
(27, 31),
(12, 32),
(31, 33),
(32, 35),
(33, 36),
(2, 98),
(1, 99);

-- --------------------------------------------------------

--
-- Table structure for table `mark`
--

CREATE TABLE `mark` (
  `id` tinyint(1) UNSIGNED NOT NULL,
  `name` varchar(16) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `mark`
--

INSERT INTO `mark` (`id`, `name`) VALUES
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D'),
(5, 'E'),
(6, 'F'),
(7, 'G'),
(8, 'H'),
(9, 'I'),
(10, 'J')
(11, 'K')
(12, 'L')
(13, 'M')
(14, 'N')
(15, 'O');

-- --------------------------------------------------------

--
-- Table structure for table `profile`
--

CREATE TABLE `profile` (
  `id` smallint(2) UNSIGNED NOT NULL,
  `run` smallint(2) NOT NULL,
  `deleted` datetime DEFAULT NULL,
  `created` datetime NOT NULL,
  `validated` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Table structure for table `profile_mark`
--

CREATE TABLE `profile_mark` (
  `id` int(11) NOT NULL,
  `id_profile` smallint(2) UNSIGNED NOT NULL,
  `id_mark` tinyint(1) UNSIGNED NOT NULL,
  `id_amount` tinyint(1) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

每次新数据到达时,都会创建一个配置文件,如果需要,还会创建一个新标记和新数量。

这意味着一个配置文件最多可以有 48 个值。我计划将来数据库中至少有 20000 个配置文件。

我的目标: 如果我选择一个配置文件,我必须找到所有其他配置文件,这些配置文件的 X 标记至少有 1 个共同值。 (其中 X 是必须匹配的最小标记数)

目前,我将所有配置文件一一与测试的进行比较。这需要一些时间(我目前在数据库中只有大约 50 个配置文件)并且对于我的应用程序的未来来说这不是一个好的解决方案。

我想象的另一个解决方案是缓存(或保存在数据库中)每个 mark_amount 关联的所有配置文件 ID...但这似乎不是一个好主意:(

我需要一些建议来优化这个比较。 (我对其他数据库开放,缓存系统比 php/mysql 等...)

EDIT1:配置文件匹配与否的例子

https://jsfiddle.net/gafy2w4k/

这个问题需要更多详细信息,但我看到了一些对此处有用的一般改进: 首先,我没有看到任何索引,请为每个 id 创建 PRIMARY KEY 示例:

CREATE TABLE `mark` (
  `id` tinyint(1) UNSIGNED NOT NULL PRIMARY KEY, 
  ...

如果更改表格为时已晚,请使用 CREATE INDEX

其次,为了保持一致性,使用 REFERENCES 来声明外键依赖 示例:

FOREIGN KEY (id_mark) REFERENCES mark(id)

最后,运行 EXPLAIN声明你的查询,看看你可以根据结果改进什么(你可以为经常使用的查询添加索引) EXPLAIN SELECT ...

查询 return 所有 profile_mark.id_profile 具有 完全 @matched_marks 标记至少有 1 个与给定配置文件相同的数量@target_profile_id:

SELECT `match`.id_profile, count(*) as X FROM (
    SELECT DISTINCT `all`.id_profile, `all`.id_mark FROM profile_mark as `all`
    INNER JOIN profile_mark as `one` 
      ON `one`.id_mark = `all`.id_mark 
      AND `one`.id_amount = `all`.id_amount
    WHERE `all`.id_profile <> @target_profile_id
      AND `one`.id_profile = @target_profile_id
) as `match`
GROUP BY 1
HAVING X = @matched_marks; // can be >= if you need at least X matching marks

附带说明一下,id_profile smallint(2) 似乎不足以 至少 20000 个配置文件