Автозаполнение jQuery - вопрос оптимизации

были бы рады вашим мыслям по этому поводу.

Я использую автозаполнение jQuery в приложении ASP.NET MVC для получения списка записей из базы данных - я хотел бы знать, есть ли лучший способ, чем тот, который я делаю сейчас, - следующим образом:

Вот jQuery (я вызываю метод действия GetRecordByName с автозаполнением)

    $('#tb_name').autocomplete({
        source: 'Home/GetRecordByName',
        minLength: 1, delay: 0,
        select: function (event, ui) {
            // do stuff
        }
    });

На задней панели я использую Linq to Entities в методе для получения результатов из базы данных:

public JsonResult GetRecordByName(string term)
{
        var data = records
            .Where(dr => dr.Key.StartsWith(term))
            .Select(dr => new { dr, value = dr.Key })
            .Take(5);

        return Json(data, JsonRequestBehavior.AllowGet);
}

В настоящее время он работает немного медленно (~ 1-2 секунды). По сути, БД содержит десятки тысяч записей, и каждый раз, когда вы вводите символ в текстовое поле, приложение попадает в базу данных. Я могу установить его на 2 или 3 символа, но это не меняет скорость, и я не хочу требовать столько символов.

У меня есть идея, как его оптимизировать: при загрузке страницы получить все возможные результаты из БД и отправить их клиенту (через скрытый ввод или структуру данных javascript), а при автозаполнении использовать эти данные на стороне клиента в качестве источника. Я уверен, что это будет молниеносно, но мне это кажется странным - есть ли недостатки в том, чтобы сделать это таким образом?

Есть ли другие способы добиться более быстрого автозаполнения?

ОБНОВЛЕНИЕ: Хорошо, по-видимому, проблема заключалась в том, как я строил свой EF-вызов. Вызов EF для «записей» в конечном итоге не создавал предложение WHERE в запросе sql; он получал всю таблицу каждый раз, а затем методы linq выходили из этой уже пронумерованной массы данных - это происходило каждый раз, когда вводилась буква, - вызывая замедление. Дох! Я переместил метод .Where на уровень репозитория данных, где он перечисляет после того, как where фильтрует результаты и возвращает словарь - теперь кажется, что он отлично работает. Спасибо за вашу помощь! Я отметил самый полезный ответ, который помог мне разобраться в проблеме.

Что касается решения Flickr / предоставления всего набора данных клиенту, я все еще чувствую, что это странно / излишне, но я уверен, что это оправдано с некоторыми большими наборами данных. Также я буду больше изучать OutputCache для других вещей.

Еще раз спасибо!


person donnovan9    schedule 12.05.2011    source источник
comment
Забыл упомянуть об использовании ILookup сзади [закрытая строка ILookup ‹только для чтения, RecordsTable› records = Repository.GetDirectoryRecordsAll ();]   -  person donnovan9    schedule 12.05.2011
comment
Ребята, большое спасибо за ответы! Я рассматриваю различные варианты и дам вам знать, какое решение было лучшим для моего сценария.   -  person donnovan9    schedule 12.05.2011


Ответы (4)


Как и при любой оптимизации, сначала вы должны протестировать, чтобы выяснить, где находится узкое место. В противном случае ваши усилия будут сосредоточены не в том направлении. Например, используйте Firebug, чтобы узнать, сколько времени занимает фактический запрос. Используйте секундомер в своем действии MVC, чтобы увидеть, сколько времени занимает фактическое извлечение данных (вызовите ToList в конце вашего запроса, чтобы убедиться, что он оценивается в методе).

Пока мы не узнаем, где происходит замедление, невозможно дать вам действительно хорошее предложение по оптимизации, но вот пара идей, которые приходят на ум:

  • Используйте SQL Server Management Studio для анализа пути выполнения запроса, созданного LINQ to Entities. Возможно, добавление какого-либо индекса в текстовый столбец заставит базу данных быстрее возвращать результаты?
  • В Windows существует проблема с DNS, которая часто приводит к тому, что браузеры, отличные от IE, очень медленно работают со средами разработки. Если это работает быстро в IE, но не в Firefox, возможно, вам просто нужно настроить файл Hosts.

При загрузке страницы получите все возможные результаты из БД и отправьте их клиенту (через скрытый ввод или структуру данных javascript), а при автозаполнении используйте эти данные на стороне клиента в качестве источника. Я уверен, что это будет молниеносно, но мне это кажется странным - есть ли недостатки в том, чтобы сделать это таким образом?

