Post
#1
|
|
|
Grupa: Zarejestrowani Postów: 1 086 Pomógł: 8 Dołączył: 10.12.2003 Ostrzeżenie: (0%)
|
Zaprojektowałem bazę danych do przechowywania dokumentów sprzedażowych z ich pozycjami. W uproszczeniu do istotnych kolumn wygląda ona tak:
Kod ┌────────────┐ ┌────────────┐ │ invoices │ │ items │ ├────────────┤ ├────────────┤ │ id │ 1 n │ id │ │ date ├────────┤ invoice_id │ │ number │ │ position │ │ contractor │ │ name │ └────────────┘ │ quantity │ │ price │ └────────────┘ Jak widać, w tabeli "invoices" nie przechowuję sumy pozycji. Dla wygody stworzyłem więc widok: Kod CREATE VIEW invoices_summary AS SELECT invoices.*, SUM(items.quantity * items.price) AS total FROM invoices LEFT JOIN items ON (items.invoice_id = invoices.id) GROUP BY invoices.id Powyższe działało bardzo fajnie na MySQL aż do rozrośnięcia się danych. Obecnie wyciągnięcie choćby jednego wiersza z "invoices_summary" trwa ok. 2 sekund. Przyczyną kulejącej wydajności jest ograniczenie algorytmu MERGE w MySQL: https://dev.mysql.com/doc/refman/8.0/en/view-algorithms.html MySQL nie potrafi użyć MERGE gdy widok korzysta z funkcji grupujących. Stąd każde zapytanie do "invoices_summary" to generowanie tymczasowej tabeli na podstawie setek tysięcy. Gdyby MySQL "przeniosło" moje WHERE do wnętrza widoku, wystarczyłoby kilkadziesiąt wierszy. Szukam pomysłu jak wybrnąc z tej sytuacji i potrzebuję pomocy. Rozważałem:
Czy ktoś ma jakieś inne pomysły albo ogólnie sugestie? |
|
|
|
![]() |
Post
#2
|
|
|
Grupa: Zarejestrowani Postów: 1 086 Pomógł: 8 Dołączył: 10.12.2003 Ostrzeżenie: (0%)
|
Dzięki wszystkim za odpowiedzi, wątpliwości co do problemów wydajnościowych (przy nieprzesadnie wielu danych) nakierowały mnie na dalsze podejrzenia i poszukiwania. Ostatecznie mieliście rację, do problemów (poza widokami) przyczynił się jeszcze jeden - nieświadomie "zatajony" - fakt.
Nadmieniłem, że operuję na cenach netto, brutto i stawkach VAT (nie wspomniałem jedynie o rabatach procentowych). Otóz do wyliczania wartości brutto (dla "ułatwienia") stworzyłem sobie funkcje:
Dzięki temu mam ładnie wyglądające zapytanie SELECT price_to_total_gross(price, discount), quantity, vat_rate). Niektórzy może już widzą mój błąd. Okazuje się, że składowane funkcje są potwornie wolne w MySQL. Przy kilkuset wierszach nie byłoby tego widać. Tu jednak na problem funkcji nakładają się nieoptymalne widoki, które powodują wyliczanie całej tymczasowej tabeli. To oznacza stosowanie wolnych funkcji dla kilkudziesięciu tysięcy wierszy. Mam więc kilka rozwiązań, chociaż żadne nie jest idealne, ale przynajmniej zrozumiałem co się dzieje. Będę myślał o:
Ewentualnie zostaje użycie triggerów do imitowania zmaterializowanego widoku. Na razie składanim się ku triggerowi wyliczającemu wynikowe kolumny. To od razu uprości kod SQL i pozbycie się widoków nie będzie takie bolesne. Sprawdź jeszcze wynik EXPLAIN SELECT... EXPLAIN to w MySQL jakiś żart (IMG:style_emoticons/default/sad.gif) 3 bezwartościowe informacje (wiersze)Albo zmień bazę na postgresa, stwórz sobie widok zmaterializowany i ogólna wydajność pewnie też będzie szybsza. Super sprawa z tymi widokami zmaterializowanymi, zapomniałem, że takie coś istnieje (poza MySQL przynajmniej).Wywal ten widok i zakoduj zapytanie w aplikacji a potem go reużywaj. Strasznie dziwne że przy takiej ilości danych to kuleje. A byłem taki dumny ze swoich widoków i prostego kodu SQL w aplikacji (IMG:style_emoticons/default/tongue.gif) Serwer to dzielony hosting mydevil, MySQL 5.7.26, ale problem obserwuję też loklanie na MadiaDB 10.4.13.Jaką masz wersję mysql jeszcze, jakie zasoby serwera. I na prawdę, wywal widok w cholerę (IMG:style_emoticons/default/smile.gif) Nie ma co na siłę trzymać się normalizacji, czasem denormalizacja nie jest zła, a wręcz wskazana (np. przez względy wydajnościowe). Dodaj do tabeli z fakturami kolumnę z sumą i aktualizuj jej wartość triggerem (w zasadzie na każde zdarzenie :/). Od strony aplikacji nie dotykaj tej kolumny, nie ingeruj w jej wartość. Również fajny pomysł z triggerem, zawsze to jakieś rozwiązanie przy braku zmaterializowanych widoków.
Ten post edytował Zajec 15.09.2020, 21:12:36 |
|
|
|
Zajec Projekt i wybór bazy - normalizacja oraz wydajność widoków 12.09.2020, 11:49:17
trueblue 1. Ile obecnie jest tych danych (faktur i pozycji)... 12.09.2020, 12:12:23 
Zajec Cytat(trueblue @ 12.09.2020, 13:12:23... 12.09.2020, 12:31:01
trueblue 1. To tyle co nic. Założone są indeksy na kolumny ... 12.09.2020, 12:37:14 
Zajec Cytat(trueblue @ 12.09.2020, 13:37:14... 12.09.2020, 12:47:40
trueblue Sprawdź jeszcze wynik EXPLAIN SELECT... 12.09.2020, 13:26:05
viking Albo zmień bazę na postgresa, stwórz sobie widok z... 12.09.2020, 13:30:49
Pyton_000 Wywal ten widok i zakoduj zapytanie w aplikacji a ... 12.09.2020, 16:17:47
phpion Nie ma co na siłę trzymać się normalizacji, czasem... 13.09.2020, 08:51:46
trueblue Cytat(Zajec @ 15.09.2020, 22:10:43 ) ... 16.09.2020, 06:04:45
Zajec Cytat(trueblue @ 16.09.2020, 07:04:45... 16.09.2020, 06:21:51 ![]() ![]() |
|
Aktualny czas: 30.12.2025 - 11:33 |