Приложение запрашивает пустые таблицы

10

Моя компания использует приложение, которое имеет довольно серьезные проблемы с производительностью. Есть ряд проблем с самой базой данных, над которыми я сейчас работаю, но многие проблемы связаны исключительно с приложениями.

В своем исследовании я обнаружил, что миллионы запросов попадают в базу данных SQL Server, которые запрашивают пустые таблицы. У нас есть около 300 пустых таблиц, и некоторые из этих таблиц запрашиваются до 100-200 раз в минуту. Таблицы не имеют ничего общего с нашей бизнес-сферой и по сути являются частями исходного приложения, которое поставщик не удалил, когда они заключили контракт с моей компанией на разработку программного решения для нас.

Помимо того, что мы подозреваем, что журнал ошибок нашего приложения переполнен ошибками, связанными с этой проблемой, поставщик заверяет нас, что это не повлияет на производительность или стабильность приложения или сервера базы данных. Журнал ошибок заполняется до такой степени, что мы не можем видеть ошибок более 2 минут для диагностики.

Фактическая стоимость этих запросов, очевидно, будет низкой с точки зрения циклов ЦП и т. Д. Но кто-нибудь может подсказать, как это повлияет на SQL Server и приложение? Я подозреваю, что действительная механика отправки запроса, его подтверждения, обработки, возврата и подтверждения получения приложением сама по себе влияет на производительность.

Мы используем SQL Server 2008 R2, Oracle Weblogic 11g для приложения.

@ Frisbee - Короче говоря, я создал таблицу, содержащую текст запроса, который попал в пустые таблицы в базе данных приложения, затем запросил его для всех имен таблиц, которые, как я знаю, пусты, и получил очень длинный список. Максимальный результат - 2,7 млн. Выполнений за 30 дней безотказной работы, учитывая, что приложение обычно используется с 8:00 до 18:00, поэтому эти цифры более сконцентрированы на рабочих часах. Несколько таблиц, несколько запросов, вероятно, некоторые из них связаны через объединения, некоторые нет. Главный хит (2,7 млн. В то время) был простым выбором из одной пустой таблицы с предложением where, без объединений. Я ожидал бы, что большие запросы с объединениями к пустым таблицам могут включать обновления связанных таблиц, но я проверю это и обновлю этот вопрос как можно скорее.

Обновление: существует 1000 запросов с количеством выполнений от 1043 до 4622614 (более 2,5 месяцев). Мне придется копать больше, чтобы узнать, когда происходит кэширование плана. Это просто, чтобы дать вам представление о степени запросов. Большинство из них достаточно сложны с более чем 20 объединениями.

@ srutzky- да, я думаю, что есть колонка с датой, когда план был составлен, так что это может быть интересно, поэтому я это проверю. Интересно, будут ли ограничения потоков вообще фактором, когда SQL Server находится в кластере VMware? К счастью, скоро будет выделенный Dell PE 730xD.

@ Фрисби - Извините за поздний ответ. Как вы предложили, я запустил команду select * из пустой таблицы 10000 раз в течение 24 потоков, используя SQLQueryStress (то есть фактически 240 000 итераций), и сразу же набрал 10000 Batch Requests / sec. Затем я сократил до 1000 раз по 24 потокам и набрал чуть менее 4000 запросов в секунду. Я также попробовал 10000 итераций только для 12 потоков (таким образом, всего 120000 итераций), и это дало устойчивые 6 505 пакетов / сек. Влияние на ЦП было действительно заметным, около 5-10% от общего использования ЦП во время каждого запуска тестирования. Ожидания в сети были незначительными (например, 3 мс с клиентом на моей рабочей станции), но влияние ЦП было там точно, что, на мой взгляд, довольно убедительно. Это, кажется, сводится к использованию процессора и небольшому количеству ненужного ввода-вывода файла базы данных. Общее количество выполнений в секунду составляет чуть менее 3000, это больше, чем в производстве, однако я тестирую только один из десятков подобных запросов. Таким образом, суммарный эффект сотен запросов, обрабатывающих пустые таблицы со скоростью 300-4000 раз в минуту, не будет пренебрежимо мал, когда речь идет о времени процессора. Все тесты проводились на простое PE 730xD с двумя флэш-массивами и 256 ГБ оперативной памяти, 12 современными ядрами. Это вывод SQLSentry

