Browse Source

Alarm query optimizations

pull/3068/head
Igor Kulikov 6 years ago
parent
commit
bbb2c0d0a1
  1. 2
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  2. 26
      dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java
  3. 19
      dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java
  4. 2
      dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java
  5. 61
      dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java

2
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -256,6 +256,8 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
log.info("Optimizing alarm relations...");
conn.createStatement().execute("DELETE from relation WHERE relation_type_group = 'ALARM' AND relation_type <> 'ALARM_ANY';");
conn.createStatement().execute("DELETE from relation WHERE relation_type_group = 'ALARM' AND relation_type = 'ALARM_ANY' " +
"AND exists(SELECT * FROM alarm WHERE alarm.id = relation.to_id AND alarm.originator_id = relation.from_id)");
log.info("Alarm relations optimized.");
for (String table : tables) {

26
dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java

@ -47,26 +47,28 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> {
@Param("alarmType") String alarmType,
Pageable pageable);
@Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a, " +
"RelationEntity re " +
"WHERE a.tenantId = :tenantId " +
"AND (a.originatorId = :affectedEntityId or (a.id = re.toId " +
"AND re.relationTypeGroup = 'ALARM' AND re.toType = 'ALARM' " +
@Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " +
"LEFT JOIN RelationEntity re ON a.id = re.toId " +
"AND re.relationTypeGroup = 'ALARM' " +
"AND re.toType = 'ALARM' " +
"AND re.fromId = :affectedEntityId " +
"AND re.fromType = :affectedEntityType)) " +
"AND re.fromType = :affectedEntityType " +
"WHERE a.tenantId = :tenantId " +
"AND (a.originatorId = :affectedEntityId or re.fromId IS NOT NULL) " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND (:alarmStatuses IS NULL OR a.status in :alarmStatuses) " +
"AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%'))" +
"OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%'))" +
"OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%')))",
countQuery = "SELECT count(a) FROM AlarmEntity a, " +
"RelationEntity re " +
"WHERE a.tenantId = :tenantId " +
"AND (a.originatorId = :affectedEntityId or (a.id = re.toId " +
"AND re.relationTypeGroup = 'ALARM' AND re.toType = 'ALARM' " +
countQuery = "SELECT count(a) FROM AlarmEntity a " +
"LEFT JOIN RelationEntity re ON a.id = re.toId " +
"AND re.relationTypeGroup = 'ALARM' " +
"AND re.toType = 'ALARM' " +
"AND re.fromId = :affectedEntityId " +
"AND re.fromType = :affectedEntityType)) " +
"AND re.fromType = :affectedEntityType " +
"WHERE a.tenantId = :tenantId " +
"AND (a.originatorId = :affectedEntityId or re.fromId IS NOT NULL) " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND (:alarmStatuses IS NULL OR a.status in :alarmStatuses) " +

19
dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java

@ -74,7 +74,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
" WHEN a.originator_type = " + EntityType.CUSTOMER.ordinal() +
" THEN (select title from customer where id = a.originator_id)" +
" WHEN a.originator_type = " + EntityType.USER.ordinal() +
" THEN (select CONCAT (first_name, ' ', last_name) from tb_user where id = a.originator_id)" +
" THEN (select email from tb_user where id = a.originator_id)" +
" WHEN a.originator_type = " + EntityType.DASHBOARD.ordinal() +
" THEN (select title from dashboard where id = a.originator_id)" +
" WHEN a.originator_type = " + EntityType.ASSET.ordinal() +
@ -101,7 +101,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
" a.propagate_relation_types as propagate_relation_types, " +
" a.type as type," + SELECT_ORIGINATOR_NAME + ", ";
public static final String JOIN_RELATIONS = ", relation r";
public static final String JOIN_RELATIONS = "left join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id and r.from_id in (:entity_ids)";
@Autowired
protected NamedParameterJdbcTemplate jdbcTemplate;
@ -111,6 +111,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId,
AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds) {
QueryContext ctx = new QueryContext();
ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList()));
StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION);
StringBuilder fromPart = new StringBuilder(" from alarm a ");
@ -118,22 +119,20 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
StringBuilder sortPart = new StringBuilder(" order by ");
boolean addAnd = false;
if (pageLink.isSearchPropagatedAlarms()) {
selectPart.append(" r.from_id as entity_id ");
selectPart.append(" CASE WHEN r.from_id IS NULL THEN a.originator_id ELSE r.from_id END as entity_id ");
fromPart.append(JOIN_RELATIONS);
wherePart.append(buildPermissionsQuery(tenantId, customerId, ctx));
addAnd = true;
} else {
selectPart.append(" a.originator_id as entity_id ");
//No need to check permissions if we select by originator.
}
EntityDataSortOrder sortOrder = pageLink.getSortOrder();
if (sortOrder != null && sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) {
String sortOrderKey = sortOrder.getKey().getKey();
sortPart.append(alarmFieldColumnMap.getOrDefault(sortOrderKey, sortOrderKey))
.append(" ").append(sortOrder.getDirection().name());
ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList()));
if (pageLink.isSearchPropagatedAlarms()) {
wherePart.append(" and (a.originator_id in (:entity_ids) or (r.relation_type_group = 'ALARM' and r.relation_type = 'ALARM_ANY' and a.id = r.to_id and r.from_id in (:entity_ids)))");
wherePart.append(" and (a.originator_id in (:entity_ids) or r.from_id IS NOT NULL)");
} else {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
@ -154,7 +153,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
}
fromPart.append(" as e(id, priority)) e ");
if (pageLink.isSearchPropagatedAlarms()) {
fromPart.append("on r.from_id = e.id");
fromPart.append("on (r.from_id IS NULL and a.originator_id = e.id) or (r.from_id IS NOT NULL and r.from_id = e.id)");
} else {
fromPart.append("on a.originator_id = e.id");
}
@ -219,12 +218,6 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
}
List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx);
log.error(dataQuery);
log.error("PARAMS:");
for (String param : ctx.getParameterNames()) {
log.error("PARAM: {}, VALUE: {}", param, ctx.getValue(param));
}
return AlarmDataAdapter.createAlarmData(pageLink, rows, totalElements, orderedEntityIds);
}

