🐛 fix(query-editor): 修复结果集阻塞与未知总数分页误导

- 为查询结果定位元数据探测增加软超时降级,避免租户元数据卡死阻塞主查询结果渲染
- 将未知总数分页切换为顺序翻页模式,并修正文案仅在真实统计时显示正在统计中
- 补充查询结果与分页回归测试,覆盖元数据超时和 legacy 未知总数分页场景
This commit is contained in:
tianqijiuyun-latiao
2026-06-24 10:47:37 +08:00
parent 1aab48783d
commit 7dab6f2e33
8 changed files with 202 additions and 38 deletions

View File

@@ -369,6 +369,7 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
const duckdbApproxKeyRef = useRef<string>('');
const oracleApproxSeqRef = useRef(0);
const oracleApproxKeyRef = useRef<string>('');
const autoCountKeyRef = useRef<string>('');
const manualCountSeqRef = useRef(0);
const manualCountKeyRef = useRef<string>('');
const pkSeqRef = useRef(0);
@@ -463,6 +464,7 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
countKeyRef.current = '';
duckdbApproxKeyRef.current = '';
oracleApproxKeyRef.current = '';
autoCountKeyRef.current = '';
manualCountKeyRef.current = '';
duckdbSafeSelectCacheRef.current = {};
latestConfigRef.current = null;
@@ -923,7 +925,9 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
return { ...prev, current: currentPage, pageSize: size };
}
}
const keepManualCounting = prev.totalCountLoading && manualCountKeyRef.current === countKey;
const keepTotalCounting = prev.totalCountLoading && (
manualCountKeyRef.current === countKey || autoCountKeyRef.current === countKey
);
const hasApproximateTotalForCurrentKey =
prev.totalApprox &&
(duckdbApproxKeyRef.current === countKey || oracleApproxKeyRef.current === countKey) &&
@@ -938,7 +942,7 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
totalKnown: false,
totalApprox: true,
approximateTotal: prev.approximateTotal,
totalCountLoading: keepManualCounting,
totalCountLoading: keepTotalCounting,
totalCountCancelled: false,
};
}
@@ -950,8 +954,8 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
totalKnown: false,
totalApprox: false,
approximateTotal: undefined,
totalCountLoading: keepManualCounting,
totalCountCancelled: keepManualCounting ? false : prev.totalCountCancelled,
totalCountLoading: keepTotalCounting,
totalCountCancelled: keepTotalCounting ? false : prev.totalCountCancelled,
};
});
@@ -959,11 +963,13 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
if (shouldRunAsyncCount) {
if (countKeyRef.current !== countKey) {
countKeyRef.current = countKey;
autoCountKeyRef.current = countKey;
const countSeq = ++countSeqRef.current;
const countStart = Date.now();
// Large-table COUNT(*) can be slow and may delay later operations in some runtimes.
// DuckDB large-file scenarios disable background COUNT because it can slow pagination significantly.
const countConfig = buildRpcConnectionConfig(config, { timeout: 5 });
setPagination(prev => ({ ...prev, totalCountLoading: true, totalCountCancelled: false }));
DBQuery(countConfig, dbName, countSql)
.then((resCount: any) => {
@@ -982,11 +988,21 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
if (countSeqRef.current !== countSeq) return;
if (latestCountKeyRef.current !== countKey) return;
if (!resCount.success) return;
if (!Array.isArray(resCount.data) || resCount.data.length === 0) return;
autoCountKeyRef.current = '';
if (!resCount.success) {
setPagination(prev => ({ ...prev, totalCountLoading: false }));
return;
}
if (!Array.isArray(resCount.data) || resCount.data.length === 0) {
setPagination(prev => ({ ...prev, totalCountLoading: false }));
return;
}
const total = parseTotalFromCountRow(resCount.data[0]);
if (total === null) return;
if (total === null) {
setPagination(prev => ({ ...prev, totalCountLoading: false }));
return;
}
setPagination(prev => ({
...prev,
@@ -1001,6 +1017,8 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
.catch(() => {
if (countSeqRef.current !== countSeq) return;
if (countKeyRef.current !== countKey) return;
autoCountKeyRef.current = '';
setPagination(prev => ({ ...prev, totalCountLoading: false }));
// Count failures do not block the main flow; details stay in the SQL log.
});
}