You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Redis中执行指定LINQ逻辑以优化查询性能?

可行优化方案

1. 用Lua脚本在Redis端直接执行逻辑

Lua脚本可在Redis服务器内运行,彻底避免全量拉取数据到客户端的开销,是当前场景下最直接的解决方案。核心步骤如下:

  • 通过SCAN命令分批获取所有RedisJSON键(避免一次性加载20k键造成服务器阻塞)
  • 对每个键,用JSON.GET读取所需字段(EventKey, BetCategory, CustomParticipant, CustomLine, BetPosition, OddsDecimal, PositionId, BetData)
  • 在Lua内按复合键分组,将同一组的Position数据存入临时表
  • 遍历每个分组,对组内Position两两配对,检查t1.BetPosition != t2.BetPosition和(1/t1.OddsDecimal + 1/t2.OddsDecimal) < 0.985的条件
  • 收集符合条件的结果,一次性返回给客户端

示例Lua核心逻辑(简化版):

local cursor = "0"
local groups = {}
repeat
    local result = redis.call("SCAN", cursor, "MATCH", "*", "COUNT", 1000) -- 分批扫描键,COUNT值可根据Redis性能调整
    cursor = result[1]
    local keys = result[2]
    for _, key in ipairs(keys) do
        local json = redis.call("JSON.GET", key)
        local data = cjson.decode(json)
        -- 构建复合键作为分组标识
        local compositeKey = data.EventKey .. "|" .. data.BetCategory .. "|" .. data.CustomParticipant .. "|" .. data.CustomLine
        -- 初始化分组并加入数据
        if not groups[compositeKey] then
            groups[compositeKey] = {}
        end
        table.insert(groups[compositeKey], {
            PositionId = data.PositionId,
            OddsDecimal = data.OddsDecimal,
            BetData = data.BetData,
            BetPosition = data.BetPosition,
            BetCategory = data.BetCategory
        })
    end
until cursor == "0"

-- 遍历分组生成符合条件的结果
local finalResult = {}
for _, group in pairs(groups) do
    local len = #group
    if len >= 2 then
        -- 组内两两配对(避免重复检查i<j)
        for i=1, len do
            for j=i+1, len do
                local t1 = group[i]
                local t2 = group[j]
                if t1.BetPosition ~= t2.BetPosition then
                    local sum = 1/t1.OddsDecimal + 1/t2.OddsDecimal
                    if sum < 0.985 then
                        table.insert(finalResult, {
                            PositionId1 = t1.PositionId,
                            OddsDecimal1 = t1.OddsDecimal,
                            BetData1 = t1.BetData,
                            PositionId2 = t2.PositionId,
                            OddsDecimal2 = t2.OddsDecimal,
                            BetData2 = t2.BetData,
                            BetCategory = t1.BetCategory
                        })
                    end
                end
            end
        end
    end
end

return cjson.encode(finalResult)

C#调用示例:

var script = File.ReadAllText(@"path/to/your/script.lua");
var result = await _redis.GetDatabase(1).ScriptEvaluateAsync(script);
var finalList = JsonSerializer.Deserialize<List<YourResultType>>(result.ToString());

2. 预构建分组索引,降低Lua遍历开销

如果全量SCAN键仍有性能压力,可提前维护分组索引优化流程:

  • 每次写入/更新RedisJSON数据时,将对应Position ID添加到以复合键命名的Redis Set中,例如键名格式为group:{EventKey}:{BetCategory}:{CustomParticipant}:{CustomLine}
  • Lua脚本优先扫描所有分组键(SCAN MATCH group:*),再通过SMEMBERS获取分组内的Position ID列表
  • 用JSON.MGET批量读取这些Position的字段,后续配对逻辑与上述Lua脚本一致

这种方式减少了全量扫描数据键的开销,适合数据更新频率较低的场景。

3. 改用RedisGraph实现关系查询

RedisGraph是Redis的图数据库模块,支持Cypher查询语言,可简洁处理这类分组配对逻辑:

  • 将每个Position作为图节点,节点属性包含所有所需字段
  • 执行Cypher查询直接筛选符合条件的节点对:
MATCH (p1:Position), (p2:Position)
WHERE p1.EventKey = p2.EventKey
  AND p1.BetCategory = p2.BetCategory
  AND p1.CustomParticipant = p2.CustomParticipant
  AND p1.CustomLine = p2.CustomLine
  AND p1.BetPosition <> p2.BetPosition
  AND (1/p1.OddsDecimal + 1/p2.OddsDecimal) < 0.985
RETURN p1.PositionId AS PositionId1, p1.OddsDecimal AS OddsDecimal1, p1.BetData AS BetData1,
       p2.PositionId AS PositionId2, p2.OddsDecimal AS OddsDecimal2, p2.BetData AS BetData2,
       p1.BetCategory AS BetCategory

可通过C#的RedisGraph客户端库(如StackExchange.Redis.Extensions.RedisGraph)执行查询,直接获取结果,无需拉取全量数据。

方案选型建议

  • Lua脚本:无需额外安装模块,适配现有RedisJSON环境,处理20k数据的性能可轻松控制在600ms以内
  • 预构建索引:进一步降低Lua脚本的执行耗时,适合数据更新不频繁的场景
  • RedisGraph:语法最简洁,长期维护成本低,需安装RedisGraph模块,但查询性能最优

内容的提问来源于stack exchange,提问作者user3533755

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 06:50:27