提高订单源的查询速度
This commit is contained in:
+7
-1
@@ -22,12 +22,18 @@ public interface OracleUpstreamOrderMapper
|
||||
|
||||
long countTabOrderMonitor(@Param("orderTable") String orderTable, @Param("query") TabOrderMonitorQuery query);
|
||||
|
||||
List<Map<String, Object>> selectTabOrderMonitorPage(
|
||||
/** Key-first page for customer+time queries (sort narrow columns only). */
|
||||
List<Map<String, Object>> selectTabOrderMonitorKeyPage(
|
||||
@Param("orderTable") String orderTable,
|
||||
@Param("query") TabOrderMonitorQuery query,
|
||||
@Param("startRow") long startRow,
|
||||
@Param("endRow") long endRow);
|
||||
|
||||
/** List detail by ids: display columns only. */
|
||||
List<Map<String, Object>> selectTabOrderMonitorListByIds(
|
||||
@Param("orderTable") String orderTable,
|
||||
@Param("ids") List<String> ids);
|
||||
|
||||
/** Distinct product codes for product-vs-package check (grouped, no pagination). */
|
||||
List<Map<String, Object>> selectTabOrderProductCodes(
|
||||
@Param("orderTable") String orderTable,
|
||||
|
||||
+200
-24
@@ -61,6 +61,12 @@ public class TabOrderMonitorService
|
||||
/** 收集结果缓存条目上限(LRU 淘汰),避免不同单号集合无限占内存。 */
|
||||
private static final int COLLECT_CACHE_MAX_ENTRIES = 20;
|
||||
|
||||
/**
|
||||
* 客户+时间列表:一次拉取的主键上限。一次取齐后内存分页,总数稳定;
|
||||
* 超过此数量仅展示前 N 条(避免 COUNT / 翻页估总数导致「共 101→201」)。
|
||||
*/
|
||||
private static final int FILTER_LIST_KEY_LIMIT = 2000;
|
||||
|
||||
/** 单批 Oracle 查询最长等待(从库 socketTimeout 为 120s,留同样余量)。 */
|
||||
private static final long COLLECT_BATCH_TIMEOUT_SECONDS = 120L;
|
||||
|
||||
@@ -102,6 +108,19 @@ public class TabOrderMonitorService
|
||||
}
|
||||
});
|
||||
|
||||
/** 客户+时间列表主键缓存(与单号收集缓存分开,存 ID 列表)。 */
|
||||
private final Map<String, FilterIdCacheEntry> filterIdCache =
|
||||
Collections.synchronizedMap(new LinkedHashMap<String, FilterIdCacheEntry>(16, 0.75f, true)
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<String, FilterIdCacheEntry> eldest)
|
||||
{
|
||||
return size() > COLLECT_CACHE_MAX_ENTRIES;
|
||||
}
|
||||
});
|
||||
|
||||
private static final class CacheEntry
|
||||
{
|
||||
private final List<MatchedOrderKey> keys;
|
||||
@@ -114,6 +133,18 @@ public class TabOrderMonitorService
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FilterIdCacheEntry
|
||||
{
|
||||
private final List<String> ids;
|
||||
private final long expireAt;
|
||||
|
||||
private FilterIdCacheEntry(List<String> ids, long expireAt)
|
||||
{
|
||||
this.ids = ids;
|
||||
this.expireAt = expireAt;
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdownCollectPool()
|
||||
{
|
||||
@@ -253,21 +284,8 @@ public class TabOrderMonitorService
|
||||
Long.valueOf(System.currentTimeMillis() - t0));
|
||||
return new TabOrderPageResult(keys.size(), rows);
|
||||
}
|
||||
long total;
|
||||
try
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
total = oracleUpstreamOrderMapper.countTabOrderMonitor(table, query);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw new ServiceException("Oracle TAB_ORDER count failed: " + e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
}
|
||||
return new TabOrderPageResult(total, doSelectRownumPage(table, query, pn, ps));
|
||||
// Customer+time: collect keys once (capped), memory-page; stable total (no 101->201).
|
||||
return doSelectFilterListPage(table, query, pn, ps);
|
||||
}
|
||||
|
||||
@DataSource(DataSourceType.SLAVE)
|
||||
@@ -338,27 +356,103 @@ public class TabOrderMonitorService
|
||||
|
||||
private List<TabOrderMonitorVo> doSelectRownumPage(String table, TabOrderMonitorQuery query, int pn, int ps)
|
||||
{
|
||||
return toVoList(doSelectRownumRows(table, query, pn, ps));
|
||||
return doSelectFilterListPage(table, query, pn, ps).getRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer+time list: pull up to {@link #FILTER_LIST_KEY_LIMIT} keys once (cached),
|
||||
* then memory-page and load display rows by ID. Total stays stable across pages.
|
||||
*/
|
||||
private TabOrderPageResult doSelectFilterListPage(String table, TabOrderMonitorQuery query, int pn, int ps)
|
||||
{
|
||||
long t0 = System.currentTimeMillis();
|
||||
List<String> allIds = doCollectFilterKeyIds(table, query);
|
||||
int total = allIds.size();
|
||||
int from = (pn - 1) * ps;
|
||||
if (from >= total)
|
||||
{
|
||||
log.info("oracle tab_order filter-list customerSize={} begin={} end={} page={}/{} rows=0 total={} costMs={}",
|
||||
query.getCustomerCodes() == null ? 0 : query.getCustomerCodes().size(),
|
||||
query.getBeginTime(), query.getEndTime(), pn, ps, Integer.valueOf(total),
|
||||
Long.valueOf(System.currentTimeMillis() - t0));
|
||||
return new TabOrderPageResult(total, Collections.emptyList());
|
||||
}
|
||||
List<String> slice = allIds.subList(from, Math.min(from + ps, total));
|
||||
List<TabOrderMonitorVo> list = loadListVosByIds(table, new ArrayList<String>(slice));
|
||||
log.info("oracle tab_order filter-list customerSize={} begin={} end={} page={}/{} rows={} total={} costMs={}",
|
||||
query.getCustomerCodes() == null ? 0 : query.getCustomerCodes().size(),
|
||||
query.getBeginTime(), query.getEndTime(), pn, ps,
|
||||
Integer.valueOf(list.size()), Integer.valueOf(total),
|
||||
Long.valueOf(System.currentTimeMillis() - t0));
|
||||
return new TabOrderPageResult(total, list);
|
||||
}
|
||||
|
||||
/** Collect (and cache) filter-path primary keys, newest first, capped at FILTER_LIST_KEY_LIMIT. */
|
||||
private List<String> doCollectFilterKeyIds(String table, TabOrderMonitorQuery query)
|
||||
{
|
||||
String fingerprint = "filter|" + collectFingerprint(table, query);
|
||||
FilterIdCacheEntry cached = filterIdCache.get(fingerprint);
|
||||
long now = System.currentTimeMillis();
|
||||
if (cached != null && cached.expireAt > now)
|
||||
{
|
||||
return new ArrayList<String>(cached.ids);
|
||||
}
|
||||
// Fetch limit+1 to detect cap; keep at most FILTER_LIST_KEY_LIMIT.
|
||||
List<String> ids = selectKeyIds(table, query, 0L, FILTER_LIST_KEY_LIMIT + 1L);
|
||||
if (ids.size() > FILTER_LIST_KEY_LIMIT)
|
||||
{
|
||||
log.warn("oracle tab_order filter-list capped at {} keys (customer+time window too large); narrow pickup range",
|
||||
Integer.valueOf(FILTER_LIST_KEY_LIMIT));
|
||||
ids = new ArrayList<String>(ids.subList(0, FILTER_LIST_KEY_LIMIT));
|
||||
}
|
||||
filterIdCache.put(fingerprint, new FilterIdCacheEntry(Collections.unmodifiableList(ids),
|
||||
now + COLLECT_CACHE_TTL_MS));
|
||||
return new ArrayList<String>(ids);
|
||||
}
|
||||
|
||||
private List<TabOrderRow> doSelectRownumRows(String table, TabOrderMonitorQuery query, int pn, int ps)
|
||||
{
|
||||
long endRow = (long) pn * ps;
|
||||
long startRow = endRow - ps;
|
||||
long t0 = System.currentTimeMillis();
|
||||
List<String> ids = selectKeyIds(table, query, startRow, endRow);
|
||||
List<TabOrderRow> rows = loadFullRowsByIds(table, ids);
|
||||
log.info("oracle tab_order sync-page customerSize={} begin={} end={} page={}/{} rows={} costMs={}",
|
||||
query.getCustomerCodes() == null ? 0 : query.getCustomerCodes().size(),
|
||||
query.getBeginTime(), query.getEndTime(), pn, ps,
|
||||
Integer.valueOf(rows.size()), Long.valueOf(System.currentTimeMillis() - t0));
|
||||
return rows;
|
||||
}
|
||||
|
||||
private List<String> selectKeyIds(String table, TabOrderMonitorQuery query, long startRow, long endRow)
|
||||
{
|
||||
try
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
long t0 = System.currentTimeMillis();
|
||||
List<Map<String, Object>> rows = oracleUpstreamOrderMapper.selectTabOrderMonitorPage(table, query, startRow, endRow);
|
||||
log.info("oracle tab_order page customerSize={} begin={} end={} page={}/{} rows={} costMs={}",
|
||||
query.getCustomerCodes() == null ? 0 : query.getCustomerCodes().size(),
|
||||
query.getBeginTime(), query.getEndTime(), pn, ps,
|
||||
rows == null ? 0 : rows.size(), System.currentTimeMillis() - t0);
|
||||
return wrapRows(rows);
|
||||
List<Map<String, Object>> keys =
|
||||
oracleUpstreamOrderMapper.selectTabOrderMonitorKeyPage(table, query, startRow, endRow);
|
||||
if (keys == null || keys.isEmpty())
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> ids = new ArrayList<String>(keys.size());
|
||||
for (Map<String, Object> key : keys)
|
||||
{
|
||||
Object idVal = value(key, "ID");
|
||||
if (idVal != null)
|
||||
{
|
||||
String id = String.valueOf(idVal).trim();
|
||||
if (!id.isEmpty())
|
||||
{
|
||||
ids.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw new ServiceException("Oracle TAB_ORDER list failed: " + e.getMessage());
|
||||
throw new ServiceException("Oracle TAB_ORDER key page failed: " + e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -366,6 +460,88 @@ public class TabOrderMonitorService
|
||||
}
|
||||
}
|
||||
|
||||
private List<TabOrderMonitorVo> loadListVosByIds(String table, List<String> ids)
|
||||
{
|
||||
if (ids == null || ids.isEmpty())
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
try
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
List<Map<String, Object>> rows = oracleUpstreamOrderMapper.selectTabOrderMonitorListByIds(table, ids);
|
||||
Map<String, Map<String, Object>> rowById = indexRowsById(rows);
|
||||
List<TabOrderMonitorVo> list = new ArrayList<TabOrderMonitorVo>(ids.size());
|
||||
for (String id : ids)
|
||||
{
|
||||
Map<String, Object> row = rowById.get(id);
|
||||
if (row != null)
|
||||
{
|
||||
list.add(toVo(row));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw new ServiceException("Oracle TAB_ORDER list by ids failed: " + e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
}
|
||||
}
|
||||
|
||||
private List<TabOrderRow> loadFullRowsByIds(String table, List<String> ids)
|
||||
{
|
||||
if (ids == null || ids.isEmpty())
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
try
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
List<Map<String, Object>> rows = oracleUpstreamOrderMapper.selectTabOrderMonitorByIds(table, ids);
|
||||
Map<String, Map<String, Object>> rowById = indexRowsById(rows);
|
||||
List<Map<String, Object>> ordered = new ArrayList<Map<String, Object>>(ids.size());
|
||||
for (String id : ids)
|
||||
{
|
||||
Map<String, Object> row = rowById.get(id);
|
||||
if (row != null)
|
||||
{
|
||||
ordered.add(row);
|
||||
}
|
||||
}
|
||||
return wrapRows(ordered);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw new ServiceException("Oracle TAB_ORDER list by ids failed: " + e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, Map<String, Object>> indexRowsById(List<Map<String, Object>> rows)
|
||||
{
|
||||
Map<String, Map<String, Object>> rowById = new LinkedHashMap<String, Map<String, Object>>();
|
||||
if (rows == null)
|
||||
{
|
||||
return rowById;
|
||||
}
|
||||
for (Map<String, Object> row : rows)
|
||||
{
|
||||
Object idVal = value(row, "ID");
|
||||
if (idVal != null)
|
||||
{
|
||||
rowById.put(String.valueOf(idVal).trim(), row);
|
||||
}
|
||||
}
|
||||
return rowById;
|
||||
}
|
||||
|
||||
private static List<TabOrderRow> wrapRows(List<Map<String, Object>> rows)
|
||||
{
|
||||
if (rows == null || rows.isEmpty())
|
||||
|
||||
Reference in New Issue
Block a user