@ srutzky- хорошее мышление. SQLQueryStress, кажется, использует пул соединений по умолчанию, но я все равно посмотрел и обнаружил, что да, флажок для пулов соединений установлен. Обновление, чтобы следовать

@ srutzky- Пул соединений, по-видимому, не включен в приложении - или, если он есть, он не работает. Я выполнил трассировку профилировщика и обнаружил, что соединения имеют EventSubClass «1 - Non-pooled» для событий входа в систему аудита.

RE: Connection Pooling - проверил блогологию и обнаружил, что пул соединений включен. Обнаружил больше следов от живых и обнаружил, что признаки объединения не происходят правильно / вообще: введите описание изображения здесь

И вот как это выглядит, когда я запускаю один запрос без соединений с заполненной таблицей; Исключения гласят: «При установлении соединения с SQL Server произошла ошибка, связанная с сетью или экземпляром. Сервер не был найден или был недоступен. Убедитесь, что имя экземпляра указано правильно и что SQL Server настроен для разрешения удаленных подключений. (поставщик: поставщик именованных каналов, ошибка: 40 - не удалось открыть соединение с SQL Server) «Обратите внимание на счетчик пакетных запросов. Проверка связи с сервером во время генерирования исключений приводит к успешному ответу проверки связи.

введите описание изображения здесь

Обновление - два последовательных теста, одна и та же рабочая нагрузка (выберите * из EmptyTable), пул включен / не включен. Чуть больше загрузка процессора и много сбоев, и никогда не превышает 500 пакетных запросов / сек. Тесты показывают 10000 пакетов / сек и без сбоев при включенном пуле, и около 400 пакетов / сек, а затем много сбоев из-за отключения пула. Интересно, связаны ли эти ошибки с отсутствием доступности соединения?

введите описание изображения здесь

@ srutzky - Выберите Count (*) из sys.dm_exec_connections;

  • Пул включен: 37 последовательно, даже после остановки нагрузочного теста

  • Пул отключен: 11-37 в зависимости от того,
    возникают ли исключения в SQLQueryStress, то есть: когда эти впадины появляются в
    графе «Пакеты / сек», исключения возникают в SQLQueryStress, а
    количество соединений падает до 11, а затем постепенно возвращается до 37 когда партии начинают достигать максимума, а исключения не возникают. Очень, очень интересно

Максимальное количество подключений в обоих тестовых / живых экземплярах по умолчанию равно 0.

Проверьте журналы приложений и не можете найти проблемы с подключением, однако, существует всего несколько минут для ведения журнала из-за большого количества и размера ошибок, т. Е. Большого количества ошибок трассировки стека. Коллега по поддержке приложений сообщает, что возникает значительное количество ошибок HTTP, связанных с подключением. Исходя из этого, может показаться, что по какой-то причине приложение неправильно создает пулы соединений, и в результате на сервере постоянно заканчиваются соединения. Я буду смотреть в журналы приложений больше. Интересно, есть ли способ доказать это происходит в производстве со стороны SQL Server?

@ srutzky- Спасибо. Завтра я проверю конфиг weblogic и обновлю. Я думал только о 37 соединениях - если SQLQueryStress выполняет 12 потоков с 10 000 итераций = 120 000 операторов выбора без пула, разве это не значит, что каждый выбор создает отдельное соединение с экземпляром sql?

@ srutzky - Weblogics настроен на пул соединений, поэтому он должен работать нормально. Пул соединений настраивается следующим образом для каждой из 4 веб-журналов с балансировкой нагрузки:

  • Начальная емкость: 10
  • Максимальная вместимость: 50
  • Минимальная вместимость: 5

Когда я увеличиваю количество потоков, выполняющих запрос на выборку из пустой таблицы, число соединений достигает пика около 47. При отключенном пуле соединений я постоянно вижу снижение максимального числа запросов в секунду (с 10 000 до 400). Каждый раз будет происходить то, что «исключения» в SQLQueryStress возникают вскоре после того, как пакет / сек входит в корыто. Это связано с подключением, но я не могу понять, почему именно это происходит. Когда тесты не выполняются, #connections снижается примерно до 12.

