Как стать автором
Обновить

Комментарии 13

И это нормальная ситуация одним запросом гонять на клиент такие объемы данных? Для чего? Почему обработку нельзя произвести на стороне сервера?
Думаю, Вы «невкурили». Статья о том, что до ее прочтения Вы (по крайней мере я уж точно) не смогли бы объяснить даже потенциальную возможность ускорения выборки от order, и свели бы это к неточностям измерения, кэшу и т.д.
Ан нет, есть еще одна не тривиальная причина. Автору — спасибо!

Ну и, если уж быть занудным, причин передать 30 тыс строк с БД я могу придумать десятки.
Таки да — нормально. Есть системы, где в принципе не предусмотрена обработка данных на стороне сервера. Возможны ситуации, когда данные пакетно обрабатываются через определённые интервалы — выгружается некий объём и обсчитывается внешней по отношению к серверу подсистемой. Есть системы многомерного анализа и т.д.
Да и обычные OLTP системы могут создать сложности в плане избыточной нагрузки. Сократив количество roundtrip-ов можно убрать bottleneck с транзакционного ограничения канала, а сократив объем — с пропускного.
Когда система упирается в нехватку некоторого ресурса, то это — как правило — говорит о том, что мы подбираемся к границам возможностей системы (ну или просчитались где-то в плане выделения ресурса), но редко бывает, что заканчивается всё и сразу и при возникновении «bottleneck» в качестве первой помощи мы — как правило — пытаемся заткнуть нехватку одного ресурса избыточностью другого. Например — нехватку памяти свопом на диск, нехватку CPU выделением большего объёма памяти и т.д. Не всегда такие «решения» высокоэффективны в плане базовых, но могут быть исключительно полезны в частных задачах.
Если вы упираетесь в пропускную способность канала, который доставляет SQL*Net пакеты, то можете попробовать увеличить её, заплатив дополнительной нагрузкой на CPU и память сервера базы данных (хоть ресурс и дорогой, но если он избыточен, то почему бы и нет).
Спасибо, очень интересный «фокус», но можно уточнить? Строчки дублируются или просто похожи? Т.е. большая часть это
1, a1, 2014.12.30, 2014.12.31
1, a1, 2014.12.30, 2014.12.31
1, a1, 2014.12.30, 2014.12.31

или все-таки вида
1, a1, 2014.12.30, 2014.12.31
1, a1, 2014.05.21, 2014.05.22

Просто есть подозрение что данная магия хорошо работает только если строчки полностью дублируются и есть подозрение что group by по всем полям или DISTINCT сработали бы ещё более эффективно, так как мне сложно представить необходимость получать сто тысяч одинаковых значений в поле имени без других параметров.

Но все равно, спасибо за интересный «трюк», надо будет попробовать и на других базах данных.
Ну, у себя я обнаружил это на обычных данных по абонентам. В среднем на абонента приходилось 7-14 записей, строчки ~ 1200 байт, в строке выборки находились данные по id абонента и имени клиента + несколько низкоселективных атрибутов. Запрос был аналитический типа STAR с групировками (там всякие агрегаты были). Базово сортировало не по абоненту, записей — около 48млн. При сортировке по клиенту, id абонента,… ужалось порядка 35%. Как повлиял ARRAYSIZE уже не скажу — на тот момент я его уже увеличил.

По поводу вашего вопроса — использовались реальные имена клиентов в истории, даты — естественно — были разные (
т.е. ближе ко второму вашему примеру).
Отличная статья. Я только надеюсь, что никто не воспринял ее как руководство юзать ORDER BY для ускорения получения результатов любых запросов :)
Насколько всё это правдиво при использовании JDBC/ODBC? Они ведь поверх SQL*Net-а работают, значит всё тоже самое должно сработать и там или есть какие-то подводные камни?
Ну, если вы используете ODBC или JDBC*OCI, то все вызовы проходят через те же Oracle Call Interface функции и результат будет такой же (только ARRAYSIZE надо определять через header соединения). Касательно JDBC*Thin думаю, что тоже будет всё ОК, но это надо проверять. Там реализован тот же SQL*Net протокол, но средствами Java Native и — естественно — некоторые аспекты могли быть опущены.
Нашел, что этой опцией протокола можно управлять с помощью *Statement.setFetchSize(int rows) в JDBC.
Если на уровне Statement, то да, но есть ещё на уровне соединения: класс — OracleConnection, метод — setDefaultRowPrefetch(...).

Да, и коль скоро мы заговорили про ARRAYSIZE,- есть такой интересный момент:
если мы, например, открываем курсор и тащим из него %fetchSize% строк, а последние строки попали из блока базы данных NNN, то после .next() нам будет передана следующая порция строк и если блок NNN был вычитан не полностью и там ещё есть нужные нам строки, то будет произведена операция повторного логического чтения данного блока. Таким образом, можно предположить, что если размер данных от %fetchSize% строк будет достаточно мал в сравнении с размером блока базы данных, то количество логических чтений будет выше реально необходимого (может даже в несколько раз).
Если я правильно понимаю, сжатие реализовано даже на уровне таких протоколов как ssh, http, то есть в теории это может сработать, даже если просто пересылать более структурированные данные по сети от бека веб.клиенту. Впрочем, я так понимать, все будет зависеть от алгоритмов архиватора протокола и в некоторых случаях никакой пользы от такой оптимизации может и не быть.
Да, при некоторых задачах успеха может и не быть по объёму трафика, но сокращение roundtrip тоже дает эффект.
Касательно сокращения трафика между бэком и веб-клиентом — это вопрос не данной темы. Здесь рассматривается взаимодействие между бэком и сервером базы данных либо между клиентом и сервером базы данных, а точнее — работа с СУБД Oracle посредством SQL*Net протокола.
Кстати, категорически советую блог Джонатана Льюиса — это прямо must read для oracle-специалистов.
Он про это еще 5 лет назад писал: jonathanlewis.wordpress.com/2010/05/07/sqlnet-compression/

Как-то мимо меня проскочил этот топик… Как бы подписаться на hub/oracle чтобы письма приходили, когда новый топик появляется?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий