️ perf(redis-datagrid): 优化大数据场景下搜索与右键菜单响应性能

- RedisViewer 引入树节点轻量化、虚拟滚动与大 keyspace 性能模式,降低 Key 列表卡顿
- Redis 搜索按模式分级加载并增加请求乱序保护,避免搜索结果回写抖动
- Redis 后端 ScanKeys 为搜索模式增加时间预算与轮次上限,优先返回可继续分页结果
- DataGrid 稳定 Context/rowSelection/onRow 引用并增加 shouldCellUpdate,减少右键触发全表重渲染
This commit is contained in:
Syngnat
2026-02-27 17:22:38 +08:00
parent cb18bc3067
commit 5986b71c4d
5 changed files with 347 additions and 161 deletions

View File

@@ -28,6 +28,11 @@ const (
redisScanMinStepCount int64 = 200
redisScanMaxStepCount int64 = 2000
redisScanMaxRounds = 64
redisScanMaxDuration = 12 * time.Second
redisSearchMaxTargetCount int64 = 1000
redisSearchMaxStepCount int64 = 1000
redisSearchMaxRounds = 16
redisSearchMaxDuration = 3 * time.Second
)
// NewRedisClient creates a new Redis client instance
@@ -110,21 +115,41 @@ func (r *RedisClientImpl) ScanKeys(pattern string, cursor uint64, count int64) (
return nil, fmt.Errorf("Redis 客户端未连接")
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if pattern == "" {
pattern = "*"
}
isSearchPattern := pattern != "*"
targetCount := normalizeRedisScanTargetCount(count)
scanStepCount := normalizeRedisScanStepCount(targetCount)
maxRounds := redisScanMaxRounds
maxDuration := redisScanMaxDuration
if isSearchPattern {
if targetCount > redisSearchMaxTargetCount {
targetCount = redisSearchMaxTargetCount
}
if scanStepCount > redisSearchMaxStepCount {
scanStepCount = redisSearchMaxStepCount
}
maxRounds = redisSearchMaxRounds
maxDuration = redisSearchMaxDuration
}
ctx, cancel := context.WithTimeout(context.Background(), maxDuration+5*time.Second)
defer cancel()
currentCursor := cursor
round := 0
scanStartedAt := time.Now()
keys := make([]string, 0, int(targetCount))
seen := make(map[string]struct{}, int(targetCount))
for len(keys) < int(targetCount) {
if time.Since(scanStartedAt) >= maxDuration {
break
}
batch, nextCursor, err := r.client.Scan(ctx, currentCursor, pattern, scanStepCount).Result()
if err != nil {
return nil, err
@@ -143,7 +168,7 @@ func (r *RedisClientImpl) ScanKeys(pattern string, cursor uint64, count int64) (
currentCursor = nextCursor
round++
if currentCursor == 0 || round >= redisScanMaxRounds {
if currentCursor == 0 || round >= maxRounds {
break
}
}