Когда пул соединений отключен, у меня возникают проблемы с пониманием, почему возникают исключения, но, может быть, это совершенно другой вопрос / вопрос для stackamchange для Адама Маханича?

@srutzky Интересно, почему исключения происходят без включения пула, даже если в SQL Server не заканчиваются соединения?

Питер
источник
1
Питер, учитывая последние обновления, касающиеся пула соединений, похоже, что теперь тебе нужно заново запускать свои тесты с SQLQueryStress, но с отключенным пулированием соединений . Это было бы более точным отражением влияния работы приложения, и я считаю, что оно покажет увеличение использования процессора и даже использования оперативной памяти.
Соломон Руцкий
1
Питер, у тебя установлено максимальное количество соединений для сервера? Я предполагаю, что без объединения вы столкнетесь с проблемой слишком большого количества соединений. Интересно, получит ли ваше приложение такую ​​ошибку? Кроме того, если возможно повторно запустить этот последний тест еще раз (как с включенным пулированием, так и без него), пока тест выполняется для каждой из этих двух конфигураций, запустите a, SELECT COUNT(*) FROM sys.dm_exec_connections;чтобы увидеть, сильно ли отличается значение между включенным пулированием или не. Исходя из этих ошибок, я думаю, что было бы гораздо больше соединений, когда пул отключен.
Соломон Руцкий,
1
Питер, 37 соединений кажется ужасно низким максимумом. Учитывая, что предел соединения установлен в 0 (то есть неограничен), ограничена ли системная память? Также пул соединений должен быть включен по умолчанию, но контролируется клиентом. Является ли приложение приложением .NET? Не обязательно использовать пул соединений, но поможет узнать, чтобы найти причину этого. И можете ли вы увидеть, какая строка подключения используется? Это указывает Pooling=falseили Max Pool Size?
Соломон Руцкий,
1
Питер, каждый из 12 потоков создает свое собственное соединение для каждого запроса, последовательно для итераций 10k. Поэтому без объединения соединение может быть уничтожено, как только код закроет соединение. Объединение будет поддерживать связь для повторного использования. Таким образом, имеет смысл, чтобы число соединений было постоянным при использовании пула. Не уверен, почему 37 без дополнительной информации. Сколько существует соединений, когда тест не выполняется? Отклонение этого числа даст лучшее представление о том, сколько было создано тестированием.
Соломон Руцкий
1
Пул соединений поддерживается для каждого клиента, а не для сервера. Поэтому WebLogics и SQLQueryStress должны иметь свои собственные пулы соединений (с точки зрения размеров min_pool и max_pool и т. Д.). Относительно «При отключенном пуле соединений я вижу более низкий максимальный объем пакетных запросов / сек»: это имеет смысл, поскольку для каждого соединения приложения требуется больше времени для аутентификации и инициализации сеанса и т. Д. Именно поэтому существует пул соединений: ).
Соломон Руцкий

Ответы:

7

Я подозреваю, что действительная механика отправки запроса, его подтверждения, обработки, возврата и подтверждения получения приложением сама по себе влияет на производительность.

Да, и есть даже некоторые дополнительные факторы, но степень, в которой какой-либо из них действительно влияет на вашу систему, невозможно определить без анализа системы.

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

