【问题标题】:Linq Where much quicker than SQL WhereLinq Where 比 SQL Where 快得多
【发布时间】:2016-12-08 18:35:10
【问题描述】:

我是 SQL 新手,无法理解为什么这条 Where 语句效率如此低下。

关于数据库的一些背景知识。它是一个用于存储图标的 SQL Compact Edition 数据库。一个项目可以有多个图标,每个图标可以有多个路径,每个路径由几何、颜色和不透明度组成。大约有 2000 个图标,产生大约 12000 条路径。

我正在尝试创建一个只返回属于给定项目的图标的查询

SELECT Icons.Id, Icons.Name... etc FROM Icons
INNER JOIN Projects ON Icons.FK_ProjectId = Projects.Id 
INNER JOIN IconDetails ON Icons.Id = IconDetails.FK_IconId
INNER JOIN Paths ON IconDetails.FK_PathId = Paths.Id
INNER JOIN Colours ON IconDetails.FK_ColourId = Colours.Id
WHERE (Icons.FK_ProjectId = 5)

这需要大约 2.8 秒才能完成。但是,如果我删除底部的 Where 语句,它只需要 ~0.3 秒。然后我可以使用 C# Linq 来选择它们属于我想要的项目的所有图标。

var iconTable = GetIconDataFromDatabase().Where(e => e.Project == projectName);


private List<IconData> GetIconDataFromDatabase()
{
    var getAllIconsCommand = new SqlCeCommand( // SQL Above);

    return ReturnIconData(LOCAL_CONNECTION_STRING, getAllIconsCommand);
}

private List<IconData> ReturnIconData(string connectionString, SqlCeCommand command)
{
    var IconDataToReturn = new List<IconData>();

    using (var connection = new SqlCeConnection(connectionString))
    {
        command.Connection = connection;

        using (command)
        {
            try
            {
                connection.Open();

                 using (SqlCeDataReader dataReader = command.ExecuteReader())
                 {
                     while (dataReader.Read())
                     {
                         IconDataToReturn.Add(new IconData
                         {
                             Id = int.Parse(dataReader["Id"].ToString().Trim()),
                             Project = dataReader["ProjectName"].ToString().Trim(),
                             Name = dataReader["Name"].ToString().Trim(),
                             Geometry = Geometry.Parse(dataReader["Geometry"].ToString().Trim()),
                             Colour = dataReader["Colour"].ToString().Trim(),
                             Opacity = double.Parse(dataReader["Opacity"].ToString().Trim()),
                             IsPathCompact = bool.Parse(dataReader["Compact"].ToString().Trim()),
                             ZOrder = int.Parse(dataReader["ZOrder"].ToString().Trim())
                       });

                    }
                }  
            }
        }
    return IconDataToReturn;
}

我不明白返回每个图标然后自己过滤掉结果怎么会这么快。

【问题讨论】:

  • 你显示 sql 但你在谈论 LINQ。你能展示真正的C#代码吗? sql查询是实际执行的还是你认为的?
  • 您在显示的代码中根本没有使用iconTable,但是您使用的是dataReader,您还没有声明......很难遵循您的内容正在做。
  • 你在下次执行时清除了 sql 缓存吗?
  • 旁注:不要将所有内容都转换为字符串,然后再转换回正确的类型,例如与double.Parse(dataReader["Opacity"].ToString().Trim())。而是将其存储为正确的类型,然后使用 dataReader.GetDouble(opacityIndex)
  • Icons.FK_ProjectId 是否已编入索引?

标签: c# sql-server linq


【解决方案1】:

对此没有一般的答案。您的性能值将在很大程度上取决于数据库大小和使用的索引等因素。如果您的表中有很多行并且您在Icons.FK_ProjectId 上有一个非常有选择性的索引(例如,您只选择一百万行中的 10 行),我怀疑加载所有行并使用 LINQ 选择会更快,因为数据库可以使用索引进行查找操作(快速)并且只返回一小部分行(也很快)。

另一方面,如果您没有索引并且选择了行的一个大子集(例如 2500 行中的 2000 行),SQL Server 将首先必须执行聚集索引扫描,然后它才会返回几乎所有行数据集。这个额外的操作会占用大部分的执行时间,并且不会显着减少结果集的大小。

你应该做的是比较你的执行计划有和没有在哪里,看看你是否可以优化你的查询。在 DB 级别进行调优通常比在客户端进行调优更可取。

【讨论】:

  • 我刚刚跑了CREATE INDEX IconIdIndex ON Icons (FK_ProjectId)。它说它是成功的,但它并没有对性能产生影响。
  • 一个索引可以有效果,if SQL Server选择使用它。如果它估计它不会有很大的不同(例如不是很有选择性 - 例如第二段中的示例),它可能仍然会忽略它。这就是为什么根据执行计划进行数据库性能调优很重要的原因。
  • 另外,您的查询中有多个JOINs,因此您可能还需要一些其他索引。
  • 我会看看我是否能找到一些关于如何评估执行计划的教程。谢谢。
【解决方案2】:

本身不是一个答案,但可能对任何展望未来的人来说都是一个有用的解决方案。我在 SQLite 中实现了完全相同的东西,并且能够在 0.03 秒内恢复数据,而无需自己执行任何 linq。

【讨论】:

    猜你喜欢
    • 2011-07-29
    • 2011-01-05
    • 2012-01-29
    • 1970-01-01
    • 2010-11-10
    • 2010-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多