Що в коді визначає "занадто багато запитів до бази даних"?


17

Це сама дискусія, і деякі мої колеги проводять і думають, що я вийду сюди і подивлюсь, що, якщо є загальний консенсус щодо цього.

В основному це зводиться до наступних 2 висновків щодо дзвінків до бази даних: 1. Зробіть один великий дзвінок, щоб отримати все, що може знадобитися для зменшення кількості баз даних у виклику БД. Дзвінки DB

Там, де це особливо грає, є загальний код. Ми будемо використовувати приклад класу Employee, оскільки це досить прямо.

Скажімо, ваш клас Співробітник має 10 атрибутів значення (ім’я, прізвище, найманий персонал тощо), а потім 2 атрибути класу ... 1 вказує на клас відділу, а потім 1 керівник, який вказує на іншого об'єкта працівника.

Зважаючи на настрій № 1, ви б здійснили один виклик, який повертає дані працівника, а також поля, необхідні для заповнення атрибутів Департаменту та Супервізора ... або принаймні поля, які найчастіше використовуються з цих під об’єктів.

Зважаючи на настрій № 2, ви спочатку заповнюєте об'єкт «Співробітник», а потім лише об’єкти Департаменту та Супервізора, лише якщо вони дійсно запитуються.

Позиція 2 досить прямолінійна ... мінімізуйте розмір запитів і кількість об'єктів бази даних, які потрібно вражати щоразу, коли один із цих запитів робиться. Позиція №1 полягає в тому, що навіть якщо він міг би бути реалізований належним чином, сам факт, що код повинен був би зробити декілька з'єднань, спричинить більше навантаження на зв’язок між веб-сервером та базою даних, а не зменшити його.

Рушійною силою дослідження є те, що кількість трафіку між нашим веб-сервером та сервером баз даних виходить з-під контролю.


7
На мій досвід, немає «правильної відповіді» на це. Існує баланс між затримкою та пропускною здатністю. Низька затримка може переносити багато маленьких запитів або навіть один великий; однак високі латентні зв’язки, як правило, краще перенести багато даних одночасно. Тим не менш, якщо пропускна здатність низька в конфігурації з високою затримкою, вам краще отримати менші шматки, щоб бути більш чуйними.

3
Можливо, пов’язана з проблемою n + 1 stackoverflow.com/questions/97197/…
Валера Колупаєв,

@ Валера: для зручності ось посилання, розміщене з цього питання: realsolve.co.uk/site/tech/hib-tip-pitfall.php?name=n1selects
rwong

4
"кількість трафіку між нашим веб-сервером та сервером баз даних виходить з-під контролю". Що це означає? Чи можете ви бути конкретними, у чому полягає справжня проблема? Чи є у вас проблеми з роботою? Ви робили профілювання та вимірювання? Укажіть, будь ласка, фактичні результати фактичних вимірювань. Інакше ми просто здогадуємось.
С.Лотт

Відповіді:


8

Якщо рушійною силою цього питання є занадто великий трафік, ви шукали кешування часто використовуваних об'єктів? Наприклад: Після того, як ви отримаєте об'єкти «Співробітник та Департамент» та «Супервайзор», можливо, було б доречно додати їм кеш, щоб, якщо вони знову їх запитають, вони вже знаходяться в кеші і не потрібно їх отримувати знову. Звичайно, кеш-пам'ять потребує того, щоб рідко використовувані об'єкти закінчувались, а також повинні мати можливість видаляти об'єкти, які були змінені програмою та збережені назад до бази даних.

Залежно від того, якою мовою та рамками ви користуєтесь, може вже існувати структура кешування, яка може виконати частину (або більшість) того, що вам потрібно. Якщо ви використовуєте Java, ви можете заглянути в Apache Commons-Cache (я не використовував його деякий час, і хоча він виглядає спокійним, він все ще доступний для використання, і він був досить пристойний, коли останній раз я його використовував).


3

Завжди будьте зрозумілі та зрозуміліші, коли ви щось пишете. Потім ви можете зробити рефактор, якщо і коли потрібно. Зробіть тестування навантаження, щоб знайти вузькі місця, у багатьох випадках його кількість викликає не кількість дзвінків, а погано написані.

