Entity Framework и большая база данных Mysql

36
12 января 2017, 05:04

Делаю приложение, которое работает server side и показывает таблицу со 120000 книгами.

Все вроде ок, кроме скорости, от этого страдает и стабильность выкидывает постоянно.

Message=Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

База данных Innodb поиск провожу по полю название книги, вот как выглядит мой контроллер.

[ValidateInput(false)]
public JsonResult DataTableGet()
{
    var draw = Request.Form.GetValues("draw").FirstOrDefault();
    var start = Request.Form.GetValues("start").FirstOrDefault();
    var length = Request.Form.GetValues("length").FirstOrDefault();
    //Find order columns info
    var sortColumn = Request.Form.GetValues("columns[" + Request.Form.GetValues("order[0][column]").FirstOrDefault()
                            + "][name]").FirstOrDefault();
    var sortColumnDir = Request.Form.GetValues("order[0][dir]").FirstOrDefault();
    var value = Request.Form.GetValues("search[value]").FirstOrDefault();
    var page_types = Request.Form.GetValues("columns[1][search][value]").FirstOrDefault();
    var year = Request.Form.GetValues("columns[2][search][value]").FirstOrDefault();
    var illustrations = Request.Form.GetValues("columns[3][search][value]").FirstOrDefault();
    var cover_type = Request.Form.GetValues("columns[4][search][value]").FirstOrDefault();
    var cover_design = Request.Form.GetValues("columns[5][search][value]").FirstOrDefault();
    int pageSize = length != null ? Convert.ToInt32(length) : 0;
    int skip = start != null ? Convert.ToInt16(start) : 0;
    int recordsTotal = 0;

    using (books_entites dc = new books_entites())
    {
        var v = (from a in dc.labirints select a);
        if (!string.IsNullOrEmpty(value))
        {
            v = v.Where(p => p.name.ToString().ToLower().Contains(value.ToString().ToLower()));
        }
        if (!string.IsNullOrEmpty(year))
        {
            int year_int = int.Parse(year);
            v = v.Where(a => a.year == year_int);
        }
        if (!string.IsNullOrEmpty(page_types))
        {
            v = v.Where(a => a.pages_type == page_types);
        }
        if (!string.IsNullOrEmpty(illustrations))
        {
            v = v.Where(a => a.illustrations == illustrations);
        }
        if (!string.IsNullOrEmpty(cover_type))
        {
            v = v.Where(a => a.cover_type == cover_type);
        }
        if (!string.IsNullOrEmpty(cover_design))
        {
            v = v.Where(a => a.cover_design == cover_design);
        }
        if (!(string.IsNullOrEmpty(sortColumn) && string.IsNullOrEmpty(sortColumnDir)))
        {
            v = v.OrderBy(sortColumn + " " + sortColumnDir);
        }
        recordsTotal = v.Count();
        var data = v.Skip(skip).Take(pageSize).ToList();
        return Json(new { draw = draw, recordsFiltered = recordsTotal, recordsTotal = recordsTotal, data = data },
            JsonRequestBehavior.AllowGet);
    }

Загружается страница быстро листается тоже вроде нормально. Но беда, когда я в вожу поле поиска текст.

Иногда ищет секунд 40-50, хотя поле

название книги

индексированое. Два дня не могу уснуть и пытаюсь понять почему.

В базах данных я не силен. Но нашел какой запрос приходит при поиске на Mysql

SELECT 
`GroupBy1`.`A1` AS `C1` 
FROM (SELECT 
COUNT(1) AS `A1` 
FROM `labirint` AS `Extent1` 
WHERE (LOCATE(LOWER(CASE WHEN ('Французско-русский' IS NULL) THEN ('') ELSE ('Французско-русский') END), LOWER(CASE WHEN (`Extent1`.`name` IS NULL) THEN ('') ELSE (`Extent1`.`name`) END))) > 0) AS `GroupBy1

Ввел его в админире, он тоже думал секунд 40, но ответил. Куда мне копать?

Я грешу на Entity Framework на это место.

  if (!string.IsNullOrEmpty(value))
    {
        v = v.Where(p => p.name.ToString().ToLower().Contains(value.ToString().ToLower()));
    }

Смотрю Mysql и вижу вот это.

Но не может же быть, чтобы такая известная орм так плохо работала.

Answer 1

не может же быть, чтобы такая известная орм так плохо работала.

Конечно, не может. MySQL тут вообще не при чём. Ему сказали, он делает. Безальтернативно полным сканированием таблицы (ну или если повезёт, то индекса как таблицы). И индекс не может ускорить поиск- потому что LOCATE никаким индексом пользоваться не может, только фуллскан. Так что формально надо предъявлять претензии фреймворку и реализации в нём метода Contains. Но и ему ничего предъявить нельзя - просто потому что во что транслировать иначе? в LIKE '%текст%'? хрен редьки...

Для того, чтобы реально ускорить поиск, нужно либо использовать полнотекстовый поиск по этому полю, либо использовать внешние поисковые механизмы вроде Сфинкса или Эластика. Но насколько это реализовано, если вообще реализовано, в используемом фреймворке, я лично понятия не имею.

READ ALSO
Сортировка коллекции. Интерфейс Comparator

Сортировка коллекции. Интерфейс Comparator

Возникла необходимость избавиться от второго метода сравнения compareоднако после его удаления программа не компилируетсяПодскажите в чем...

40
Клиент-серверная архитектура Android [требует правки]

Клиент-серверная архитектура Android [требует правки]

Мне нужно построить клиент-серверную архитектуруКлиентом выступает Android приложение, однако в будущем планируется и создание web-страницы...

38
Анимация setVisibility GONE/VISIBLE

Анимация setVisibility GONE/VISIBLE

Как сделать, чтобы при скрытии нескольких View-элементов, находящихся рядом в LinearLayout было так:

42
Подскажите методы выведения на экран с помощью блока If [требует правки]

Подскажите методы выведения на экран с помощью блока If [требует правки]

Нужно сделать так, что если наступает определённое время, то на экране выводится, что принимает другой врачМожно ли написать как-то с помощью...

40