]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7187 Fix perf issue in selectByQuery
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 14 Apr 2016 09:06:49 +0000 (11:06 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 14 Apr 2016 13:52:25 +0000 (15:52 +0200)
Replace usage of RowBounds by SQL pagination

sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java
sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java
sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml
sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java

index 050389c885808d77d9d7666bd75760f5953281a0..e32a1be153588413fdd55676f2dccb6b18803315 100644 (file)
@@ -69,7 +69,7 @@ public class CeActivityDao implements Dao {
       return Collections.emptyList();
     }
 
-    return mapper(dbSession).selectByQuery(query, new RowBounds(offset, pageSize));
+    return mapper(dbSession).selectByQuery(query, offset, pageSize);
   }
 
   public int countByQuery(DbSession dbSession, CeTaskQuery query) {
index a59254827ed49853741de9e255f207f163cb792a..ea4652d4185d108b259b50cab849310913dde709 100644 (file)
@@ -33,7 +33,7 @@ public interface CeActivityMapper {
 
   List<CeActivityDto> selectByComponentUuid(@Param("componentUuid") String componentUuid);
 
-  List<CeActivityDto> selectByQuery(@Param("query") CeTaskQuery query, RowBounds rowBounds);
+  List<CeActivityDto> selectByQuery(@Param("query") CeTaskQuery query, @Param("offset") int offset, @Param("pageSize") int pageSize);
 
   List<CeActivityDto> selectOlderThan(@Param("beforeDate") long beforeDate);
 
index d86c8f73212e24a02822379998bb6e15a3ab5003..08247b4faa17cefcef1fdb20bd6725706b41003c 100644 (file)
@@ -4,6 +4,7 @@
 <mapper namespace="org.sonar.db.ce.CeActivityMapper">
 
   <sql id="columns">
+    ca.id,
     ca.uuid,
     ca.task_type as taskType,
     ca.component_uuid as componentUuid,
   </select>
 
   <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.ce.CeActivityDto">
-    select
+    SELECT
     <include refid="columns"/>
     <include refid="sqlSelectByQuery" />
-    order by ca.submitted_at desc, ca.id desc
+    ORDER BY ca.id desc
+    LIMIT #{pageSize} OFFSET #{offset}
+  </select>
+
+  <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.ce.CeActivityDto" databaseId="mssql">
+    SELECT * FROM (
+    SELECT ROW_NUMBER() OVER(ORDER BY id desc) AS NUMBER,
+      <include refid="columns"/>
+      <include refid="sqlSelectByQuery" />
+      ) AS QUERY
+    WHERE NUMBER BETWEEN (#{offset} * #{pageSize} + 1) AND ((#{offset} + 1) * #{pageSize})
+    ORDER BY id desc
+  </select>
+
+  <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.ce.CeActivityDto" databaseId="oracle">
+    SELECT * FROM (
+      SELECT ROWNUM AS rn, t.* FROM (
+        SELECT
+        <include refid="columns"/>
+        <include refid="sqlSelectByQuery" />
+        ORDER BY ca.id desc
+      ) t
+    ) t
+    WHERE rn BETWEEN (#{offset} * #{pageSize} + 1) AND ((#{offset} + 1) * #{pageSize})
   </select>
 
   <select id="countByQuery" parameterType="map" resultType="int">
index 8b2b03adde9eedc8f9ff0a131698e704f17db9ab..bb92b76097bf3ed7ccb07bbc6c7fe35972d6c93c 100644 (file)
  */
 package org.sonar.db.ce;
 
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
 import java.util.Collections;
 import java.util.List;
+import javax.annotation.Nonnull;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.utils.internal.TestSystem2;
@@ -31,7 +34,6 @@ import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.db.ce.CeTaskTypes.REPORT;
 
-
 public class CeActivityDaoTest {
 
   TestSystem2 system2 = new TestSystem2().setNow(1_450_000_000_000L);
@@ -122,6 +124,22 @@ public class CeActivityDaoTest {
     assertThat(dtos).extracting("uuid").containsExactly("TASK_2");
   }
 
+  @Test
+  public void selectByQuery_is_paginated_and_return_results_sorted_from_last_to_first() {
+    insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insert("TASK_2", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED);
+    insert("TASK_3", REPORT, "PROJECT_2", CeActivityDto.Status.SUCCESS);
+    insert("TASK_4", "views", null, CeActivityDto.Status.SUCCESS);
+
+    assertThat(selectPageOfUuids(0, 1)).containsExactly("TASK_4");
+    assertThat(selectPageOfUuids(1, 1)).containsExactly("TASK_3");
+    assertThat(selectPageOfUuids(0, 3)).containsExactly("TASK_4", "TASK_3", "TASK_2");
+    assertThat(selectPageOfUuids(0, 4)).containsExactly("TASK_4", "TASK_3", "TASK_2", "TASK_1");
+    assertThat(selectPageOfUuids(0, 100)).containsExactly("TASK_4", "TASK_3", "TASK_2", "TASK_1");
+    assertThat(selectPageOfUuids(0, 0)).isEmpty();
+    assertThat(selectPageOfUuids(10, 2)).isEmpty();
+  }
+
   @Test
   public void test_countByQuery() {
     insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
@@ -262,4 +280,17 @@ public class CeActivityDaoTest {
     system2.setNow(date);
     underTest.insert(db.getSession(), dto);
   }
+
+  private List<String> selectPageOfUuids(int offset, int pageSize) {
+    return FluentIterable.from(underTest.selectByQuery(db.getSession(), new CeTaskQuery(), offset, pageSize)).transform(CeActivityToUuid.INSTANCE).toList();
+  }
+
+  private enum CeActivityToUuid implements Function<CeActivityDto, String> {
+    INSTANCE;
+
+    @Override
+    public String apply(@Nonnull CeActivityDto input) {
+      return input.getUuid();
+    }
+  }
 }