Почему болтливое SQL-приложение еле ползёт через VPN и что стоит объединять в пакеты
Экран, отправляющий сто зависимых запросов, платит за круговой путь сто раз. Посчитайте ожидания, объедините независимые, затем перенесите выполнение.
Форма, которая в локальной сети открывается меньше чем за секунду, через VPN занимает пять секунд, тогда как копирование файла по тому же каналу идёт на полной скорости. Разница не в пропускной способности. Форма ждёт последовательность ответов и на каждом шаге платит полный круговой путь, а копирование файла непрерывно держит байты в полёте. Посчитайте эти ожидания, прежде чем трогать линию доступа.
Симптом это экран, а не запрос
Каждый запрос на этом экране может быть быстрым, а экран всё равно может быть медленным, потому что итог это сумма ожиданий, а не сумма времён выполнения. Оператор, выполняющийся за две миллисекунды, всё равно стоит целого кругового пути, когда клиент должен получить результат до отправки следующего. На маршруте с задержкой сорок миллисекунд сто зависимых вызовов складываются примерно в четыре секунды, прежде чем начнётся хоть какая-то работа отрисовки. Эта арифметика это модель ожидания, а не замер вашего канала.
Вот почему тест скорости выглядит невинно. Массовая передача измеряет пропускную способность, болтливая форма измеряет задержку, и VPN может быть превосходным в одном и оставаться обычным в другом. Поэтому диагностировать экран означает измерять экран, а не канал.
Запишите время от начала до конца одного действия пользователя, прежде чем что-либо менять. Только это число может сказать, сработала ли последующая правка.
Посчитайте последовательные ожидания в одном действии пользователя
Инструментируйте клиент вместо догадок. В psql \timing on печатает прошедшее время каждого оператора, а EXPLAIN (ANALYZE, BUFFERS) показывает, сколько из этого времени сервер действительно потратил на работу.
Разница между этими двумя числами это ваши сетевые и клиентские накладные расходы. Если оператор выполняется за две миллисекунды, а клиент фиксирует шестьдесят, оставшиеся пятьдесят восемь это дорога и локальная обработка, и никакой индекс их не уберёт. Повторите это сравнение для каждого оператора, который отправляет экран, и складывайте разницы, а не времена выполнения.
Запишите результат как количество последовательных ожиданий. Именно эту величину способны уменьшить следующие два раздела, и это число, о котором можно спорить с доказательствами.
Объединяйте независимые вызовы, оставляйте зависимые
Два оператора, которые не читают результат друг друга, могут ехать вместе и быть собраны один раз, что превращает два ожидания в одно. Два оператора, где второму нужно значение первого, так не могут, потому что зависимость реальна и объединение изменило бы то, что делает программа. Разложите вызовы на эти две кучи до того, как что-то переписывать, и размер каждой кучи скажет, что возможно.
Работа на множествах устраняет ожидания основательнее, чем объединение в пакеты. Один запрос, возвращающий строки, которые цикл тянул по одной, устраняет и цикл, и круговые пути. Ищите сначала цикл, потому что обычно это больший выигрыш и более простая для проверки правка.
Пакет всё равно должен сохранять обработку ошибок и границы транзакций. Склейка несвязанных операторов в одну строку не безопасная оптимизация, а пакет, скрывающий неудачный оператор за успешной отправкой, хуже сэкономленных ожиданий.
Переиспользуйте соединения, прежде чем покупать полосу пропускания
Новое соединение стоит разрешения имён, рукопожатия TCP, согласования TLS и аутентификации, и на маршруте с высокой задержкой каждое из этого ещё один круговой путь до запуска первого запроса. Пулы соединений существуют, чтобы платить эту цену один раз на процесс, а не один раз на вызов.
В ADO.NET закрытие или dispose соединения из пула возвращает его для повторного использования, а не открывает новое физическое, поэтому шаблон, похожий на утечку, часто является правильным использованием. Проверьте, что пул действительно используется, вместо предположения: логируйте создание физических соединений или наблюдайте число сессий на сервере, пока экран работает. Руководство по производительности SQL говорит то же самое о сокращении круговых путей и объединении частых ad hoc вызовов, с примерами для конкретных служб, которые следует перенести на ваше развёртывание.
Пул убирает затраты на установку и оставляет последовательные ожидания запросов нетронутыми. Это предпосылка чистого измерения, а не самостоятельное исправление.
Взвесьте перенос выполнения ближе к данным
Запуск приложения рядом с базой данных заменяет множество удалённых обменов с базой одной удалённой сессией отображения. Для болтливой нагрузки это может быть крупным изменением, и это операционное изменение в той же мере, что и производительное: управление сессиями, контроль доступа, развёртывание ПО и пользовательский опыт движутся вместе с приложением.
Измерьте фактический интерфейс и данные, которые он передаёт, прежде чем предполагать, что какое-то направление быстрее. Сессия удалённого рабочего стола передаёт пиксели, и экран с плотной графикой может работать хуже по тому же маршруту, чем запросы, которые он заменил, особенно когда клиент непрерывно перерисовывает.
Затем повторите исходное действие и сравните три числа: последовательные ожидания, объём результатов и время завершения от начала до конца. Улучшение, которое меняет измеряемую задачу пользователя, сохраняя корректность данных и политику доступа, то, которое стоит оставить.