Add DAO setting to specify maximum query size

This commit is contained in:
James Agnew 2017-06-16 09:41:45 -04:00
parent 69849dd3c5
commit d40c5fa5e3
4 changed files with 88 additions and 25 deletions

View File

@ -104,7 +104,7 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
TypedQuery<Long> q = myEntityManager.createQuery("SELECT t.myId FROM ResourceTable t WHERE t.myIndexStatus IS NULL", Long.class); TypedQuery<Long> q = myEntityManager.createQuery("SELECT t.myId FROM ResourceTable t WHERE t.myIndexStatus IS NULL", Long.class);
ourLog.info("Beginning indexing query with maximum {}", maxResult); ourLog.debug("Beginning indexing query with maximum {}", maxResult);
q.setMaxResults(maxResult); q.setMaxResults(maxResult);
Collection<Long> resources = q.getResultList(); Collection<Long> resources = q.getResultList();
@ -145,9 +145,14 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
} }
long delay = System.currentTimeMillis() - start; long delay = System.currentTimeMillis() - start;
long avg = count > 0 ? (delay / count) : 0; long avg;
ourLog.info("Indexed {} resources in {}ms - Avg {}ms / resource", new Object[] { count, delay, avg }); if (count > 0) {
avg = (delay / count);
ourLog.info("Indexed {} resources in {}ms - Avg {}ms / resource", new Object[] { count, delay, avg });
} else {
ourLog.debug("Indexed 0 resources in {}ms", delay);
}
return count; return count;
} }
}); });

View File

