2

我会尽力解释我的问题。

我必须比较相同类型的数据,这些数据保存在 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;

每次新数据到达时,都会创建一个配置文件,并在必要时创建一个新标记和一个新数量。

  • 配置文件具有固定数量的标记(9、16、24)
  • 对于每个配置文件,其每个标记都可以有 0、1 或 2 个数量

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

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

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

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

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

EDIT1:配置文件匹配或不匹配的示例 8 标记

https://jsfiddle.net/gafy2w4k/

4

2 回答 2

2

查询返回所有profile_mark.id_profile具有至少 1 个与具有给定的配置文件相同数量的完全 标记:@matched_marks@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

作为旁注,对于至少 20000 个配置文件id_profile smallint(2)似乎不够。

于 2017-08-24T14:59:58.893 回答
0

这个问题需要更多细节,但我看到了一些有用的一般改进:首先,我没有看到任何索引,请为每个 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 ...

于 2017-08-24T14:35:53.307 回答