Подтвердить что ты не робот

Оптимизировать запрос LINQ, который быстро выполняется на сервере 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.

4b9b3361

Ответ 1

Запустив 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();
}

Ответ 2

Если вы хотите в полной мере использовать преимущества своей базы данных 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

Попробуйте это

MyDataContext context = new MyDataContext();
var count=context.Related_Huge_Table_Data.where(o=>o.Parentid==id).Count();

//or

int count=context.Database.SqlQuery<int>("select count(1) from Related_Huge_Table_Data where Parentid="+id).FirstOrDefault();

Ответ 4

Попробуйте следующее:

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

Ответ 5

Ответ GSerg является правильным во многих случаях. Но когда ваша таблица становится действительно огромной, даже Count(1) непосредственно в SQL Server работает медленно.

Лучший способ обойти это - напрямую запросить статистику базы данных, что невозможно в Linq (или я не знаю).

Лучшее, что вы можете сделать, это создать статический sub (С#) в определении ваших таблиц, который вернет результат следующего запроса:

SELECT 
    SUM(st.row_count)
FROM 
    sys.dm_db_partition_stats st
WHERE 
    object_name(object_id) = '{TableName}' 
    AND (index_id < 2)

где {TableName} - имя базы данных вашей таблицы.

Остерегайтесь его ответом только на случай подсчета всех записей в таблице!

Ответ 6

Является ли ваш linq2sql возвратом набора записей, а затем локальным .Count() или отправляет SQL на сервер для подсчета на сервере? Там будет большая разница в производительности.

Также вы проверили SQL, сгенерированный при выполнении запроса? Из памяти Linq2Sql позволяет вам проверять SQL (возможно, путем установки регистратора в вашем классе?). В Entity Framework вы можете увидеть его при отладке и проверке объекта IQueryable < > , не уверен, есть ли эквивалент в Linq2Sql.

Способ просмотра SQL, выполняемого LINQ в Visual Studio?

В качестве альтернативы используйте Profiler SQL Server (если есть) или каким-то образом видите, что выполняется.

Ответ 7

Вы можете попробовать следующее: -

  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();