Да, есть недостатки. Вы говорите, что в базе данных есть десятки тысяч возможных результатов: достаточно, чтобы вы заподозрили, что базе данных требуется пара секунд, чтобы вернуть несколько результатов по вашему запросу. Загрузка всех этих записей на страницу при начальной загрузке страницы значительно повысит производительность при начальной загрузке страницы. Вероятно, размер вашей страницы будет на несколько сотен тысяч больше, чем нужно, что имеет большое значение для пользователей с медленным интернет-соединением.

person StriplingWarrior    schedule 12.05.2011
comment
Отличный совет. После некоторого анализа я определил, что большую часть времени занимает база данных, о чем я все равно подумал. Это имеет смысл, потому что это очень старая база данных без индексов, ограничений или отношений - что еще хуже, я не уверен, что могу ее изменить. Мне сказали работать с тем, что мне дали. Возможно, мне придется подтолкнуть, чтобы разместить там индекс. Если это невозможно с политической точки зрения, можно ли придумать какие-либо другие обходные пути? - person donnovan9; 12.05.2011
comment
@Konrad: А, я помню, как работал в большой корпорации. Мои соболезнования. В любом случае, если они не позволят вам добавить индекс в поле базы данных, но им по-прежнему нужно быстрое время отклика, вероятно, лучше использовать кеш в памяти. Возможно, вам потребуется найти или написать класс коллекции, который позволит выполнять быстрый поиск на основе критерия StartsWith: возможно, дерево, в котором каждый узел имеет символ, а его листья - это пути, которые начинаются с символов на пути к корню. - person StriplingWarrior; 12.05.2011
comment
@Konrad: Еще один вариант, если значения в базе данных почти никогда не меняются, - это создать статический файл с этими значениями, а затем использовать настройки кеша, которые заставят файл загружаться только один раз в браузере. Посмотрите, как chinese-tools.com/tools/ime.html использует chinese-tools.com/jdd/public/ime/data-utf .js - person StriplingWarrior; 12.05.2011

1) Это действительно зависит от вашего использования и ваших данных, но я рекомендую использовать [OutputCache]. Вы можете избежать выполнения запроса к базе данных каждый раз, когда какой-либо пользователь вызывает одно и то же действие контроллера. Дополнительные сведения см. здесь. Это будет только для каждого пользователя, если вы используете кеширование на уровне действий контроллера, он будет кешировать один для всех пользователей.

2) посмотрите ответ на этот вопрос: Как повысить производительность автозаполнения JQuery < / а>

"This widget downloads a list of all of your contacts, in JavaScript, in under 200ms
(this is true even for members with 10,000+ contacts). In order to get this level of 
performance, we had to completely rethink how we send data from the server to the client."

3) Я видел людей, использующих Redis. Это требует некоторой настройки, но эффективно.

Автозаполнение Redis

эффективное автозаполнение на стороне сервера

person Priyank    schedule 12.05.2011
comment
Я смотрю в OutputCache, это может быть то, что мне нужно - person donnovan9; 12.05.2011
comment
Нет, к сожалению, он кэширует первый набор результатов, который я запрашиваю - скажем, я набираю Pr и получаю Приянка, Прудона и т. Д. - затем я печатаю Кон, ожидая получить Конрада, но я все равно получаю результаты для термина автосовместимости, который я изначально набрал Приянк, Прудон и др. - person donnovan9; 12.05.2011
comment
Почему бы вам не попробовать второй вариант [пример flickr] и переосмыслить структуру данных и захват на стороне сервера. Я считаю, что нет лучшего решения, чем использование облегченного транспорта данных и перехвата на стороне сервера. - person Priyank; 12.05.2011

То, как вы упомянули, неплохая идея, но, как упоминал StriplingWarrior, это может повлиять на загрузку вашей страницы. Способ решить эту проблему - выполнить асинхронный вызов ajax при загрузке страницы и в обратном вызове успеха привязать данные, возвращаемые к автозаполнению.

Это означает, что автозаполнение не будет работать до тех пор, пока не будут возвращены результаты, но каковы шансы, что использование перейдет в текстовое поле и наберет ‹2/3 секунды?

person jcvandan    schedule 12.05.2011

Я не совсем уверен в ваших настройках, но один из путей оптимизации, который вы можете выбрать, - это использовать redis для хранения всех ваши доступные для поиска параметры в виде пары ключ / значение. Просто настройте задачу, чтобы она постоянно обновлялась.

person Chance    schedule 12.05.2011