У нас есть около 300 пустых таблиц, и некоторые из этих таблиц запрашиваются до 100-200 раз в минуту.

  • Пустые таблицы, которые не запрашиваются, не являются проблемой. Но я думаю, вы могли также иметь в виду, что их всех опрашивают, просто что некоторые получают удар намного больше, чем другие.
  • Синтаксический анализ запроса и генерация плана выполнения не должны быть большой проблемой, если отправляемый текст запроса остается неизменным при вызовах. SQL Server будет хэшировать текст запроса и искать его в кэше плана. Если он найден, он больше не будет выполнять шаги синтаксического анализа или компиляции (пока план не будет удален из кэша).
  • Любая таблица, пустая или не пустая, потребует как минимум «разделяемой» блокировки, чтобы указать, что ресурс используется. Это не позволяет операциям, которые требуют монопольных блокировок (добавление / изменение / удаление столбцов и т. Д.), Вносить изменения во время использования ресурса. Блокировка и разблокировка, даже если она выполняется менее чем за 1 миллисекунду, поскольку данных нет, все еще требует системных ресурсов (памяти и ЦП) для управления этими операциями блокировки.
  • Даже если наборы результатов не возвращаются в приложение из SQL Server, по-прежнему сохраняется тот же объем сетевого трафика, поступающего в SQL Server, независимо от того, дает ли запрос результаты или нет. Текст запроса или имя хранимой процедуры необходимо отправить. И даже если результаты не возвращаются, SQL Server все равно должен отправлять некоторые сетевые пакеты, содержащие структуру набора результатов, в дополнение к пакетам, сообщающим клиенту, что набор результатов запускается (даже если строки не найдены), а затем, что набор результатов окончание и должно быть закрыто. И могут быть дополнительные сообщения от операторов печати и / или количества строк.
  • Подключение к SQL Server требует определенного количества системных ресурсов. Требуется процессор и память для обработки аутентификации (а также сетевых пакетов назад и вперед), и это также требует времени. Вот почему Connection Pooling существует: чтобы сократить эти расходы.
  • Даже при том, что пул соединений сокращает использование системных ресурсов, SQL Server по-прежнему необходимо поддерживать эти соединения, а для этого требуются память и некоторый минимальный ЦП.
  • Даже без строк и, следовательно, с очень быстрым временем выполнения, запрос все еще выполнялся. Даже если было 10 или 10000 строк, и они были извлечены из пула буферов (т. Е. Памяти), поскольку они часто использовались, поток все еще должен выполнять эту работу. И поток, который работает над этим бесполезным запросом, не работает над реальным полезным запросом.

Может быть даже больше, но это должно помочь понять смысл вещей. И имейте в виду, что, как и большинство проблем с производительностью, все зависит от масштаба. Все предметы, упомянутые выше, не являются проблемой, если их ударить раз в минуту. Это похоже на тестирование изменений на вашей рабочей станции или в базе данных разработки: оно всегда работает только с 10 - 100 строками в таблицах. Переместите этот код в рабочий процесс, и его выполнение займет 10 минут, и кто-то обязательно скажет: «Ну, он работает на моем компьютере» ;-). Это означает, что проблема возникает только из-за большого количества звонков, но такая ситуация существует.

Таким образом, даже при 1 миллионе бесполезных запросов в 0 строк это составит:

  • дополнительные 2 миллиона операций блокировки (каждая блокировка должна быть разблокирована, верно?). Это в основном затраты времени на бесполезную операцию, а не на полезную операцию.
  • больше сетевого трафика, который может приблизить вас к насыщению (не уверен, насколько это вероятно, но все же)
  • поддерживается больше соединений, которые занимают больше памяти. Сколько у вас неиспользуемой физической памяти? эта память будет лучше использоваться для выполнения запросов и / или кэша плана запросов. В худшем случае вам не хватает физической памяти, и SQL Server должен начать использовать виртуальную память (swap), поскольку это замедляет работу (проверьте журнал ошибок SQL Server, чтобы узнать, получаете ли вы сообщения о выгружаемой памяти).

    И на всякий случай кто-нибудь скажет: «ну, есть пул соединений». Да, это определенно помогает уменьшить количество необходимых соединений. Но с запросами, поступающими со скоростью до 200 раз в минуту, это много одновременных действий, и для законных запросов все еще должны существовать соединения. Сделайте, SELECT * FROM sys.dm_exec_connections;чтобы увидеть, сколько активных соединений вы поддерживаете.

  • независимо от чего-либо, по крайней мере, 1 миллион раз в течение дня поток, который мог бы делать что-то полезное, был вместо этого недоступен.

Если я не ошибаюсь в том, что я здесь заявляю, то мне кажется, что, даже если в небольшом масштабе это тип DDoS-атаки на вашу систему, поскольку она наводняет сеть и ваш SQL-сервер поддельными запросами предотвращение попадания реальных запросов в SQL Server или их обработки SQL Server.

