Linq to SQL在进行连接时创建额外的子选择

时间:2011-03-17 00:21:26

标签: c# linq-to-sql

我有一个简单的父子关系,我想用LINQ to SQL加载。我想在父母的同时加载孩子。生成的SQL做了太多工作。它试图统计孩子们并加入他们。我不会更新这些对象。我不会将孩子添加到父母那里。我只对阅读它感兴趣。我已将表格简化为最低限度。实际上我有更多的专栏。 LINQ to SQL正在生成以下SQL

SELECT [t0].[parentId] AS [Id], [t0].[name], [t1].[childId] AS [Id2], 
[t1].[parentId], [t1].[name] AS [name2], 
( SELECT COUNT(*)
    FROM [dbo].[linqchild] AS [t2]
    WHERE [t2].[parentId] = [t0].[parentId]
) AS [value]
FROM [dbo].[linqparent] AS [t0]
LEFT OUTER JOIN [dbo].[linqchild] AS [t1] ON [t1].[parentId] = [t0].[parentId]
ORDER BY [t0].[parentId], [t1].[childId]

我不知道为什么SELECT COUNT(*) ...存在。我宁愿它消失了。父表和子表在生产中都有数百万行。额外的查询耗费了大量时间。这似乎是不必要的。有没有办法让它消失?我也不确定ORDER BY来自哪里。

这些课程看起来像这样。

[Table(Name = "dbo.linqparent")]
public class LinqParent
{
    [Column(Name = "parentId", AutoSync = AutoSync.OnInsert, IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false)]
    public long Id { get; set; }

    [ Column( Name = "name", CanBeNull = false ) ]
    public string name { get; set; }

    [Association(OtherKey = "parentId", ThisKey = "Id", IsForeignKey = true)]
    public IEnumerable<LinqChild> Kids { get; set; }
}


[Table(Name = "dbo.linqchild")]
public class LinqChild
{
    [Column(Name = "childId", AutoSync = AutoSync.OnInsert, IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false)]
    public long Id { get; set; }

    [ Column( Name = "parentId", CanBeNull = false ) ]
    public long parentId { get; set; }

    [Column(Name = "name", CanBeNull = false)]
    public string name { get; set; }
}

我正在使用类似下面的内容来查询,生产中会有一个where子句和一个匹配的索引。

using (DataContext context = new DataContext(new DatabaseStringFinder().ConnectionString, new AttributeMappingSource()) { ObjectTrackingEnabled = false, DeferredLoadingEnabled = false })
{
    var loadOptions = new DataLoadOptions();
    loadOptions.LoadWith<LinqParent>(f => f.Kids);
    context.LoadOptions = loadOptions;
    var table = context.GetTable<LinqParent>();
    context.Log = Console.Out;

    // do something with table.
}

2 个答案:

答案 0 :(得分:0)

不幸的是,没有。 ORM永远不是最高性能的解决方案;如果您编写自己的SQL(或使用存储过程),您将始终获得更好的性能,但这是权衡取舍。

您所看到的是ORM的标准做法;而不是使用多重结果查询(在我看来这是最有效的方式,但我不是ORM库作者),ORM会将整个图形展平为一个查询并带回 all 它需要的信息 - 包括帮助它确定重复数据位的信息 - 来重建图形。

这也是ORDER BY的来源,因为它要求链接的实体位于连续的块中。

答案 1 :(得分:0)

正在生成的查询效率不高。如果您查看估计的执行计划,您将看到计数(*)费用非常小。 order by子句应该由您的主键排序,这可能是您的聚簇索引,因此它对性能的影响也很小。

确保在LINQ查询上测试性能时,要确保没有设置context.Log。将此设置为Console.Out将导致巨大的性能损失。

希望这有帮助。

编辑:

在仔细观察执行计划之后,我看到即使我的Count(*)只是一个聚集索引扫描,它仍然是我执行的33%,所以我同意这有点烦人在sql中额外的子选择。如果这确实是性能瓶颈,那么您可能需要考虑创建视图或存储过程以返回结果。