优化在Sql server中快速运行的LINQ查询?

时间:2017-02-12 11:14:19

标签: c# sql-server linq linq-to-sql

我想计算相关表的行:

MainTable tbl = tblInfo(id);
var count = tbl.Related_Huge_Table_Data.Count();

问题是:执行时间太长(大约20秒),但是当我在Sql Server中运行此查询时,执行时间不到一秒。如何在linq中优化此查询?我也试过使用存储过程,但没有运气。

这是tblInfo方法:

public MainTable tblInfo(int id)
{
    MyDataContext context = new MyDataContext();
    MainTable mt = (from c in context.MainTables
                    where c.Id == id
                    select c).SingleOrDefault();
    return mt;
}

我使用了LinqToSql,类是由LinqToSql生成的。

7 个答案:

答案 0 :(得分:9)

通过运行SingleOrDefault(),您执行查询并在此之后必须处理内存中的结果。您需要使用IQueryable,直到查询完全构建完毕。

回答“此父记录有多少个子记录”的最简单方法是从子方面接近它:

using (var dx = new MyDataContext())
{
    // If you have an association between the tables defined in the context
    int count = dx.Related_Huge_Table_Datas.Where(t => t.MainTable.id == 42).Count();

    // If you don't
    int count = dx.Related_Huge_Table_Datas.Where(t => t.parent_id == 42).Count();
}

如果你坚持父方方法,你也可以这样做:

using (var dx = new MyDataContext())
{
    int count = dx.MainTables.Where(t => t.id == 42).SelectMany(t => t.Related_Huge_Table_Datas).Count();
}

如果你想在tblInfo这样的函数中保留这个查询的一部分,你可以,但你不能从这个函数内部实例化MyDataContext,否则你会在尝试时遇到异常将查询与MyDataContext的另一个实例一起使用。因此,要么将MyDataContext传递给tblInfo,要么让tblInfo成为partial class MyDataContext的成员:

public static IQueryable<MainTable> tblInfo(MyDataContext dx, int id)
{
    return dx.MainTables.Where(t => t.id == id);
}

...

using (var dx = new MyDataContext())
{
    int count = tblInfo(dx, 42).SelectMany(t => t.Related_Huge_Table_Datas).Count();
}

答案 1 :(得分:2)

试试这个

//Bank Account class   
import java.text.NumberFormat;

public class BankAccount {

private String ownerName;
private String accountId;
private double accountBalance;

public BankAccount(String ownerName, String accountId, double accountBalance) {
    this.ownerName = ownerName;
    this.accountId = accountId;
    if(accountBalance >= 0) { 
        this.accountBalance = accountBalance;           
    } else {
        System.out.println("Due to your negative account balace, you will be issued a fee.\n");
    }
}

public BankAccount(double accountBalance) {
    accountBalance = 0;
}

public String getOwnerName() {
    return ownerName;
}

public void setOwnerName(String ownerName) {
    this.ownerName = ownerName;
}

public String getAccountId() {
    return accountId;
}

public void setAccountId(String accountId) {
    this.accountId = accountId;
}

public double getAccountBalance() {
    return accountBalance;
}

public void setAccountBalance(double accountBalance) {
    if(accountBalance >= 0) { 
        this.accountBalance = accountBalance;           
    } else {
        System.out.println("Due to your negative account balace, you will be issued a fee.\n");
    }
}

public void withdraw(double amount) { 
    if(amount > 0 && amount < accountBalance) { 
        accountBalance -= amount;           
    } else {
        System.out.println("Invalid withdraw amount! Please try again.\n");
    }
}

public void deposit(double amount) { 
    if(amount > 0) { 
        accountBalance += amount;
    } else {
        System.out.println("Invalid deposit amount! Please try again.\n");
    }
}

public String toString() { 
    NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
    return "Account Owner's Name: " + ownerName + "\n" + "Account ID: " + accountId + "\n" + 
           "Balance in the account: " + currencyFormatter.format(accountBalance);
}
}

//Driver Program
public class BankAccountDriver {

public static void main(String[] args) {

    BankAccount myAccount = new BankAccount("Smith", "123jahgsd", 1200);                      
    myAccount.withdraw(0.453);
    myAccount.deposit(1000.1);
    System.out.println(myAccount);
}
}

答案 2 :(得分:1)

如果您希望充分利用SQL数据库的性能,直接查询它而不是使用Linq可能是有意义的。应该更合理地执行:)

 var Related_Huge_Table_Data = "TABLENAME";//Input table name here
 var Id = "ID"; //Input Id name here     
 var connectionString = "user id=USERNAME; password=PASSWORD server=SERVERNAME; Trusted_Connection=YESORNO; database=DATABASE; connection timeout=30";

 SqlCommand sCommand = new SqlCommand();
 sCommand.Connection = new SqlConnection(connectionString);
 sCommand.CommandType = CommandType.Text;
 sCommand.CommandText = $"COUNT(*) FROM {Related_Huge_Table_Name} WHERE Id={ID}";
 sCommand.Connection.Open();

 SqlDataReader reader = sCommand.ExecuteReader();
 var count = 0;
 if (reader.HasRows)
 {
     reader.Read();
     count = reader.GetInt32(0);
 }
 else
 {
      Debug.WriteLine("Related_Huge_Table_Data: No Rows returned in Query.");
 }
 sCommand.Connection.Close();

答案 3 :(得分:0)

试试这个:

MyDataContext context = new MyDataContext();
var count = context.MainTables.GroupBy(x => x.ID).Distict().Count();

答案 4 :(得分:0)

在许多情况下,GSerg的答案是正确的。但是当你的表开始变得非常大时,即使SQL Server中的width=840也很慢。

最好的解决方法是直接查询数据库统计信息,这对Linq来说是不可能的(或者我不知道)。

您可以做的最好的事情是在表定义上创建一个静态子(C#),它将返回以下查询的结果:

height=1188

其中Count(1)是表格的数据库名称。

请注意,这只是对计算表中所有记录的情况的答案!

答案 5 :(得分:0)

您的linq2sql是否返回记录集然后在本地执行.Count(),还是将SQL发送到服务器以在服务器上进行计数?那里的表现会有很大差异。

另外,您是否检查了执行查询时生成的SQL?从内存中,Linq2Sql允许您检查SQL(可能是通过在您的类上设置记录器?)。在Entity Framework中,您可以在调试和检查IQueryable&lt;&gt;时看到它。对象,不确定Linq2Sql中是否有等价物。

Way to view SQL executed by LINQ in Visual Studio?

或者,使用SQL Server Profiler(如果可用),或以某种方式查看正在执行的内容。

答案 6 :(得分:0)

您可以尝试以下操作: -

  var c = from rt in context.Related_Huge_Table_Data
    join t in context.MainTables
    on rt.MainTableId ==t.id where t.id=id
    select new {rt.id};

   var count=c.Distict().Count();