Що стосується того, що класифікується як занадто багато, це залежить від програми. Для більшості веб-додатків все, що не перевищує 30 секунд, є майже прийнятним. Я б говорив з вашими користувачами щодо їхніх очікувань.


Що являє собою неправильно записаний db-дзвінок?
nu everest

3

Ваше запитання, мабуть, ґрунтується на припущенні, що ви повинні здогадатися, які дані знадобляться для будь-якої сторінки. Це не так. Це не так просто, як наївний підхід, але ви можете сконструювати свій код, щоб дізнатися, чи потрібні вам атрибути відділу чи керівника, перш ніж робити будь-які дзвінки в базу даних.


3

Це правила, якими я користуюсь, можливо, вони будуть вам корисні.

  1. Виміряйте спочатку! Я навіть не буду дивитись на код, який "може бути повільним", якщо я не можу побачити трафік, що надходить на цей ресурс, і цей ресурс реагує повільно.
  2. 1 запит = K запитів.Кількість розмов із базою даних повністю визначається видом запитуваного ресурсу; і ніколи за характером запиту чи стану цього ресурсу; У вашому прикладі це, мабуть, максимум 3 запити: 1 для працівників, 1 для підрозділів та 1 для керівників; Не має значення, скільки з них трапляється.
  3. Не запитуйте те, що ви не будете використовувати . Якщо це HTTP, про який ми говоримо, немає сенсу запитувати дані для подальшого; пізніше немає; кожен запит починається з чистого сланця. Іноді мені найбільше потрібно стовпців зі столу, але іноді мені потрібно лише одна-дві; коли я точно знаю потрібні мені поля, я попрошу саме це.
  4. Киньте апаратне забезпечення проблеми. Сервери дешеві; Іноді ви можете досягти достатньої продуктивності, просто перемістивши базу даних у коробку для полювання або надіслати деякі запити до репліки лише для читання.
  5. Спочатку недійсний кеш, потім реалізуйте кешування. Прагнення вводити часто використовувані або важко запитувати дані в кеш-пам'ять є сильним; але занадто часто вилучення невикористаних даних або закінчення терміну дії замінених даних не помічається. Якщо ви знаєте, як вийняти дані з кешу; тоді ви сміливо вкладаєте його в кеш; Якщо виявиться, що доцільніше визнати недійсним кеш, ніж просто виконати запит; тоді вам не знадобився кеш.

2

Обидві стратегії тут цілком справедливі. Для кожного є свої переваги та недоліки:

