в 999 случаях из 1000 человек не может ничего сделать глядя на 2кк строк. Наш мозг просто не в состоянии оперировать такими объемами сразу. Треть пользователей накладывает нужный фильтр, еще треть делает сортировку по одному значимому для них столбцу, и «мотает» до нужных значений. Остальные пользуются поиском на каждую запись.
Посмотрите к какой трети относятся ваши пользователи. Мне кажется сделать диалог-мастер с фильтром гораздо проще, чем выкабениваться с 2кк записей, 90% которых не требуются пользователю :)
Если у вас данные не лезут в json, как вариант, можно делать дамп таблички в static-file, загружать его, а потом уже ajax-ом доводить до кондиции с бд, если база не часто обновляет записи.
Префильтры у нас есть. Но они лишь частично спасают ситуацию. У пользователей слишком много этих префильтров и им иногда проще загрузить все данные целиком, чем создавать префильтр и потом переходить по ним. Идея со стартовым визардом понравилась. Возможно заинтегрируем :)
По поводу json. Chrome крешиться при загрузке json больше 75Mb. Можно разбить на куски и грузить их поочереди/паралельно. Но нет уверености в том, что данные из кеша будут часто переиспользоваться, т.к. комбинаций фильтров слишком много, а данные обновляются раз в сутки, что практически весь кеш инвалидирует.
> У пользователей слишком много этих префильтров и им иногда проще загрузить все данные целиком
Неправда. Я не представляю себе человека, уверенно просматривающего список из 2 млн. строк. Скорее, у вас плохие и неудобные фильтры, которыми никто не хочет пользоваться.
Возможно, но проблема не в удобстве фильтров, а скорости их работы. Пользователи конечно не просматривают 2м строк, но им нужно быстро переключаться между фильтрами или дополнять их. Если это сделать с перезагрузкой данных, то получиться медленее, чем просто дождаться загрузки всех данных и быстро фильтровать на клиенте.
Сделайте ключи по каждому полю. Это не так критично, как вам кажется. В конце концов — БД создана чтобы быстро в ней искать данные =)
Если все-таки серверный вариант вас не удовлетворяет — открой ссылку на IndexedDB, которую вам уже предлагали, и перекидайте все данные в эту базу. Каждому пользователю локально.
Ключ по каждому полю для 20 таблиц со средним размером в 10М записей и 20 полями, просто съест всю оперативку + как нюанс если индексы будут использоваться только для сортировки, то фильтрация будет не шустрая, хотя и приемлемая.
IndexedDB смотрю, но всё равно остается вопрос: как в нее загрузить все эти данные.
1. Грузите «бочками» — по частям. Первый запрос выдает ответ с, допустим, количеством партиций и адресом откуда каждую скачивать. далее с помощью например webworker выкачивать их параллельно.
2. Т.к. sqllite deprecated, я бы попробовал IndexedDB.
Результат: всё работает медлено из-за сортировки и фильтров по не индексируемым полям.
Так индексируйте таблицы, 2кк записей — это не много для MySQL.
Как правильно сказал Vampiro, нет абсолютно никакого смысла вываливать всё на клиент, пользователь не увидит и 5% этих данных, но производительность браузера это убьет насмерть.
Мгновенная сортировка делается только при индексации. Скорее всего хром этим и занимался при импорте.
Индексы имеет смысл тогда, когда они используются. Если пользователи хотят сортировать по полю — там должен быть индекс.
Вообще идея ворочить данные на клиенте, когда их больше 1к — имхо мертворожденная.
К стати если данные меняются медленно то хорошо работает кеширование — ставим ключи сортировки и прочего в урл и кешируем в nginx
Для уменьшения объёма файлов (данных) вместо json можете попробовать использовать массив массивов. Первый элемент массива — ключи. Дальше — данные. Загружаете и распаковываете в объекты.
При этом методе и создание json на сервере будет быстрее — можно использовать обычные массивы и implode.
Мы передаем данные как массивы. Но хотелось бы в идеале отправлять запрос в базу, который формирует csv файл. Ajax запрос перенаправляется на этот файл. Сервер отдает его быстро как статику. Дальше javascript сохраняет этот файл локально клиенту и парсит его через буфер, что бы получить финальный массив.
RE CSV: мне кажется что распарсить csv можно быстрее чем json (даже нативными средствами). Но проблема в том что если приходит json, то браузер обязан полностью его положить в оперативку + этот json нам нужно перегнать в нужный нам массив, а если будет приходит csv файл и его можно читать построчно, то в оперативку попадет только сформированный массив + буфер на чтение. Тут мы пробывали даже XHR2 + Blob и всё равно хром падает на файлах > 200Mb.
так мой вариант и предполагает сразу массив. и ничего не нужно парсить. это нативный метод, он сразу получит нужный массив в памяти.
дело в том, что если использовать объекты, то будет много памяти на ключи использоваться. при массивов этого нет.
но если у вас такие объёмы данных, то вам нужно уже оптимизировать алгоритм, конечно. разбивать на блоки и т.п.
например, сначала грузить первую страницу, а остальные данные фоном.
если, например, есть какие-то слои, то можно их предварительно подготовить в кеш-файлы и грузить в нужный момент.
вам вообще можно сервер не нагружать, а подготовить нужные данные во всех представлениях во всех вариантах сортировки в сотни js-кеш-файлов, которые подгружать в нужный момент по ajax.
Будет выбираться всё порциями, подтягиваться ajax-ом и проблем быть не должно, главное никакого клиентского кеширования не юзать, а то браузер будет умирать, а БД с расставленными индексами с лёгкостью справится с 2M записей.
Опишите плз подробнее. 5м каких записей (я имею ввиду их суммарный размер)? Т.е. фильтрация + сортировка по любому из полей не тормозила? При этом данные сразу все подгружались, либо только те что запросил?
Возможно, я что то упускаю из вида.
jqGrid умеет подсасывать данные порциями. смотрите здесь в new in 3.7 / virual scrolling
Использовал для работы с большими объемами — проблем не было. На клиенте всегда был лишь небольшой кусок данных что к торомозам привести ну никак не может. Естественно прийдется подкрутить серверную сторону, чтобы она возвращала нужные куски, а так-же отвечала за фильтрацию и сортировку.
Так собственно у нас серверная сторона и будет педалить в данном случае. Мне просто не понятно, как можно сделать серверную сортировку + фильтрацию, что бы она не педалила. Тут наверное мне стоит уточнить каждая таблица состоит из >20 полей + используется пару join'ов + полный размер таблицы в районе 20M (2M — это только то что нужно для конкретного пользователя). Индексы — не вариант, т.к. а) их на все поля ставить не будешь; б) они уже используются для того что бы из 20М сделать 2М. Запросы без сортировки еще более менее нормально отрабатывают, но если добавить сортировку то время ответа средней страницы уже будет достаточно большим (к сожалению, точных цифр не назову, но явно больше 10секунд).
jqGrid не подгружает сразу всё, вы же не отображаете все 5 миллионов записей, например, сразу? :) Он делает
select * from table order by field limit 200
Проверьте, сколько времени у вас выполняется такой запрос? У меня это было терпимо, даже при больших объёмах данных. Тем более, индексы есть у вас! Собственно, это и есть тот путь решения, где вы хотите грузить «по частям».
>> Индексы — не вариант, т.к. а) их на все поля ставить не будешь;
Так Вам шашечки или ехать? Хотите быстро — ставьте индексы. Клиентсайд в любом случае будет на пярядки медленнее базы данных.
Тем более эти 10 секунд не обязательно ждать каждый раз, организуйте серверный кэш и отдавайте готовый json, если попали в кэш.
Избавьтесь от join в пользу денормализации, может можно выделить небольшую актуальную часть данных в отдельную таблицу и при пэйджинге на первой десятке страниц работать с ней и лишь на дальних страницах подключать большую и т.д. и т.п.
Вы бы описали для чего вам это нужно, на основании юскейса легче предлагать нужные именно вам варианты.