Що швидше, один великий запит чи багато невеликих запитів?


68

Я працюю в різних компаніях, і я помітив, що деякі з них вважають за краще мати погляди, які приєднаються до столу з усіма його «родичами». Але тоді в додатку кілька разів нам потрібно використовувати лише 1 стовпець.

Тож було б швидше просто зробити простий вибір, а потім "приєднати" їх до системного коду?

Система може бути php, java, asp, будь-якою мовою, яка підключається до бази даних.

Отже, питання полягає в тому, що швидше переходити з серверної сторони (php, java, asp, ruby, python ...) до бази даних, виконайте один запит, який отримає все, що нам потрібно, або перехід із серверної частини до бази даних та запустіть a запит, який отримують стовпці з однієї таблиці одночасно?


2
Яку реалізацію 'SQL' ви використовуєте? MySQL, Microsoft SQL Server, Oracle, Postgresql тощо? Оновіть свій тег.
RLF

1
Mysql і Postgresql
sudo.ie

6
Мій досвід полягає в тому, що MySQL не любить складні запити і, як правило, швидше з дуже просто запитами (але більше). Оптимізатор запитів Postgres набагато краще, і там, як правило, ефективніше запускати один великий запит.
a_horse_with_no_name

3
@a_horse_with_no_name Це дуже широке узагальнення, особливо в контексті цього питання. Оптимізатор MySQL насправді дуже простий за дизайном, і може спричинити проблеми з приєднаннями та підзапитими, особливо на старих версіях MySQL, які в іншому випадку створюють швидші плани в PostgreSQL, в той час як MySQL може бути дуже швидким для чистого навантаження OLTP. Однак, в контексті питання, один великий запит буде швидшим, що, скажімо, - в гіршому сценарії - SELECT всередині циклу програмування (незалежно від використовуваної RDBMS).
jynus

2
@jynus: ну, питання є дуже широким (плюс я сказав: «в моєму досвіді» , - інші люди можуть мати різний досвід). Запит всередині LOOP ніколи не є хорошою ідеєю і майже завжди є результатом поганого дизайну або недостатнього розуміння того, як працювати з реляційною базою даних.
a_horse_with_no_name

Відповіді:


68

Що стосується вашого питання, це тема ПРИЄДНАЙТЕСЬ ДО РОЗВИТКУ.

Згідно Page 209 Книги

Високопродуктивний MySQL

Ви можете розкласти об'єднання, виконавши кілька запитів на одній таблиці замість багатопоточного з'єднання, а потім виконавши приєднання в програмі. Наприклад, замість цього єдиного запиту:

SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id = tag.id
JOIN post ON tag_post.post_id = post.id
WHERE tag.tag = 'mysql';

Ви можете запустити ці запити:

SELECT * FROM tag WHERE tag = 'mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);

Чому на землі ти це зробив би? На перший погляд це виглядає марно, адже ви збільшили кількість запитів, не отримуючи нічого взамін. Однак така реструктуризація може насправді дати значні переваги у виконанні:

  • Кешування може бути більш ефективним. Багато додатків кешують "об'єкти", які відображають безпосередньо в таблиці. У цьому прикладі, якщо об’єкт із тегом mysqlуже кешований, програма пропустить перший запит. Якщо ви знайдете публікації з ідентифікатором 123, 567 або 908 в кеші, їх можна видалити зі IN()списку. Кеш запитів також може виграти від цієї стратегії. Якщо лише одна з таблиць часто змінюється, розкладання об'єднання може зменшити кількість недійсних кеш-пам'яті.
  • Виконання запитів індивідуально може іноді зменшити суперечку із блокуванням
  • Приєднання до програми полегшує масштабування бази даних, розміщуючи таблиці на різних серверах.
  • Самі запити можуть бути ефективнішими. У цьому прикладі використання IN()списку замість з'єднання дозволяє MySQL сортувати ідентифікатори рядків та отримувати рядки більш оптимально, ніж це можливо при об'єднанні.
  • Ви можете зменшити зайвий доступ до рядків. З'єднання в програмі означає отримання кожного рядка лише один раз., Тоді як об'єднання в запиті - це по суті денормалізація, яка може неодноразово отримувати доступ до одних і тих же даних. З тієї ж причини, така реструктуризація також може зменшити загальний мережевий трафік та використання пам'яті.
  • Певною мірою ви можете розглядати цю техніку як вручну реалізовувати хеш-з'єднання замість алгоритму вкладених циклів, який MySQL використовує для виконання з'єднання. Хеш-з'єднання може бути більш ефективним.

Як результат, приєднання до програми в програмі може бути більш ефективним, коли ви кешуєте та використовуєте багато даних із попередніх запитів, ви поширюєте дані на декілька серверів, замінюєте приєднання IN()списками або кілька разів посилається на ту саму таблицю.

ОБМЕЖЕННЯ

Мені подобається перша куля, тому що InnoDB є дещо важкою, коли вона перевіряє кеш запитів.

Щодо останньої точки, я написав публікацію ще 11 березня 2013 року ( Чи є різниця у виконанні між умовою JOIN та умовою WHERE? ), Що описує алгоритм вкладеного циклу. Прочитавши його, ви побачите, наскільки добре може бути розкладання приєднання.