@ -64,21 +64,21 @@ public class DaoConfig {
*/ */
public static final Long DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS = DateUtils.MILLIS_PER_MINUTE; public static final Long DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS = DateUtils.MILLIS_PER_MINUTE;
// *** /**
// update setter javadoc if default changes * update setter javadoc if default changes
// *** */
private boolean myAllowExternalReferences = false; private boolean myAllowExternalReferences = false;
// *** /**
// update setter javadoc if default changes * update setter javadoc if default changes
// *** */
private boolean myAllowInlineMatchUrlReferences = true; private boolean myAllowInlineMatchUrlReferences = true;
private boolean myAllowMultipleDelete; private boolean myAllowMultipleDelete;
private boolean myDefaultSearchParamsCanBeOverridden = false; private boolean myDefaultSearchParamsCanBeOverridden = false;
// *** /**
// update setter javadoc if default changes * update setter javadoc if default changes
// *** */
private int myDeferIndexingForCodesystemsOfSize = 2000; private int myDeferIndexingForCodesystemsOfSize = 2000;
private boolean myDeleteStaleSearches = true; private boolean myDeleteStaleSearches = true;
@ -87,27 +87,34 @@ public class DaoConfig {
private boolean myEnforceReferentialIntegrityOnWrite = true; private boolean myEnforceReferentialIntegrityOnWrite = true;
// *** /**
// update setter javadoc if default changes * update setter javadoc if default changes
// *** */
private long myExpireSearchResultsAfterMillis = DateUtils.MILLIS_PER_HOUR; private long myExpireSearchResultsAfterMillis = DateUtils.MILLIS_PER_HOUR;
private int myHardTagListLimit = 1000; /**
* update setter javadoc if default changes
*/
private Integer myFetchSizeDefaultMaximum = null;
private int myHardTagListLimit = 1000;
private int myIncludeLimit = 2000; private int myIncludeLimit = 2000;
// *** /**
// update setter javadoc if default changes * update setter javadoc if default changes
// *** */
private boolean myIndexContainedResources = true; private boolean myIndexContainedResources = true;
private List<IServerInterceptor> myInterceptors; private List<IServerInterceptor> myInterceptors;
// *** /**
// update setter javadoc if default changes * update setter javadoc if default changes
// *** */
private int myMaximumExpansionSize = 5000; private int myMaximumExpansionSize = 5000;
private int myMaximumSearchResultCountInTransaction = DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION; private int myMaximumSearchResultCountInTransaction = DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION;
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC; private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
private Long myReuseCachedSearchResultsForMillis = DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS; private Long myReuseCachedSearchResultsForMillis = DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS;
private boolean mySchedulingDisabled; private boolean mySchedulingDisabled;
private boolean mySubscriptionEnabled; private boolean mySubscriptionEnabled;
/**
* update setter javadoc if default changes
*/
private long mySubscriptionPollDelay = 1000; private long mySubscriptionPollDelay = 1000;
private Long mySubscriptionPurgeInactiveAfterMillis; private Long mySubscriptionPurgeInactiveAfterMillis;
private boolean mySuppressUpdatesWithNoChange = true; private boolean mySuppressUpdatesWithNoChange = true;
@ -160,6 +167,20 @@ public class DaoConfig {
return myExpireSearchResultsAfterMillis; return myExpireSearchResultsAfterMillis;
} }
/**
* Gets the default maximum number of results to load in a query.
* <p>
* For example, if the database has a million Patient resources in it, and
* the client requests <code>GET /Patient</code>, if this value is set
* to a non-null value (default is <code>null</code>) only this number
* of results will be fetched. Setting this value appropriately
* can be useful to improve performance in some situations.
* </p>
*/
public Integer getFetchSizeDefaultMaximum() {
return myFetchSizeDefaultMaximum;
}
/** /**
* Gets the maximum number of results to return in a GetTags query (DSTU1 only) * Gets the maximum number of results to return in a GetTags query (DSTU1 only)
*/ */
@ -549,6 +570,20 @@ public class DaoConfig {
myExpireSearchResultsAfterMillis = theExpireSearchResultsAfterMillis; myExpireSearchResultsAfterMillis = theExpireSearchResultsAfterMillis;
} }
/**
* Gets the default maximum number of results to load in a query.
* <p>
* For example, if the database has a million Patient resources in it, and
* the client requests <code>GET /Patient</code>, if this value is set
* to a non-null value (default is <code>null</code>) only this number
* of results will be fetched. Setting this value appropriately
* can be useful to improve performance in some situations.
* </p>
*/
public void setFetchSizeDefaultMaximum(Integer theFetchSizeDefaultMaximum) {
myFetchSizeDefaultMaximum = theFetchSizeDefaultMaximum;
}
/** /**
* Do not call this method, it exists only for legacy reasons. It * Do not call this method, it exists only for legacy reasons. It
* will be removed in a future version. Configure the page size on your * will be removed in a future version. Configure the page size on your

View File

@ -82,8 +82,7 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao; import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum; import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
@ -130,6 +129,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
@Before @Before
public void beforeDisableResultReuse() { public void beforeDisableResultReuse() {
myDaoConfig.setReuseCachedSearchResultsForMillis(null); myDaoConfig.setReuseCachedSearchResultsForMillis(null);
myDaoConfig.setFetchSizeDefaultMaximum(new DaoConfig().getFetchSizeDefaultMaximum());
} }
/** /**
@ -1852,6 +1852,22 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
assertThat(patients, not(containsInAnyOrder(pid2))); assertThat(patients, not(containsInAnyOrder(pid2)));
} }
@Test
public void testSearchWithFetchSizeDefaultMaximum() {
myDaoConfig.setFetchSizeDefaultMaximum(5);
for (int i = 0; i < 10; i++) {
Patient p = new Patient();
p.addName().setFamily("PT" + i);
myPatientDao.create(p);
}
SearchParameterMap map = new SearchParameterMap();
map.setLoadSynchronous(true);
IBundleProvider values = myPatientDao.search(map);
assertEquals(5, values.size().intValue());
assertEquals(5, values.getResources(0, 1000).size());
}
@Test @Test
public void testSearchStringParam() throws Exception { public void testSearchStringParam() throws Exception {

View File

@ -28,6 +28,13 @@
Optimize queries in JPA server remove a few redundant select columns when performing Optimize queries in JPA server remove a few redundant select columns when performing
searches. This provides a slight speed increase in some cases. searches. This provides a slight speed increase in some cases.
</action> </action>
<action type="add">
Add configuration to JPA server DaoConfig that allows a maximum
number of search results to be specified. Queries will never return
more than this number, which can be good for avoiding accidental
performance problems in situations where lare queries should not be
needed
</action>
</release> </release>
<release version="2.5" date="2017-06-08"> <release version="2.5" date="2017-06-08">
<action type="fix"> <action type="fix">