Linq требуется более 20 секунд для запроса таблицы с менее чем 100 записями - PullRequest
0 голосов
/ 13 февраля 2019

К сожалению, я не нашел хорошего ответа на эту проблему.Ответы и вопросы, которые я видел здесь до сих пор, касаются больших таблиц с большим количеством записей.

Я пытаюсь запросить таблицу с именем Tickets со следующим кодом:

var Status = ticketStatusService.GetByName("New");
string StatusID = Status.Id;
var tickets = db.Tickets.Where(e => 
              !e.Deleted && 
              e.Project == null && 
              e.Status != null && 
              e.Status.Id == StatusID);
var list = tickets.ToList();

В настоящее время в таблице менее 100 записей, выполнение этого запроса занимает в среднем 22 секунды.

Первая модель кода для него выглядит следующим образом:

public class Ticket : Base
{
    [Key]
    [Required]
    public Guid Id { get; set; }

    [Display(Name = "Date")]
    public DateTime RowDate { get; set; } = DateTime.Now;

    public bool Deleted { get; set; } = false;

    [Index(IsUnique = true)]
    public int? Number { get; set; }

    [Display(Name = "Ticket Subject")]
    public string Subject { get; set; }

    [Display(Name = "Notes (Employees Only)")]
    public string Notes { get; set; }

    [Display(Name = "E-Mail")]
    public string From { get; set; }

    [Display(Name = "Phone Number")]
    public string Phone { get; set; }

    [Display(Name = "Secondary Phone Number")]
    public string PhoneAlt { get; set; }

    [Display(Name = "Client Name")]
    public string Name { get; set; }

    [Display(Name = "Message")]
    public string Messages { get; set; }

    [DataType(DataType.DateTime)]
    public DateTime? OpenDate { get; set; }

    [DataType(DataType.DateTime)]
    public DateTime? CloseDate { get; set; }

    [DataType(DataType.DateTime)]
    public DateTime? AssignedDate { get; set; }

    public bool? Origin { get; set; }

    public virtual User AssignedUser { get; set; }

    public virtual List<TicketFile> TicketFiles { get; set; }

    public virtual List<Task> Tasks { get; set; }

    public virtual Project Project { get; set; }

    public virtual TicketStatus Status { get; set; }

    public virtual TicketClosingCategory TicketClosingCategory { get; set; }
    public virtual TicketGroup TicketGroup { get; set; }

    public virtual TicketPriority TicketPriority { get; set; }
}

Любое понимание этоговопрос будет оценен.Большое спасибо!

Редактировать: Выполнение одного и того же запроса непосредственно в SQL Server Management Studio также занимает очень много времени, от 9 до 11 секунд.Так что может быть проблема с самой таблицей.

1 Ответ

0 голосов
/ 14 февраля 2019

Я вижу несколько возможных улучшений.

По какой-то причине вы решили отклониться от соглашений по коду структуры сущностей .Одним из них является использование List вместо ICollection, другое - исключение упоминания внешних ключей.

Использование ICollection вместо List

Вы уверены, что Ticket.TicketFiles[4] имеет определенное значение?А что бы значило Ticket.TicketFiles.Insert(4, new TicketFile())

Лучше придерживаться интерфейса, который запрещает использование функций, которые не имеют определенного значения.Используйте ICollection<TicketFile>.Таким образом, вы будете иметь только те функции, которые имеют правильное значение в контексте базы данных.Кроме того, он дает инфраструктуре сущностей свободу выбора наиболее эффективного типа коллекции для выполнения своих запросов.

Пусть ваши классы представляют таблицы

Пусть ваши классы просто являются POCO.Не добавляйте никаких функций, которых нет в ваших таблицах.

В каркасе сущностей столбцы таблицы представлены не виртуальными свойствами.Виртуальные свойства представляют отношения между таблицами (один-ко-многим, многие-ко-многим, ...)

Пусть структура сущностей решает, что наиболее эффективно для инициализации данных в ваших последовательностях,Не используйте конструктор, в котором вы создаете List, который будет немедленно отброшен структурой сущностей, чтобы заменить его собственным ICollection.Не инициализируйте автоматически свойство Deleted, если платформа сущностей немедленно заменит его своим собственным значением.

Вероятно, у вас будет только одна процедура, в которой вы добавите билет в базу данных.Используйте эту функцию для правильной инициализации поля любого «вновь добавленного тикета»

Не забудьте внешние ключи

Вы определили несколько отношений между вашими таблицами (одно-to-many или many-to-many?) но вы забыли определить внешние ключи.Поскольку вы используете virtual, сущностный каркас может понять, что ему нужны внешние ключи, и он их добавит, но в вашем запросе вам нужно написать e.Status != null && e.Status.Id == statusId, тогда как, очевидно, вы можете просто использовать внешний ключ e.StatusId == statusId.Для этого вам не нужно объединяться с таблицей «Статусы»

Еще одна причина указать внешние ключи: они являются реальными столбцами в ваших таблицах.Если вы определите, что эти классы представляют ваши таблицы, они должны быть в этих классах!

Выберите только те свойства, которые вы действительно планируете использовать

Одна из более медленных частейзапрос к базе данных - это передача выбранных данных из системы управления базами данных в локальный процесс.Следовательно, разумно выбирать только те данные, которые вы действительно планируете использовать.

Пример.Кажется, между User и Ticket существует отношение один ко многим: каждый пользователь имеет ноль или более Tickets, каждый Ticket принадлежит ровно одному User.Предположим, что User 4 имеет 20 Tickets.Каждый Ticket будет иметь UserId со значением 4. Если вы получите эти 20 Tickets без правильного Select, вы получите все свойства одного и того же User 4 один раз за Ticket, и вы получитетранспортировать данные этого же User 20 раз (со всеми его свойствами и, возможно, всеми его отношениями).Какая трата вычислительной мощности!

Всегда использовать Select для запроса ваших данных и Select только те свойства, которые вы фактически планируете использовать.Используйте функцию «Включить» только в том случае, если вы планируете обновить включенные данные.

var tickets = dbContext.Tickets.Where(ticket => !ticket.Deleted

    // improvement: use foreign keys
    && ticket.ProjectId == 0 (or == null, if ProjectId nullable)
    && ticket.StatusId == statusId)       // no Join with Statuses needed

    .Select(ticket => new
    {
        ... 
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...