3

我正在创建一个约会门户网站,我们将向用户询问大约 40-50 个问题,例如宗教、种姓、出生日期、食物偏好、吸烟/不吸烟。

我正在就年龄范围、宗教偏好、吸烟偏好等用户偏好提出类似的问题。

我有大约 30-40 个这样的偏好。

现在我想根据首选项集向用户显示匹配项。我想知道我应该如何设计 MySQL 表和索引。

我应该创建 1 个 user_preferences 大表并拥有所有首选项索引。应该是多列索引还是合并索引。

我应该在不同的表中保留一组问题并在获取数据时加入它们吗?米

4

2 回答 2

1

我看到这样的事情:

在此处输入图像描述

questions是要回答的问题列表。question_type是一个枚举,指示期望的答案类型(例如从question_choices、日期、数字、文本等查找) - 您希望输入的任何类型的数据。这与此表中的其他列一起,可以驱动您的输入表单。

question_answers包含预定义的问题答案列表(例如预定义的宗教列表、头发颜色或眼睛颜色等)。这可用于在输入表单上构建值的下拉列表。

users非常不言自明。

user_characteristics包含我对调查问卷的回答列表。该weight栏表明寻找我的人有相同的答案对我来说有多重要。question_choices_id如果答案来自从表中构建的选择列表,则会填充question_choices。否则question_choices_id将为NULL。反之亦然valuevalue如果答案来自从表中构建的选择列表,则为 NULL question_choices。否则value将包含用户对问题的手工制作的答案。

user_preferences包含我正在寻找的问卷的答案。该weight栏表明我正在寻找的人有相同的答案对我来说有多重要。question_choices_id和列的value行为与表中的相同user_characteristics

查找我的匹配项的 SQL 可能类似于:

SELECT uc.id
      ,SUM(up.weight)                   AS my_weighted_score_of_them
      ,SUM(uc.weight)                   AS their_weighted_score_of_me
      ,SUM(up.weight) + SUM(uc.weight)  AS combined_weighted_score
  FROM user_preferences        up
  JOIN user_characteristics    uc
    ON uc.questions_id           = up.questions_id
   AND uc.question_choices_id    = up.question_choices_id
   AND uc.value                  = up.value
   AND uc.users_id              != up.users_id
 WHERE up.users_id               = me.id
 GROUP BY uc.id
 ORDER BY SUM(up.weight) + SUM(uc.weight) DESC
         ,SUM(up.weight) DESC
         ,SUM(uc.weight) DESC

出于性能原因,建议对 user_characteristics(id、question_id、question_choices_id、value 和 user_id) 使用索引和在 user_preferences(id、question_id、question_choices_id、value 和 user_id) 上使用索引。

请注意,上述 SQL 将为每个用户返回一行,但发出请求的用户除外。这当然是不可取的。因此,人们可能会考虑添加HAVING SUM(up.weight) + SUM(uc.weight) > :some_minimum_value- 或其他方式来进一步过滤结果。

进一步的调整可能包括只返回与我一样重视答案的人(即他们的特征体重> =我的体重偏好权重。

于 2013-09-20T18:55:30.073 回答
1

我认为这可能是EAV的情况:

在此处输入图像描述

您应该能够按降序(从最匹配到最不匹配)获得匹配的用户对,类似于:

SELECT *
FROM (
    SELECT U1.USER_ID, U2.USER_ID, COUNT(*) MATCH_COUNT
    FROM USER U1
        JOIN USER_PREFERENCE P1
            ON (U1.USER_ID = P1.USER_ID)
        JOIN USER_PREFERENCE P2
            ON (P1.NAME = P2.NAME AND P1.VALUE = P2.VALUE)
        JOIN USER U2
            ON (P2.USER_ID = U2.USER_ID)
    WHERE U1.USER_ID < U2.USER_ID -- To avoid matching the user with herself and duplicated pairs with flipped user IDs.
    GROUP BY U1.USER_ID, U2.USER_ID
) Q
ORDER BY MATCH_COUNT DESC

这只是通过它们的确切值匹配偏好。您可能希望为范围或类似枚举的值创建额外的“首选项”表,并P1.VALUE = P2.VALUE相应地进行替换。如果匹配的是 USER 表中的数据(例如用户的年龄是否属于其他用户的首选年龄范围),您可能还需要特殊处理。

{NAME, VALUE}请注意旨在提供帮助的索引P1.NAME = P2.NAME AND P1.VALUE = P2.VALUE。InnoDB 表是聚集的,一个后果是二级索引包含 PK 字段的副本——在这种情况下会导致索引I1完全覆盖表。MySQL 是否会真正使用它是另一回事 - 一如既往地查看查询计划并衡量代表性数据......

于 2013-09-14T01:13:50.443 回答