]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4368 Highly improve performance of the project deletion operation
authorJulien HENRY <julien.henry@sonarsource.com>
Wed, 12 Jun 2013 10:44:58 +0000 (12:44 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Wed, 12 Jun 2013 10:44:58 +0000 (12:44 +0200)
sonar-core/src/main/java/org/sonar/core/purge/PurgeCommands.java
sonar-core/src/main/java/org/sonar/core/purge/PurgeDao.java
sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java
sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml

index dc7ee6e04540e90a2d6584478b524f0955472bfd..e37b0fef7047ac8cfb1b22fb8f0d9d1b6c7e9a35 100644 (file)
@@ -21,12 +21,15 @@ package org.sonar.core.purge;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import org.apache.ibatis.session.SqlSession;
 
 import java.util.List;
 
 class PurgeCommands {
   private static final int MAX_CHARACTERISTICS_PER_QUERY = 1000;
+  private static final int MAX_SNAPSHOTS_PER_QUERY = 1000;
+  private static final int MAX_RESOURCES_PER_QUERY = 1000;
 
   private final SqlSession session;
   private final PurgeMapper purgeMapper;
@@ -48,103 +51,104 @@ class PurgeCommands {
   }
 
   void deleteResources(List<Long> resourceIds) {
+    List<List<Long>> resourceIdsPartition = Lists.partition(resourceIds, MAX_RESOURCES_PER_QUERY);
     // Note : do not merge the delete statements into a single loop of resource ids. It's
     // voluntarily grouped by tables in order to benefit from JDBC batch mode.
     // Batch requests can only relate to the same PreparedStatement.
 
-    for (Long resourceId : resourceIds) {
-      deleteSnapshots(PurgeSnapshotQuery.create().setResourceId(resourceId));
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      deleteSnapshots(purgeMapper.selectSnapshotIdsByResource(partResourceIds));
     }
 
     // possible missing optimization: filter requests according to resource scope
 
     profiler.start("deleteResourceLinks (project_links)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceLinks(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceLinks(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceProperties (properties)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceProperties(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceProperties(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceIndex (resource_index)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceIndex(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceIndex(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceGroupRoles (group_roles)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceGroupRoles(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceGroupRoles(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceUserRoles (user_roles)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceUserRoles(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceUserRoles(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceManualMeasures (manual_measures)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceManualMeasures(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceManualMeasures(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceIssueChanges (issue_changes)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceIssueChanges(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceIssueChanges(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceIssues (issues)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceIssues(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceIssues(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceActionPlans (action_plans)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceActionPlans(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceActionPlans(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceEvents (events)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceEvents(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceEvents(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResourceGraphs (graphs)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResourceGraphs(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResourceGraphs(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteResource (projects)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteResource(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteResource(partResourceIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteAuthors (authors)");
-    for (Long resourceId : resourceIds) {
-      purgeMapper.deleteAuthors(resourceId);
+    for (List<Long> partResourceIds : resourceIdsPartition) {
+      purgeMapper.deleteAuthors(partResourceIds);
     }
     session.commit();
     profiler.stop();
@@ -156,40 +160,42 @@ class PurgeCommands {
 
   private void deleteSnapshots(final List<Long> snapshotIds) {
 
-    deleteSnapshotDependencies(snapshotIds);
+    List<List<Long>> snapshotIdsPartition = Lists.partition(snapshotIds, MAX_SNAPSHOTS_PER_QUERY);
 
-    deleteSnapshotDuplications(snapshotIds);
+    deleteSnapshotDependencies(snapshotIdsPartition);
+
+    deleteSnapshotDuplications(snapshotIdsPartition);
 
     profiler.start("deleteSnapshotEvents (events)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshotEvents(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshotEvents(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteSnapshotMeasureData (measure_data)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshotMeasureData(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshotMeasureData(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
 
     profiler.start("deleteSnapshotMeasures (project_measures)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshotMeasures(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshotMeasures(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
 
-    deleteSnapshotSources(snapshotIds);
+    deleteSnapshotSources(snapshotIdsPartition);
 
-    deleteSnapshotGraphs(snapshotIds);
+    deleteSnapshotGraphs(snapshotIdsPartition);
 
-    deleteSnapshotData(snapshotIds);
+    deleteSnapshotData(snapshotIdsPartition);
 
     profiler.start("deleteSnapshot (snapshots)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshot(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshot(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
@@ -201,22 +207,23 @@ class PurgeCommands {
 
   private void purgeSnapshots(final List<Long> snapshotIds) {
     // note that events are not deleted
+    List<List<Long>> snapshotIdsPartition = Lists.partition(snapshotIds, MAX_SNAPSHOTS_PER_QUERY);
 
-    deleteSnapshotDependencies(snapshotIds);
+    deleteSnapshotDependencies(snapshotIdsPartition);
 
-    deleteSnapshotDuplications(snapshotIds);
+    deleteSnapshotDuplications(snapshotIdsPartition);
 
-    deleteSnapshotSources(snapshotIds);
+    deleteSnapshotSources(snapshotIdsPartition);
 
-    deleteSnapshotGraphs(snapshotIds);
+    deleteSnapshotGraphs(snapshotIdsPartition);
 
-    deleteSnapshotData(snapshotIds);
+    deleteSnapshotData(snapshotIdsPartition);
 
     profiler.start("deleteSnapshotWastedMeasures (project_measures)");
     List<Long> metricIdsWithoutHistoricalData = purgeMapper.selectMetricIdsWithoutHistoricalData();
     if (!metricIdsWithoutHistoricalData.isEmpty()) {
-      for (Long snapshotId : snapshotIds) {
-        purgeMapper.deleteSnapshotWastedMeasures(snapshotId, metricIdsWithoutHistoricalData);
+      for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+        purgeMapper.deleteSnapshotWastedMeasures(partSnapshotIds, metricIdsWithoutHistoricalData);
       }
       session.commit();
     }
@@ -225,10 +232,10 @@ class PurgeCommands {
     profiler.start("deleteSnapshotMeasuresOnCharacteristics (project_measures)");
     List<Long> characteristicIds = purgeMapper.selectCharacteristicIdsToPurge();
     if (!characteristicIds.isEmpty()) {
-      for (Long snapshotId : snapshotIds) {
+      for (List<Long> partSnapshotIds : snapshotIdsPartition) {
         // SONAR-3641 We cannot process all characteristics at once
         for (List<Long> ids : Iterables.partition(characteristicIds, MAX_CHARACTERISTICS_PER_QUERY)) {
-          purgeMapper.deleteSnapshotMeasuresOnCharacteristics(snapshotId, ids);
+          purgeMapper.deleteSnapshotMeasuresOnCharacteristics(partSnapshotIds, ids);
         }
       }
       session.commit();
@@ -243,46 +250,46 @@ class PurgeCommands {
     profiler.stop();
   }
 
-  private void deleteSnapshotData(final List<Long> snapshotIds) {
+  private void deleteSnapshotData(final List<List<Long>> snapshotIdsPartition) {
     profiler.start("deleteSnapshotData (snapshot_data)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshotData(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshotData(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
   }
 
-  private void deleteSnapshotGraphs(final List<Long> snapshotIds) {
+  private void deleteSnapshotGraphs(final List<List<Long>> snapshotIdsPartition) {
     profiler.start("deleteSnapshotGraphs (graphs)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshotGraphs(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshotGraphs(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
   }
 
-  private void deleteSnapshotSources(final List<Long> snapshotIds) {
+  private void deleteSnapshotSources(final List<List<Long>> snapshotIdsPartition) {
     profiler.start("deleteSnapshotSource (snapshot_sources)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshotSource(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshotSource(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
   }
 
-  private void deleteSnapshotDuplications(final List<Long> snapshotIds) {
+  private void deleteSnapshotDuplications(final List<List<Long>> snapshotIdsPartition) {
     profiler.start("deleteSnapshotDuplications (duplications_index)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshotDuplications(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshotDuplications(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
   }
 
-  private void deleteSnapshotDependencies(final List<Long> snapshotIds) {
+  private void deleteSnapshotDependencies(final List<List<Long>> snapshotIdsPartition) {
     profiler.start("deleteSnapshotDependencies (dependencies)");
-    for (Long snapshotId : snapshotIds) {
-      purgeMapper.deleteSnapshotDependencies(snapshotId);
+    for (List<Long> partSnapshotIds : snapshotIdsPartition) {
+      purgeMapper.deleteSnapshotDependencies(partSnapshotIds);
     }
     session.commit();
     profiler.stop();
index 9c848aabf23d365d5eac313fedf5ff4dfd3a9c06..fd8c0cfecc263fbd8859a731e155a924f8de1ee5 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.resource.ResourceDao;
 import org.sonar.core.resource.ResourceDto;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
@@ -50,7 +51,6 @@ public class PurgeDao {
     this.profiler = profiler;
   }
 
-
   public PurgeDao purge(PurgeConfiguration conf) {
     SqlSession session = mybatis.openBatchSession();
     PurgeMapper mapper = session.getMapper(PurgeMapper.class);
@@ -83,32 +83,32 @@ public class PurgeDao {
     if (hasAbortedBuilds(project.getId(), commands)) {
       LOG.info("<- Delete aborted builds");
       PurgeSnapshotQuery query = PurgeSnapshotQuery.create()
-        .setIslast(false)
-        .setStatus(new String[]{"U"})
-        .setRootProjectId(project.getId());
+          .setIslast(false)
+          .setStatus(new String[] {"U"})
+          .setRootProjectId(project.getId());
       commands.deleteSnapshots(query);
     }
   }
 
   private boolean hasAbortedBuilds(Long projectId, PurgeCommands commands) {
     PurgeSnapshotQuery query = PurgeSnapshotQuery.create()
-      .setIslast(false)
-      .setStatus(new String[]{"U"})
-      .setResourceId(projectId);
+        .setIslast(false)
+        .setStatus(new String[] {"U"})
+        .setResourceId(projectId);
     return !commands.selectSnapshotIds(query).isEmpty();
   }
 
   private void purge(ResourceDto project, String[] scopesWithoutHistoricalData, PurgeCommands purgeCommands) {
     List<Long> projectSnapshotIds = purgeCommands.selectSnapshotIds(
-      PurgeSnapshotQuery.create().setResourceId(project.getId()).setIslast(false).setNotPurged(true)
-    );
+        PurgeSnapshotQuery.create().setResourceId(project.getId()).setIslast(false).setNotPurged(true)
+        );
     for (final Long projectSnapshotId : projectSnapshotIds) {
       LOG.info("<- Clean snapshot " + projectSnapshotId);
       if (!ArrayUtils.isEmpty(scopesWithoutHistoricalData)) {
         PurgeSnapshotQuery query = PurgeSnapshotQuery.create()
-          .setIslast(false)
-          .setScopes(scopesWithoutHistoricalData)
-          .setRootSnapshotId(projectSnapshotId);
+            .setIslast(false)
+            .setScopes(scopesWithoutHistoricalData)
+            .setRootSnapshotId(projectSnapshotId);
         purgeCommands.deleteSnapshots(query);
       }
 
@@ -170,7 +170,7 @@ public class PurgeDao {
 
   @VisibleForTesting
   void disableResource(long resourceId, PurgeMapper mapper) {
-    mapper.deleteResourceIndex(resourceId);
+    mapper.deleteResourceIndex(Arrays.asList(resourceId));
     mapper.setSnapshotIsLastToFalse(resourceId);
     mapper.disableResource(resourceId);
   }
index 66b1550780e1041ad92253a2097ae80192600df5..d7e3c2d034fac515625a712919a918670fc1a12c 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.core.purge;
 import org.apache.ibatis.annotations.Param;
 
 import javax.annotation.Nullable;
+
 import java.util.Date;
 import java.util.List;
 
@@ -29,61 +30,65 @@ public interface PurgeMapper {
 
   List<Long> selectSnapshotIds(PurgeSnapshotQuery query);
 
+  List<Long> selectSnapshotIdsByResource(@Param("resourceIds") List<Long> resourceIds);
+
   List<Long> selectProjectIdsByRootId(long rootResourceId);
 
-  void deleteSnapshot(long snapshotId);
+  void deleteSnapshot(@Param("snapshotIds") List<Long> snapshotIds);
 
-  void deleteSnapshotDependencies(long snapshotId);
+  void deleteSnapshotDependencies(@Param("snapshotIds") List<Long> snapshotIds);
 
-  void deleteSnapshotDuplications(long snapshotId);
+  void deleteSnapshotDuplications(@Param("snapshotIds") List<Long> snapshotIds);
 
-  void deleteSnapshotEvents(long snapshotId);
+  void deleteSnapshotEvents(@Param("snapshotIds") List<Long> snapshotIds);
 
-  void deleteSnapshotMeasures(long snapshotId);
+  void deleteSnapshotMeasures(@Param("snapshotIds") List<Long> snapshotIds);
 
-  void deleteSnapshotMeasureData(long snapshotId);
+  void deleteSnapshotMeasureData(@Param("snapshotIds") List<Long> snapshotIds);
 
-  void deleteSnapshotSource(long snapshotId);
+  void deleteSnapshotSource(@Param("snapshotIds") List<Long> snapshotIds);
 
-  void deleteSnapshotGraphs(long snapshotId);
+  void deleteSnapshotGraphs(@Param("snapshotIds") List<Long> snapshotIds);
+
+  void deleteSnapshotData(@Param("snapshotIds") List<Long> snapshotIds);
 
   List<Long> selectMetricIdsWithoutHistoricalData();
 
   List<Long> selectCharacteristicIdsToPurge();
 
-  void deleteSnapshotWastedMeasures(@Param("sid") long snapshotId, @Param("mids") List<Long> metricIds);
+  void deleteSnapshotWastedMeasures(@Param("snapshotIds") List<Long> snapshotIds, @Param("mids") List<Long> metricIds);
 
-  void deleteSnapshotMeasuresOnCharacteristics(@Param("sid") long snapshotId, @Param("cids") List<Long> characteristicIds);
+  void deleteSnapshotMeasuresOnCharacteristics(@Param("snapshotIds") List<Long> snapshotIds, @Param("cids") List<Long> characteristicIds);
 
   void updatePurgeStatusToOne(long snapshotId);
 
   void disableResource(long resourceId);
 
-  void deleteResourceIndex(long resourceId);
+  void deleteResourceIndex(@Param("resourceIds") List<Long> resourceIds);
 
   void deleteEvent(long eventId);
 
   void setSnapshotIsLastToFalse(long resourceId);
 
-  void deleteResourceLinks(long resourceId);
+  void deleteResourceLinks(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceProperties(long resourceId);
+  void deleteResourceProperties(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResource(long resourceId);
+  void deleteResource(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceGroupRoles(long resourceId);
+  void deleteResourceGroupRoles(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceUserRoles(long resourceId);
+  void deleteResourceUserRoles(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceManualMeasures(long resourceId);
+  void deleteResourceManualMeasures(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceEvents(long resourceId);
+  void deleteResourceEvents(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceActionPlans(long resourceId);
+  void deleteResourceActionPlans(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceGraphs(long resourceId);
+  void deleteResourceGraphs(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteAuthors(long developerId);
+  void deleteAuthors(@Param("resourceIds") List<Long> resourceIds);
 
   List<PurgeableSnapshotDto> selectPurgeableSnapshotsWithEvents(long resourceId);
 
@@ -91,11 +96,9 @@ public interface PurgeMapper {
 
   List<Long> selectResourceIdsByRootId(long rootProjectId);
 
-  void deleteSnapshotData(long snapshotId);
-
-  void deleteResourceIssueChanges(long resourceId);
+  void deleteResourceIssueChanges(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceIssues(long resourceId);
+  void deleteResourceIssues(@Param("resourceIds") List<Long> resourceIds);
 
   void deleteOldClosedIssueChanges(@Param("rootProjectId") long rootProjectId, @Nullable @Param("toDate") Date toDate);
 
index 936acac2cdfdc80e0368d008952e4400a686cd02..ae75f3c77d6128a7125192c5b8699ab2026ca8d8 100644 (file)
       </if>
     </where>
   </select>
+  
+  <select id="selectSnapshotIdsByResource" parameterType="map" resultType="long">
+    select s.id from snapshots s
+    <where>
+      s.project_id in
+      <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+        #{resourceId}
+      </foreach>
+    </where>
+  </select>
 
   <select id="selectPurgeableSnapshotsWithEvents" parameterType="long" resultType="PurgeableSnapshot">
     select s.id as "snapshotId", s.created_at as "date", ${_true} as "hasEvents", islast as "isLast" from
     select id from projects where root_id=#{id} or id=#{id}
   </select>
 
-  <delete id="deleteSnapshotMeasures" parameterType="long">
-    delete from project_measures where snapshot_id=#{id}
+  <delete id="deleteSnapshotMeasures" parameterType="map">
+    delete from project_measures where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
-  <delete id="deleteSnapshotMeasureData" parameterType="long">
-    delete from measure_data where snapshot_id=#{id}
+  <delete id="deleteSnapshotMeasureData" parameterType="map">
+    delete from measure_data where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
-  <delete id="deleteSnapshotSource" parameterType="long">
-    delete from snapshot_sources where snapshot_id=#{id}
+  <delete id="deleteSnapshotSource" parameterType="map">
+    delete from snapshot_sources where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
-  <delete id="deleteSnapshotGraphs" parameterType="long">
-    delete from graphs where snapshot_id=#{id}
+  <delete id="deleteSnapshotGraphs" parameterType="map">
+    delete from graphs where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
-  <delete id="deleteSnapshotDependencies" parameterType="long">
-    delete from dependencies where from_snapshot_id=#{id} or to_snapshot_id=#{id} or project_snapshot_id=#{id}
+  <delete id="deleteSnapshotDependencies" parameterType="map">
+    delete from dependencies where from_snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
+    or to_snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
+    or project_snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
-  <delete id="deleteSnapshotDuplications" parameterType="long">
-    delete from duplications_index where snapshot_id=#{id}
+  <delete id="deleteSnapshotDuplications" parameterType="map">
+    delete from duplications_index where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
-  <delete id="deleteSnapshotEvents" parameterType="long">
-    delete from events where snapshot_id=#{id}
+  <delete id="deleteSnapshotEvents" parameterType="map">
+    delete from events where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
-  <delete id="deleteSnapshot" parameterType="long">
-    delete from snapshots where id=#{id}
+  <delete id="deleteSnapshot" parameterType="map">
+    delete from snapshots where id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
   <delete id="deleteSnapshotWastedMeasures" parameterType="map">
-    delete from project_measures where snapshot_id=#{sid} and
+    delete from project_measures where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
+    and
     (rule_id is not null or person_id is not null or metric_id in
     <foreach item="mid" index="index" collection="mids" open="(" separator="," close=")">#{mid}</foreach>
     )
   </delete>
 
   <delete id="deleteSnapshotMeasuresOnCharacteristics" parameterType="map">
-    delete from project_measures where snapshot_id=#{sid}
+    delete from project_measures where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
     and (
     <foreach item="cid" index="index" collection="cids" open="" separator=" OR " close="">characteristic_id=#{cid}</foreach>
     )
     update projects set enabled=${_false} where id=#{id}
   </update>
 
-  <delete id="deleteResourceIndex" parameterType="long">
-    delete from resource_index where resource_id=#{id}
+  <delete id="deleteResourceIndex" parameterType="map">
+    delete from resource_index where resource_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteEvent" parameterType="long">
-    delete from events where id=#{id}
+  <delete id="deleteEvent" parameterType="map">
+    delete from events where id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceLinks" parameterType="long">
-    delete from project_links where project_id=#{id}
+  <delete id="deleteResourceLinks" parameterType="map">
+    delete from project_links where project_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceProperties" parameterType="long">
-    delete from properties where resource_id=#{id}
+  <delete id="deleteResourceProperties" parameterType="map">
+    delete from properties where resource_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResource" parameterType="long">
-    delete from projects where id=#{id}
+  <delete id="deleteResource" parameterType="map">
+    delete from projects where id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceGroupRoles" parameterType="long">
-    delete from group_roles where resource_id=#{id}
+  <delete id="deleteResourceGroupRoles" parameterType="map">
+    delete from group_roles where resource_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceUserRoles" parameterType="long">
-    delete from user_roles where resource_id=#{id}
+  <delete id="deleteResourceUserRoles" parameterType="map">
+    delete from user_roles where resource_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceManualMeasures" parameterType="long">
-    delete from manual_measures where resource_id=#{id}
+  <delete id="deleteResourceManualMeasures" parameterType="map">
+    delete from manual_measures where resource_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceEvents" parameterType="long">
-    delete from events where resource_id=#{id}
+  <delete id="deleteResourceEvents" parameterType="map">
+    delete from events where resource_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceActionPlans" parameterType="long">
-    delete from action_plans where project_id=#{id}
+  <delete id="deleteResourceActionPlans" parameterType="map">
+    delete from action_plans where project_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceGraphs" parameterType="long">
-    delete from graphs where resource_id=#{id}
+  <delete id="deleteResourceGraphs" parameterType="map">
+    delete from graphs where resource_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteAuthors" parameterType="long">
-    delete from authors where person_id=#{id}
+  <delete id="deleteAuthors" parameterType="map">
+    delete from authors where person_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
   <update id="setSnapshotIsLastToFalse" parameterType="long">
     update snapshots set islast=${_false} where project_id=#{id}
   </update>
 
-  <delete id="deleteSnapshotData" parameterType="long">
-    delete from snapshot_data where snapshot_id=#{id}
+  <delete id="deleteSnapshotData" parameterType="map">
+    delete from snapshot_data where snapshot_id in
+    <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+        #{snapshotId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceIssueChanges" parameterType="long">
+  <delete id="deleteResourceIssueChanges" parameterType="map">
     delete from issue_changes ic
-    where exists (select * from issues i where i.kee=ic.issue_key and i.component_id=#{id})
+    where exists (select * from issues i where i.kee=ic.issue_key and i.component_id in
+      <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+        #{resourceId}
+      </foreach>
+    )
   </delete>
 
   <!-- Mssql -->
-  <delete id="deleteResourceIssueChanges" databaseId="mssql" parameterType="long">
+  <delete id="deleteResourceIssueChanges" databaseId="mssql" parameterType="map">
     delete issue_changes from issue_changes
     inner join issues on issue_changes.issue_key=issues.kee
-    where issues.component_id=#{id}
+    where issues.component_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
   <!-- Mysql -->
-  <delete id="deleteResourceIssueChanges" databaseId="mysql" parameterType="long">
-    delete ic from issue_changes as ic, issues as i where ic.issue_key=i.kee and i.component_id=#{id}
+  <delete id="deleteResourceIssueChanges" databaseId="mysql" parameterType="map">
+    delete ic from issue_changes as ic, issues as i where ic.issue_key=i.kee and i.component_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>
 
-  <delete id="deleteResourceIssues" parameterType="long">
-    delete from issues where component_id=#{id}
+  <delete id="deleteResourceIssues" parameterType="map">
+    delete from issues where component_id in
+    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
+      #{resourceId}
+    </foreach>
   </delete>