c# - ejemplos - Optimizar la consulta LINQ que se ejecuta rĂ¡pidamente en el servidor Sql?
linq c# ejemplos (7)
Al ejecutar SingleOrDefault()
, ejecuta la consulta y luego tiene que ocuparse de los resultados en la memoria. IQueryable
permanecer con IQueryable
hasta que su consulta esté completamente construida.
La forma más fácil de responder "cuántos registros secundarios tiene este registro principal" es abordarlo desde el lado del niño:
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();
}
Si insiste en el enfoque del lado de los padres, puede hacerlo también:
using (var dx = new MyDataContext())
{
int count = dx.MainTables.Where(t => t.id == 42).SelectMany(t => t.Related_Huge_Table_Datas).Count();
}
Si desea mantener una parte de esta consulta en una función como tblInfo
, puede tblInfo
, pero no puede crear MyDataContext
instancia de MyDataContext
desde dicha función, de lo contrario obtendrá una excepción cuando intente utilizar la consulta con otra instancia de MyDataContext
. Así que pase MyDataContext
a tblInfo
o convierta a tblInfo
en miembro de 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();
}
Quiero calcular las filas de una tabla relacionada:
MainTable tbl = tblInfo(id);
var count = tbl.Related_Huge_Table_Data.Count();
El problema es que esto lleva demasiado tiempo (unos 20 segundos) para ejecutarse, aunque cuando ejecuto esta consulta en el servidor Sql se ejecuta por debajo de un segundo. ¿Cómo puedo optimizar esta consulta en linq? También traté de usar el procedimiento almacenado, pero no tuve suerte.
Este es el método 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;
}
Usé LinqToSql y las clases fueron generadas por LinqToSql.
Prueba esto:
MyDataContext context = new MyDataContext();
var count = context.MainTables.GroupBy(x => x.ID).Distict().Count();
La respuesta de GSerg es la correcta en muchos casos. Pero cuando su tabla comienza a ser realmente grande, incluso un Count(1)
directamente en SQL Server es lento.
La mejor manera de evitar esto es consultar las estadísticas de la base de datos directamente, lo que es imposible con Linq (o no sé).
Lo mejor que puede hacer es crear un sub estático (C #) en la definición de su tabla que devuelva el resultado de la siguiente consulta:
SELECT
SUM(st.row_count)
FROM
sys.dm_db_partition_stats st
WHERE
object_name(object_id) = ''{TableName}''
AND (index_id < 2)
donde {TableName}
es el nombre de la base de datos de su tabla.
¡Cuidado, es una respuesta solo para el caso de contar todos los registros en una tabla!
Puede intentar lo siguiente: -
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();
Si desea aprovechar al máximo el rendimiento de su base de datos SQL, puede tener sentido consultarlo directamente en lugar de utilizar Linq. Debe ser razonablemente más rendimiento :)
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();
Prueba esto
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();
¿Tu linq2sql está devolviendo el conjunto de registros y luego está haciendo el .Count () localmente, o está enviando SQL al servidor para hacer el conteo en el servidor? Habrá una gran diferencia en el rendimiento allí.
Además, ¿ha inspeccionado el SQL que se está generando cuando ejecuta la consulta? Desde la memoria, Linq2Sql le permite inspeccionar SQL (¿tal vez configurando un registrador en su clase?). En Entity Framework, puede verlo al depurar e inspeccionar el objeto IQueryable <>, no está seguro de si hay un equivalente en Linq2Sql.
¿Cómo ver el SQL ejecutado por LINQ en Visual Studio?
Alternativamente, use el Analizador de SQL Server (si está disponible), o de alguna manera vea lo que se está ejecutando.