Чи краще розділити великий запит на кілька менших запитів?


13

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

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

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY RAND() 
LIMIT %2$d

Який найкращий спосіб зробити це?

Відповіді:


14

Я збираюся не погоджуватися на великі і складні запити з datagod тут. Я бачу це лише як проблеми, якщо вони неорганізовані. Це залежить від продуктивності, але це майже завжди краще, оскільки планувальник має набагато більше свободи у пошуку інформації. Однак великі запити потрібно писати з урахуванням ремонту. Загалом, я виявив, що простий, добре структурований SQL легко налагодити, навіть коли один запит надходить на 200+ рядків. Це тому, що зазвичай ви маєте досить гарне уявлення про те, з якою проблемою ви маєте справу, тому в запиті є лише кілька областей, які вам доведеться перевірити.

Проблеми з технічним обслуговуванням, IME, виникають, коли структура SQL розпадається. Довгі складні запити в підборах погіршують читабельність та усунення неполадок, як і вбудовані перегляди, і обох цих слід уникати у довгих запитах. Натомість використовуйте VIEW, якщо можете (зауважте, якщо ви перебуваєте на MySQL, перегляди не так добре, але в більшості інших db-файлів вони є), і використовуйте загальні вирази таблиці, де це не працює (MySQL не підтримує ці btw).

Довгі складні запити працюють досить добре, як з ремонтом, так і з приводу продуктивності, коли ви зберігаєте свої пункти, де пункти прості, і де ви робите стільки, наскільки можете, приєднуючись замість підселектів. Мета полягає в тому, щоб "записи не відображалися" надає вам декілька дуже конкретних місць у запиті, щоб перевірити (чи потрапляє випадок приєднання чи відфільтрований у пункті де?) І так команда з обслуговування насправді може підтримувати речі.

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

Редагувати: Ви згадуєте, що це MySQL, тому погляди навряд чи добре спрацюють, і CTE не викликає сумніву. Крім того, наведений приклад не особливо довгий і складний, тому це не проблема.


Примітка. У мене були запити (не в MySQL, але все ж ...), які були довгими і складними, щоб генеровані плани запитів були не оптимальними. У цих випадках ви дійсно можете отримати швидші результати, розбиваючи один надзвичайно складний запит на два менш складні запити. Однак, це рідко, і я, як правило, напишу складний запит і з’ясую, чи є проблема, а не розбивати запит на більш дрібні шматки.
RDFozz

8

Як хтось, хто повинен підтримувати / очищати ці великі і складні запити, я б сказав, що набагато краще розбити їх на кілька невеликих легких для розуміння фрагментів. З точки зору продуктивності це не обов'язково краще, але ви, принаймні, даєте SQL кращі шанси придумати хороший план запитів.

Полегшіть життя людям, які стежать за вами, і вони скажуть про вас добрі речі. Складіть їм важко, і вони проклинать вас.


2
недоліком ряд простих запитів є те, що стан суттєво змінюється в них, що робить загальну налагодження програми складнішою. Тобто ви можете налагоджувати великі запити SQL часто у вигляді дерев, але код програми отримує налагоджений оператор шляхом заяви, перевіряючи, як змінюється стан у операторах. Справжні проблеми пов'язані з тим, що підселектори та вбудовані погляди також є їхніми власними деревами .....
Кріс Траверс

У моєму випадку єдиний, хто повинен керувати БД і кодом - це я. І в основному моє запитання стосувалося запиту щодо продуктивності.
Хамед Момені

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

5

Мої 2 центи на 2 ключові слова запит-ефективність та масштабованість:

Запрошення-Ефективність: Паралелізм SQL Server вже робить дуже гарну роботу, розбиваючи запити на багатопотокові пошуки, тому я не впевнений, скільки покращення продуктивності запитів ви побачите, виконуючи це для SQL Server. Вам доведеться подивитися на план виконання, щоб побачити, яка ступінь паралелізму ви отримуєте, коли ви його виконуєте, проте порівняти результати в обох напрямках. Якщо вам доводиться використовувати підказку для запитів, щоб отримати таку ж чи кращу ефективність, то IMO цього не варто, оскільки підказка запиту може бути не оптимальною пізніше.

Масштабованість: Читання запитів може бути простішим, як заявлено у datagod, і розбиття їх на окремі запити має сенс, якщо ви можете використовувати нові запити і в інших областях, але якщо ви не збираєтесь використовувати їх і для інших дзвінків, тоді буде ще більше збережених програм для управління 1 завданням, і IMO не сприятиме масштабуванню.


2
RE: "SQL Server" посилання, хоча ОР не вказав жодної конкретної RDBMS, я підозрюю, що вони є на MySQL із задніх кліщів іLIMIT
Мартін Сміт

@MartinSmith Ви підозрюєте правильно. Це MySQL.
Хамед Момені

2

Деколи не існує іншого вибору, як розділити великий / складний запит на невеликі запити. Найкращим способом визначити це було б використання EXPLAINоператора з SELECTтвердженням. Кількість слідів / сканів, які ваш db збирається отримати для отримання даних, є результатом значень "рядків", повернутих вашим EXPLAINзапитом. У нашому випадку ми мали запит, що поєднує 10 таблиць. Для конкретного запису, цей слід склав 409 мільйонів, що блогував наш БД і підштовхував використання процесора нашого сервера БД понад 300%. Нам вдалося отримати ту саму інформацію, розділивши запити набагато швидше.

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

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