Дублікат стовпця для швидших запитів?


30

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

У мене є такі таблиці

Проекти

  • ід
  • назва

Клієнти

  • ід
  • id_project
  • назва

Виплати

  • ід
  • id_customer
  • дата
  • сума

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

SELECT FROM payments where id_customer in (SELECT id from customers where id_project = 5)

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


1
тому запит не є проблемою для сучасних RDBMS (або краще, використовуйте приєднання).
garik

4
Погодьтеся, отримайте план запиту для підселектора проти приєднайтесь і подивіться, який краще
Гай

1
Я думаю , що це ТАК пост варто подивитися, так як @igor згадувалося про використання JOIN або IN
CoderHawk

Відповіді:


52

Здається, ви запитуєте, чи має сенс денормалізація .

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

Відповідь завжди "це залежить", тому ось моє правило:

Якщо ...

  • обсяг даних не великий
  • ви вже не робите тонни приєднань
  • та / або продуктивність бази даних наразі не є вузьким місцем

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

Я б денормалізував лише тоді, коли ...

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

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


9

Ви б краще написати запит як:

SELECT payments.*
FROM   customers
JOIN   payments 
ON     payments.id_customer = customers.id
WHERE  customers.id_project = 5

Хоча це здається менш стислим, і хороший планувальник запитів побачить, що ви намагаєтеся зробити, і запустить ваш кореляційний підзапит як приєднується вище, але поганий планувальник запитів може в кінцевому підсумку зробити індексне сканування payments.id_customer(якщо у вас є відповідний індекс ) (або ще гірше, сканування таблиці), а не робити ефективніше. Навіть хороший планувальник запитів може не побачити оптимізації, якщо розташування цього запиту буде обгорнуто чимось складнішим. Висловлення відносин як з'єднання, а не підзапиту може мати більше значення, ніж зміна вашої структури даних.

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

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

customer     project      payment
--------     --------     -------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer     

або якщо це менш нормалізується (хоча я сумніваюся, що це буде потрібно):

customer     project      payment
--------     --------     --------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer 
           `------------- customer    

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


3
Перше правило виконання: Ніколи не використовуйте * у виробництві!
Брайан Балсун-Стентон

@Brian: Дуже вірний пункт. А також потенційні наслідки для продуктивності, уникнення * у вибраних статтях, також дозволяє уникнути проблем із впорядкуванням стовпців у режимі перегляду в MSSQL, якщо sys.depends виходить з кілтера через те, що використовується DROP VIEW+ . CREATE VIEWALTER VIEW
Девід Спіллетт

@Brian я поклав * для простоти написання.
Габріель Соломон

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

4

У деяких базах даних у вас є можливість створити "Матеріалізовані перегляди" замість складних VIEWS з великою кількістю даних на основі складного запиту. Це можна використовувати для уникнення денормалізації в історично вирощеній системі додатків. Якщо ви вирішите використовувати " Матеріалізовані перегляди "Ви повинні мати чітке уявлення про методи оновлення та обсяг пам’яті, який буде використаний Матеріалізованим видом ...

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