Що стосується всіх інших пунктів книги , розробники дійсно шукають продуктивність як підсумок. Деякі покладаються на зовнішні засоби (за межами програми) для підвищення продуктивності, таких як використання швидкого диска, отримання більше процесорів / ядер, налаштування двигуна зберігання даних та налаштування файла конфігурації. Інші згорнутимуться та напишуть кращий код. Деякі можуть вдатися до кодування всієї бізнес-аналітики в Збережених процедурах, але все ще не застосовують декомпозицію приєднання (див. Які аргументи проти або для введення логіки програми в рівень бази даних? Разом з іншими повідомленнями). Все залежить від культури та толерантності кожного магазину розробників.

Деякі можуть бути задоволені роботою та більше не торкатися коду. Інші просто не розуміють, що є великі переваги, які можна отримати, якщо спробувати приєднатися до складу.

Для тих розробників, які бажають ...

СПРОБУВАТИ !!!


3
Що стосується цього посилання про зміну на 3 запити ... Я знаю і поважаю Барона, Вадима та Петра, але я не згоден з цією оманливою пропозицією. Більшість аргументів на користь розколу настільки рідкісні, що їх не варто згадувати. Дотримуйтесь одного запиту з JOINs, тоді давайте попрацюємо над його вдосконаленням.
Рік Джеймс

2
@RickJames Я погоджуюся з духом вашого коментаря. Протягом багатьох років я бачив, як одні приєднуються до роботи з декомпозиції, а для інших - невдачі. Навіть при належному наборі навичок SQL це може спрацювати проти вас, якщо декомпозиція об'єднання не буде виконана правильно. На моєму нинішньому роботодавці багато хто звертається до масштабування любові, особливо коли є спадковий код та наявні глибокі кишені. Тим, хто має смак ікри, але бюджети салату з яєць, приєднання до розкладання може бути ризиком, але це потрібно зробити правильно.
RolandoMySQLDBA

Я хотів би побачити, як це працює в середовищі Oracle, якби у мене були права та час.
Рік Хендерсон

Ще один спосіб, який може бути швидшим, полягає в тому, що якщо ви робите замовлення, то для замовлення менших списків загалом буде менше розрахунків, ніж для замовлення одного великого списку.
Еван Сірокий

24

У Postgres (і, мабуть, будь-яка RDBMS у подібній мірі, MySQL в меншій мірі) менше запитів майже завжди набагато швидше.

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

Не кажучи про додаткову роботу, яка повинна бути виконана клієнтом, поєднання результатів, що, як правило, набагато повільніше. RDBMS спеціалізується на такому завданні та операції базуються на оригінальних типах даних. Відсутність передачі textта повернення проміжних результатів або перетворення на початкові типи клієнта, що може призвести навіть до менш правильних (або неправильних!) Результатів. Подумайте про числа з плаваючою комою ...

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

Якщо кілька запитів означають безліч зворотних поїздок до сервера баз даних, ви також збираєте багаторазові затримки мережі та накладні транзакції, можливо, навіть накладні витрати на з'єднання. Великі, великі втрати.

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

Пов’язане запитання щодо SO:

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


Щось із цікавості ви вважаєте дуже великим ?
Sablefoste

@Sablefoste: Дуже багато залежить від вашої схеми доступу. Найважливішим моментом є те, коли паралельні транзакції починають чергуватися, чекаючи виходу блоків. Або якщо ви накопичите достатньо замків, щоб з'їсти значну частину своїх ресурсів. Або якщо ваші запити працюють досить довго, щоб перешкоджати автовакууму ...
Ервін

Але якщо ми скористаємося дещо типовою ситуацією - запит, який використовує зовнішнє з'єднання і повертає безліч зайвих даних для "батьківської" таблиці, які потім повинні бути проаналізовані та відсортовані додатком (швидше за все, деякою бібліотекою ORM) порівняно з a малий вибір, який спочатку отримує всі необхідні ідентифікатори, а потім ще один менший вибір із IN () замість зовнішнього з'єднання? Чи не буде другий підхід більш ефективним (враховуючи як БД, так і споживаний процесор CPU та пропускну здатність зв'язку)?
JustAMartin

1
@JustAMartin: Це виглядає як вид запиту, який майже напевно швидше при обробці планувальників запитів RDBMS - припускаючи правильні запити. Щодо returns lots of redundant data for "parent" table: Чому ви повертаєте зайві дані? Повертайте лише потрібні вам дані.
Ервін Брандстеттер

1
При зовнішньому з'єднанні RDBMS повертає дані з батьківської таблиці, дублюються для кожної приєднаної дитини, що означає деякий накладний обсяг мережі та пам'яті, а потім деякий додатковий аналіз в інструменті ORM, щоб викинути дублікати батьківських значень і зберегти лише одного з батьків з п ятьма дітьми. Таким чином, за допомогою одного запиту ми економимо на ефективній роботі планувальників запитів RDBMS, менше мережевих запитів (або локальних труб), але втрачаємо додаткові непотрібні корисні навантаження та переміщення даних навколо в бібліотеці ORM. Гадаю, це як завжди - виміряйте, перш ніж оптимізувати.
JustAMartin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.