2
dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java

@ -24,7 +24,7 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClassnameFilters({
"org.thingsboard.server.dao.service.sql.AlarmServiceSqlTest"
"org.thingsboard.server.dao.service.sql.*SqlTest"
})
public class SqlDaoServiceTestSuite {

61
dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java

@ -268,16 +268,29 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
Assert.assertEquals(1, customerAlarms.getData().size());
Assert.assertEquals(deviceAlarm, customerAlarms.getData().get(0));
PageData<AlarmInfo> alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder()
.affectedEntityId(tenantDevice.getId())
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
new TimePageLink(10, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()).get();
Assert.assertNotNull(alarms.getData());
Assert.assertEquals(1, alarms.getData().size());
Assert.assertEquals(tenantAlarm, alarms.getData().get(0));
}
@Test
public void testFindAlarmUsingAlarmDataQuery() throws ExecutionException, InterruptedException {
AssetId parentId = new AssetId(Uuids.timeBased());
AssetId parentId2 = new AssetId(Uuids.timeBased());
AssetId childId = new AssetId(Uuids.timeBased());
EntityRelation relation = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE);
EntityRelation relation2 = new EntityRelation(parentId2, childId, EntityRelation.CONTAINS_TYPE);
Assert.assertTrue(relationService.saveRelationAsync(tenantId, relation).get());
Assert.assertTrue(relationService.saveRelationAsync(tenantId, relation2).get());
long ts = System.currentTimeMillis();
Alarm alarm = Alarm.builder().tenantId(tenantId).originator(childId)
@ -292,7 +305,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
AlarmDataPageLink pageLink = new AlarmDataPageLink();
pageLink.setPage(0);
pageLink.setPageSize(1);
pageLink.setPageSize(10);
pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ALARM_FIELD, "createdTime")));
pageLink.setStartTs(0L);
@ -308,7 +321,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
Assert.assertEquals(created, alarms.getData().get(0));
pageLink.setPage(0);
pageLink.setPageSize(1);
pageLink.setPageSize(10);
pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime")));
pageLink.setStartTs(0L);
@ -320,20 +333,22 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, new CustomerId(CustomerId.NULL_UUID), pageLink, Collections.singletonList(childId));
Assert.assertNotNull(alarms.getData());
Assert.assertEquals(1, alarms.getData().size());
Assert.assertEquals(created, alarms.getData().get(0));
Assert.assertEquals(created, new Alarm(alarms.getData().get(0)));
// Check child relation
pageLink.setSearchPropagatedAlarms(true);
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, new CustomerId(CustomerId.NULL_UUID), pageLink, Collections.singletonList(childId));
Assert.assertNotNull(alarms.getData());
Assert.assertEquals(1, alarms.getData().size());
Assert.assertEquals(created, new Alarm(alarms.getData().get(0)));
// Check child relation
created.setPropagate(true);
result = alarmService.createOrUpdateAlarm(created);
created = result.getAlarm();
// Check child relation
pageLink.setPage(0);
pageLink.setPageSize(1);
pageLink.setPageSize(10);
pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ALARM_FIELD, "createdTime")));
pageLink.setStartTs(0L);
@ -349,7 +364,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
// Check parent relation
pageLink.setPage(0);
pageLink.setPageSize(1);
pageLink.setPageSize(10);
pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ALARM_FIELD, "createdTime")));
pageLink.setStartTs(0L);
@ -363,8 +378,38 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
Assert.assertEquals(1, alarms.getData().size());
Assert.assertEquals(created, alarms.getData().get(0));
PageData<AlarmInfo> alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
.affectedEntityId(childId)
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
new TimePageLink(10, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()).get();
Assert.assertNotNull(alarmsInfoData.getData());
Assert.assertEquals(1, alarmsInfoData.getData().size());
Assert.assertEquals(created, alarmsInfoData.getData().get(0));
alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
.affectedEntityId(parentId)
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
new TimePageLink(10, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()).get();
Assert.assertNotNull(alarmsInfoData.getData());
Assert.assertEquals(1, alarmsInfoData.getData().size());
Assert.assertEquals(created, alarmsInfoData.getData().get(0));
alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
.affectedEntityId(parentId2)
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
new TimePageLink(10, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()).get();
Assert.assertNotNull(alarmsInfoData.getData());
Assert.assertEquals(1, alarmsInfoData.getData().size());
Assert.assertEquals(created, alarmsInfoData.getData().get(0));
pageLink.setPage(0);
pageLink.setPageSize(1);
pageLink.setPageSize(10);
pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime")));
pageLink.setStartTs(0L);
@ -382,7 +427,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
created = alarmService.findAlarmByIdAsync(tenantId, created.getId()).get();
pageLink.setPage(0);
pageLink.setPageSize(1);
pageLink.setPageSize(10);
pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ALARM_FIELD, "createdTime")));
pageLink.setStartTs(0L);

Loading…
Cancel
Save