Один дзвінок для всіх 3 об’єктів:

  • буде виконувати швидше
  • ви отримаєте саме те, що вам потрібно в тому випадку, коли вам це потрібно
  • ймовірно, він може бути корисним лише в одному випадку (це може бути дуже поширеним випадком)
  • буде складніше підтримувати
  • доведеться підтримувати частіше (оскільки це зміниться, якщо зміниться будь-яка з 3-х схем об'єктів або потрібні дані)

Один виклик на об'єкт (всього 3 виклики)

  • Надає вам загальний виклик для заповнення одного екземпляра кожного типу об'єктів; потім їх можна використовувати самостійно
  • Буде більш рентабельним, оскільки структура запитів буде простішою.
  • Буде повільніше (необов'язково в 3 рази повільніше, але накладні витрати збільшені для тих самих даних)
  • Може спричинити проблеми із завантаженням непотрібних даних (витягування всього запису, коли вам потрібно одне поле, є марним)
  • Можуть викликати проблеми N + 1, коли існує багатозахисний зв’язок, якщо запит на один запис надсилається N разів, один на запис у колекції.

У відповідь на пару ваших занепокоєнь (№3 та 5 у другому списку) ... Що робити, якщо Супервізор та Департамент використовуються лише 1/3 (або менше) часу? Що робити, якщо код був розроблений для отримання всіх дітей, як тільки вперше посилався на них код, кодований, щоб містити його? ... це полегшило б більшу частину настороженості?
користувач107775

Якщо допоміжні об'єкти потрібні лише рідко, то в загальному випадку це буде працювати швидше (менше даних для отримання), але найгірший випадок буде повільнішим (ті ж дані або більше, отримані з використанням триразового накладного зв'язку з комп'ютера). Що стосується проблеми N + 1, то вам просто потрібно мати можливість архітектувати запит, який отримує список об’єктів, щоб мати змогу це зробити на основі зовнішнього ключа на "одну" сторону взаємозв'язку, а потім витягнути кілька рядків поза результатом запиту. Ви не можете використовувати версію запиту, яка повинна мати первинний ключ запису.
KeithS

1

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

Тому я вам не потрібні дані, не витрачайте пам'ять на отримання, щоб уникнути другої поїздки пізніше. Але якщо вам потрібна кількість даних, вам слід мінімізувати дзвінки на db.

Так що є обидва варіанти, і використовуйте кожен, де ситуація вимагає цього.

EDIT: Майте на увазі, що цей курс залежить також від вашої ситуації. Якщо, наприклад, його WebApp, ви повинні мати інші міркування, ніж якщо це настільний додаток, що звертається до БД у вашій мережі, на відміну від Web для WepApp.


А як бути, якщо ви пишете загальний код і не впевнені в тому, як буде використаний ваш код. Можливо, ви ніколи б не передбачили, що хтось не потребує Супервізора, але виявляється, що програма, над якою ви працюєте, є єдиною, яка потребує цього. Звичайно, ви можете написати окремі функції ... одну, щоб не включати її, а іншу для включення, але в який момент ваш загальний код починає вимагати занадто багато детальних знань, щоб використовувати?
користувач107775

@ user107775 Я зазвичай пишу лише дві функції для кожного випадку; той, який повертає лише значення властивостей, і той, який повертає клас із усіма пов'язаними класами. Це тому, що МОСТЕ раз, вам потрібні лише властивості. Таким чином, вам не потрібні детальні знання, лише один отримує основи, а інший все. Я вважаю це розумним балансом. (Однак деякі конкретні випадки вимагають більшої оптимізації, але це залежить від конкретного випадку).
AJC

1

Підключіться до БД, надішліть запит і проаналізуйте його, як правило, значний час у порівнянні з отриманням результатів, тому загальна тенденція полягає в тому, щоб об'єднати якомога більше запитів в один запит.

І все-таки це зробити за один кадр, зробить код неможливим. Замість цього зазвичай досягається додатковий рівень абстракції: код планує декілька запитів у міру необхідності, потім двигун аналізує це як один великий запит (можливо, використовуючи кеш на шляху), а потім відповіді надсилаються за потребою.

Звичайно, не завжди все можна отримати в одному запиті - у вас часто буде запит, який надає дані, необхідні для побудови наступного запиту, тому вам доведеться повторити його. Все-таки приголомшливі групи запитів і виконувати якомога більше одночасно краще, ніж сотні невеликих знімків до бази даних.

Отже, сплануйте те, що вам потрібно, запитайте та отримайте його, якщо потрібно більше, запитайте та завантажте його ще раз, а потім використовуйте дані для створення вмісту. Однозначно уникайте використання запитів баз даних, таких як локальна ініціалізація змінної, розпорошеної по коду.


1

Ми не знаємо, чи хотіли б про вашу заявку, щоб знати, який вибір ви винні в оптимізації занадто рано. Як часто використовуються дані Supervisor? Здається, це може бути марним, але ми не знаємо. Якщо ви будете тримати їх окремо, ви зможете відстежувати вашу систему, щоб побачити, як часто вони в кінцевому підсумку використовуються разом. Тоді ви можете прийняти рішення просто поєднати їх в один дзвінок. Інакше, якщо ви почнете створювати шийку для пляшок за допомогою цього великого дзвінка, звідки ви починаєте нести проблеми? Важко визначити, що має сенс опустити. До цього процесу може бути додано більше полів даних.

Було б цікаво дізнатися, скільки цього відбувається з db пам'яті проти диска. Нічого не змушує мене відчувати, що відділ більш-менш імовірно зміниться порівняно з адресою.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.