Reduce DB roundtrips for revincludes (#1937)

* Reduce DB roundtrips for revincludes

* Add changelog
This commit is contained in:
James Agnew 2020-06-23 16:26:04 -04:00 committed by GitHub
parent f88298a1fb
commit 6825d2fcf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 4 deletions

View File

@ -0,0 +1,6 @@
---
type: perf
issue: 1937
title: Due to an inefficient SQL statement when performing searches with large numbers of _revincludes where the resources
have tags, a large number of database roundtrips were produced when searching. This has been streamlined, greatly improving
the response times for some searches.

View File

@ -32,7 +32,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTag;
public interface IResourceTagDao extends JpaRepository<ResourceTag, Long> {
@Query("" +
"SELECT t FROM ResourceTag t " +
"INNER JOIN TagDefinition td ON (td.myId = t.myTagId) " +
"INNER JOIN FETCH t.myTag td " +
"WHERE t.myResourceId in (:pids)")
Collection<ResourceTag> findByResourceIds(@Param("pids") Collection<Long> pids);

View File

@ -4,11 +4,13 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.util.SqlQuery;
import ca.uhn.fhir.jpa.util.TestUtil;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.ReferenceParam;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.CareTeam;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.IdType;
@ -538,6 +540,53 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
}
@Test
public void testSearchOnReverseInclude() {
Patient patient = new Patient();
patient.getMeta().addTag("http://system", "value1", "display");
patient.setId("P1");
patient.getNameFirstRep().setFamily("FAM1");
myPatientDao.update(patient);
patient = new Patient();
patient.setId("P2");
patient.getMeta().addTag("http://system", "value1", "display");
patient.getNameFirstRep().setFamily("FAM2");
myPatientDao.update(patient);
for (int i = 0; i < 3; i++) {
CareTeam ct = new CareTeam();
ct.setId("CT1-" + i);
ct.getMeta().addTag("http://system", "value11", "display");
ct.getSubject().setReference("Patient/P1");
myCareTeamDao.update(ct);
ct = new CareTeam();
ct.setId("CT2-" + i);
ct.getMeta().addTag("http://system", "value22", "display");
ct.getSubject().setReference("Patient/P2");
myCareTeamDao.update(ct);
}
SearchParameterMap map = SearchParameterMap
.newSynchronous()
.addRevInclude(CareTeam.INCLUDE_SUBJECT)
.setSort(new SortSpec(Patient.SP_NAME));
myCaptureQueriesListener.clear();
IBundleProvider outcome = myPatientDao.search(map);
assertThat(toUnqualifiedVersionlessIdValues(outcome), containsInAnyOrder(
"Patient/P1", "CareTeam/CT1-0", "CareTeam/CT1-1","CareTeam/CT1-2",
"Patient/P2", "CareTeam/CT2-0", "CareTeam/CT2-1","CareTeam/CT2-2"
));
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
assertEquals(0, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
}
@Test
public void testTransactionWithMultipleReferences() {
Bundle input = new Bundle();

View File

@ -42,7 +42,7 @@ public class ResourceTag extends BaseTag {
@Column(name = "PID")
private Long myId;
@ManyToOne(cascade = {})
@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", foreignKey = @ForeignKey(name = "FK_RESTAG_RESOURCE"))
private ResourceTable myResource;

View File

@ -159,8 +159,9 @@ public class SearchParameterMap implements Serializable {
}
}
public void addRevInclude(Include theInclude) {
public SearchParameterMap addRevInclude(Include theInclude) {
getRevIncludes().add(theInclude);
return this;
}
private void addUrlIncludeParams(StringBuilder b, String paramName, Set<Include> theList) {
@ -268,8 +269,9 @@ public class SearchParameterMap implements Serializable {
return mySort;
}
public void setSort(SortSpec theSort) {
public SearchParameterMap setSort(SortSpec theSort) {
mySort = theSort;
return this;
}
/**