需要帮助构建性能最佳的SQL查询

本文关键字:SQL 查询 最佳 性能 帮助 构建 | 更新日期: 2023-09-27 18:00:30

我正在制作一个监听器,这样我就可以将多个游戏的游戏数据发布到我的服务器上。我会用它来保持客户端的同步,无论他们在什么设备上玩!这部分我已经完成了,使用Entity和Linq进行插入,并在它们被取消同步时加载playerdata。

根据发送的数据,每个到服务器的网络帖子大约需要2-10毫秒。(我希望这很好!)。这主要是FirstOrDefault选择,修改一些数据并保存更改。

但服务器也必须向客户端提供记分牌。"今天/所有时间"answers"仅限所有人/朋友"。

我尝试了一些LinqSQL查询。但当我看到输出时,我真的很害怕它会如何成型(成千上万的用户和数百万的得分记录)。

这里有一个例子:

using (BertEntities BGE = new BertEntities())
{
    var query =
       (from score in BGE.ScoreTable
        join game in BGE.GameSession on score.GameSessionID equals game.ID
        join user in BGE.User on game.UserID equals user.ID
        where
                game.PublicHighScore == true &&
                game.Banned == false &&
                game.GameID == GameID &&
                score.LevelID == level
        orderby score.Score descending
        select new ScoreResult
        {
            ID = user.ID,
            Name = user.FacebookName,
            Score = score.Score,
            Streak = score.Streak,
            Time = score.Time
        }).Skip(skip).Take(count);

    return JsonConvert.SerializeObject(query.ToList());
}

这样执行

SELECT TOP (100)
    [Project1].[Score] AS [Score],
    [Project1].[ID] AS [ID],
    [Project1].[FacebookName] AS [FacebookName],
    [Project1].[Streak] AS [Streak],
    [Project1].[Time] AS [Time]
    FROM ( SELECT [Project1].[Score] AS [Score], [Project1].[Streak] AS [Streak], [Project1].[Time] AS [Time], [Project1].[ID] AS [ID], [Project1].[FacebookName] AS [FacebookName], row_number() OVER (ORDER BY [Project1].[Score] ASC) AS [row_number]
        FROM ( SELECT
        [Filter1].[Score] AS [Score],
        [Filter1].[Streak] AS [Streak],
        [Filter1].[Time] AS [Time],
        [Extent3].[ID] AS [ID],
        [Extent3].[FacebookName] AS [FacebookName]
        FROM   (SELECT [Extent1].[LevelID] AS [LevelID], [Extent1].[Score] AS [Score], [Extent1].[Streak] AS [Streak], [Extent1].[Time] AS [Time], [Extent2].[UserID] AS [UserID], [Extent2].[GameID] AS [GameID]
            FROM  [dbo].[ScoreTable] AS [Extent1]
            INNER JOIN [dbo].[GameSession] AS [Extent2] ON [Extent1].[GameSessionID] = [Extent2].[ID]
            WHERE (1 = [Extent2].[PublicHighScore]) AND (0 = [Extent2].[Banned]) ) AS [Filter1]
        INNER JOIN [dbo].[User] AS [Extent3] ON [Filter1].[UserID] = [Extent3].[ID]
        WHERE ([Filter1].[GameID] = @p__linq__0) AND ([Filter1].[LevelID] = @p__linq__1)
    )  AS [Project1]
)  AS [Project1]
WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[Score] DESC

我不是SQL专家,但这对我来说很难

这是数据库布局:www.invokergame.com/db.png

我正在考虑将我需要的所有数据存储在ScoreTable表中,这样我就可以避免进行联接。但这会导致大量重复的数据,我敢肯定这是错误的方法。

也许我应该忘记Entity Linq,用ADO.NET SQL编写它(我需要帮助)?

对不起,文字墙,我期待着一些明智的话语!

编辑:

好吧,汤姆,这是你假装的吗?将我需要的所有数据拖放到一个数据集中。然后,当用户创建新的highscore或禁用PublicHighScore时,使用LINQ更新或删除并从此列表中选择项目?

这将如何表现?

public class ScoreCacheItem
{
    public Int64 ScoreTableID { get; set; }
    public Guid GameID { get; set; }
    public int LevelID { get; set; }
    public Int64 UserID { get; set; }
    public string Name { get; set; }
    public int Score { get; set; }
    public int Streak { get; set; }
    public double Time { get; set; }
    public DateTime Today { get; set; }
    public int Today_Score { get; set; }
    public int Today_Streak { get; set; }
    public double Today_Time { get; set; }
}

public sealed class ScoreCacheSystem
{
    private List<ScoreCacheItem> FScoreCache = new List<ScoreCacheItem>();
    private object FLock = new object();
    private List<ScoreCacheItem> LoadAllScores()
    {
        using (BertEntities BGE = new BertEntities())
        {
            var query =
               (from score in BGE.ScoreTable
                join game in BGE.GameSession on score.GameSessionID equals game.ID
                join user in BGE.User on game.UserID equals user.ID
                where
                        game.PublicHighScore == true &&
                        game.Banned == false 
                orderby score.Score descending
                select new ScoreCacheItem
                {
                    ScoreTableID = score.ID,
                    GameID = game.GameID,
                    LevelID = score.LevelID,
                    UserID = user.ID,
                    Name = user.FacebookName,
                    Score = score.Score,
                    Streak = score.Streak,
                    Time = score.Time,
                    Today = score.Today,
                    Today_Score = score.Today_Score,
                    Today_Streak = score.Today_Streak,
                    Today_Time = score.Today_Time
                });
            return query.ToList();
        }
    }
    public List<ScoreCacheItem> HighScores {
        get
        {
            lock (FLock)
            {
                if (FScoreCache == null)
                {
                    FScoreCache = LoadAllScores();
                }
                return FScoreCache;
            }
        }
    }
}

需要帮助构建性能最佳的SQL查询

您在SQL端有一个严重的问题。EF的SQL做得很好,但在这里我认为SQL Server的使用通常是不好的。

如果您需要快速回答这种类型的查询,那么可以从内存中进行,而不是从数据库服务器中进行。内存中查找通常用于简单的查询,这些查询对数据分发具有重复性和时间敏感性(金融交易-没有人会将价格写入数据库,然后让客户提取价格;您在将价格写入商店的同时分发价格)。

否则你就可以伪造它——缓存出现在我的脑海中。使用这种体系结构,您无法优化对重要数据库服务器的需求。确保你的索引已经到位。根据查询计划进行操作,确保不会遗漏任何内容。

但实际上,要尽量避免在所有级别都影响SQL Server的缓存输出。顺便说一句,SQL非常琐碎。当你点击2-3个屏幕长的分析查询时,事情会变得有趣;)数以百万计的记录不是问题,主要问题将是并发请求。连接最好已读取已提交的隔离,以确保您没有设置锁。然后获得一个合适的服务器并进行扩展,除非您更改体系结构。

我想把我需要的所有数据都存储在ScoreTable表中,所以我会避免加入。但这会导致大量重复数据,我很确定这是错误的方法。

绝对不是——就像不是错误的方法。非规范化是读取量大的报告数据库中的典型情况。您可以使用触发器来自动维护此表。它在你的情况下是否有意义,必须用一个好的数据集来测试。这通常并不糟糕,但却是数据仓库的标准做法,尽管这些通常处理实际数量的数据(数十亿行,而不是像一百万或两行这样的微小数据)。在我上一个更大的数据仓库项目中,我们每天加载大约4.5亿行,并且必须将它们存档10年才能进行报告。在谷歌上查找"星型模式"。基本上只读/数据仓库场景的规则不同。