Соломон Руцкий
источник
1

Если таблицы подвергаются ударам 100-200 раз в минуту, то они (надеюсь) находятся в памяти. Нагрузка на сервер очень и очень низкая. Если у вас нет высокой загрузки ЦП или памяти на сервере базы данных, это, вероятно, не проблема.

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

Я выполнил тест на 100 000 выборочных счетчиков (*) для пустой таблицы, и он прошел за 32 секунды, и запросы были переданы по сети. Итак, 1/3 миллисекунды. Если ваша сеть не перегружена, это даже не влияет на клиента. Если у вас есть серьезные проблемы с производительностью, эти пустые запросы в 1/3 миллисекунды - это не то, что убивает приложение.

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

Итак, вернемся к фактическим утверждениям. Вы видите какие-либо обновления, добавления или удаления в этих таблицах?

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

папараццо
источник
Сколько других пользователей на SQL Server выполняли запросы, когда вы выполняли тест 100k запросов? Я не говорю, что я прав, а вы не правы, но если бы вы были единственным в системе или одним из немногих, то, естественно, вы бы не увидели значительного влияния. Проблема блокировки была не в блокировке, это просто вопрос ресурсов, которые требуются от SQL Server для блокировки и разблокировки этих страниц данных, даже если они всегда находятся в пуле буферов. Это все еще работа, которая делается. И планировщики не безграничны.
Соломон Руцки
И я не говорю, что вы не правы. Другие пользователи или нет, это все еще действительный показатель того, сколько времени это заняло, и показатель ресурсов. Заявленная нагрузка составляет 100-200 в минуту. 100 000 от одного клиента за 30 секунд превышает эту нагрузку в 200–400 раз. Если нет блокировок обновлений, то, если они получены от одного клиента или 100, не имеет значения. Ваш ответ предполагает, что существует перегруженная сеть или сервер SQL, и на основании вопроса, которого вы не знаете. Если бы это была DDoS-атака, было бы больше 100 / сек (не минут), и она не была бы против пустой таблицы.
Папараццо
Правильно, основываясь на вопросе, который мы не знаем достаточно, чтобы сузить его, поэтому я говорил, что эти вещи могут быть проблемой, в зависимости от обстоятельств. И DDoS - это всего лишь аналогия, в основном основанная на формулировке исходного вопроса, которая подразумевала, что несколько человек получили удар с такой скоростью, а многие другие также получили удар, только реже.
Соломон Руцки
Я считаю, что это будет ценным ответом в том смысле, что первый абзац очень хорошо резюмирует это: «Если у вас нет большого ЦП или памяти на сервере базы данных, это, вероятно, не проблема». В нашем случае мы используем процессор в определенное время дня, и поэтому дополнительное давление на процессор, похоже, является фактором, основанным на моем тестировании.
Питер
Примечательно, что я цитировал только запросы, выполняемые 100-200 раз в минуту, когда на самом деле существует около 50 запросов к этим пустым таблицам со счетом выполнения между 200-4000 в минуту. В совокупности эффект запроса пустых таблиц с такой частотой действительно сильно влияет на ЦП, даже в лучшем случае непараметрических запросов, выполняющихся неоднократно, поэтому план, данные и т. Д. Все находятся в памяти.
Питер
0

В целом по каждому запросу выполняются следующие шаги:

  1. Запрос из приложения.
  2. База данных Разбор запроса.
  3. Проверка движком базы данных, хранится ли этот запрос уже в ОЗУ. использовать план выполнения, если существует в памяти.
  4. если ядро ​​базы данных не существует в ОЗУ, оно проверяет наличие статистики по объектам в запросе и определяет план выполнения.
  5. Запустите план выполнения, используйте ввод / вывод для получения данных с диска.
  6. ответ на заявку.

многие из упомянутых вами запросов могут вызвать дополнительную нагрузку на систему, которая уже тяжелая - дополнительная нагрузка на соединения, ЦП, ОЗУ и ввод / вывод.

alonk
источник