使用不重复+过滤器时选择特定行的最快查询

时间:2018-09-30 13:44:10

标签: postgresql jpa spring-data-jpa

表格答案:

Answer ID  | User ID | Question ID | deleted
1          | 1       |  1          | f
2          | 1       |  2          | f
3          | 1       |  2          | f
4          | 1       |  1          | t
5          | 2       |  1          | f
6          | 2       |  2          | f
7          | 2       |  2          | f

我想使用最新答案(基于最高ID)选择(userID, questionID)上所有与众不同的答案,然后从此结果集中删除所有具有deleted = t的条目。

所以我的结果应该是

Answer ID  | User ID | Question ID | deleted
3          | 1       |  2          | f
5          | 2       |  1          | f
7          | 2       |  2          | f

我想我们不能使用从界面生成的查询方法来做到这一点?我改用@Query批注:

@Query("SELECT a1 FROM answer a1 WHERE ... ")
findLatestAnswers();

我想到了这个(sql提琴:http://sqlfiddle.com/#!15/02339/8/0),甚至没有使用distinctgroup byorder by。它正在完成任务,但对于较大的数据集而言似乎效率很低?什么是更快的陈述?

SELECT * FROM answer a1
WHERE NOT EXISTS ( -- where no newer answer exists
           SELECT * FROM answer a2
           WHERE a1.user_id = a2.user_id
                   AND a1.question_id = a2.question_id
                   AND a1.id < a2.id
  )
  AND a1.deleted = FALSE;

1 个答案:

答案 0 :(得分:1)

使用distinctgroup by或聚合函数没有问题。这些在数据仓库或分析软件中至关重要,在该软件中,每个请求中都会处理数百万或记录(数十亿和数万亿的大数据)。

唯一的调整是根据您的数据和查询生成索引。

scanrio所需的功能是max。您必须按以下步骤选择max中的anser_id中的user_id, question_id


解决方案1 ​​

@Query("select max(answer) from Answer answer where answer.deleted = false group by answer.userId, answer.questionId")
List<Answer> findLatestAnswersByUserQuestionNotDeleted();

此语句返回4条记录,因为,如果您不考虑删除答案,那么问题1中用户1的最新答案将变为1。

我不知道您为什么不考虑这一点,但我会照原样回答您的问题。

因此,您必须按照您的描述以编程方式发布过滤器,以便@Query变为:

@Query("select max(answer) from Answer answer group by answer.userId, answer.questionId")
List<Answer> findLatestAnswersByUserQuestion();

您同样有4条记录,因为还存在已删除并且必须以编程方式对其进行过滤


解决方案2(两个查询,因为您需要忽略已删除并且不考虑旧查询)

第1步-找到答案的id,包括已删除(仅id):

@Query("select max(answer.id) from Answer answer group by answer.userId, answer.questionId")
List<Long> findLatestAnswersId();

第2步-通过ID(不包括已删除)加载答案

List<Answer> findAllByDeletedIsFalseAndIdIn(List<Long> ids);

解决方案3(一个查询)

@Query("select answer from Answer answer where answer.deleted = false and  answer.id in (select max(inAnswer.id) from Answer inAnswer)")
List<Answer> findLastestNotDeleted()