Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Zoptymalizuj zapytanie (indeksowanie, WYJAŚNIJ) Mysql

Ciągle zapominam o tym terminie, ponieważ pojawia się on bardzo rzadko, ale tak czy inaczej, twoje indeksy nie mogą być zoptymalizowane za pomocą funkcji MIESIĄC() i ROK(), ponieważ są one funkcjami na danych bazowych. Stosując datę RANGE, mogą. Możesz więc zachować swój miesiąc/rok, tak jakby coś zostało utworzone w styczniu 2021 i zaktualizowane w marcu 2021, ale dodatkowo dodając "i c.date_created>=current_date AND current_date <=c.date_updated" , MOŻESZ wykorzystać indeks, jeśli zawiera on datę utworzenia (mniej ważne w tym przypadku dla daty aktualizacji.Podobnie do drugiej tabeli.

Ponadto, gdy masz sprzężenie lewe ze stołu „a” do tabeli „c”, to zastosowanie gdzie, to prawie tak, jakbyś próbował wymusić łączenie, ale pozostaje lewy ze względu na OR.

Przeniosłbym warunek oparty na "c" do lewego łączenia, a następnie po prostu przetestował znaleziony tam rekord jako NULL lub nie.

Chociaż nie jest to jasne (nie zostało to wyjaśnione, kiedy zapytałem), MYŚLĘ, że kiedy tworzony jest nowy rekord „A”, system może faktycznie umieścić datę utworzenia zarówno w dacie utworzenia, jak i dacie aktualizacji. JEŚLI TAK JEST, to wystarczy odpytać/odnieść się do ostatniego zaktualizowanego pola daty z bieżącym miesiącem/rokem działalności. Jest to teraz wymóg PRIMARY dla klauzuli WHERE — NIEZALEŻNIE od podstawowego warunku LUB w tabeli „C”.

Dodatkowo, ponieważ month() i year() nie są sargeable (Dzięki Ollie), wykonuję wstępne zapytanie, aby uzyskać początek bieżącego i przyszłego miesiąca, abym mógł zbudować

WHERE > beginning of this month and LESS than beginning of next month

Jeśli chodzi o indeksy, zacząłbym aktualizować

loan_applications_tbl ( date_created, date_updated, loan_status, current_loan, ippis )
topup_or_reapplication_tbl ( ippis, status, current_loan, date_created, date_updated )

Ostatnie zapytanie do wypróbowania.

SELECT 
        a.id, 
        a.user_unique_id, 
        a.loan_location, 
        a.ippis, 
        a.tel_no,
        a.organisation, 
        a.branch, 
        a.loan_agree, 
        a.loan_type, 
        a.appr, 
        a.sold, 
        a.loan_status, 
        a.top_up, 
        a.current_loan, 
        a.date_created, 
        a.date_updated, 
        c.loan_id, 
        c.user_unique_id tu_user_unique_id, 
        c.ippis tu_ippis, 
        c.top_up_approved,
        c.loan_type tu_loan_type, 
        c.dse, 
        c.status, 
        c.current_loan tu_current_loan,
        c.record_category, 
        c.date_created tu_date_created,
        c.date_updated tu_date_updated 
    FROM 
        -- this creates inline mySQL variables I can use for the WHERE condition
        -- by doing comma after with no explicit join, it is a single row
        -- and thus no Cartesian result, just @variables available now
        ( select 
                -- first truncating any TIME portion by casting to DATE()
                @myToday := date(curdate()),
                @howFarBack := date_sub( @myToday, interval 6 month ),
                -- now subtract day of month -1 to get first of THIS month
                @beginOfMonth := date_sub( @myToday, interval dayOfMonth( @myToday ) -1 day ),
                -- and now, add 1 month for beginning of next
                @beginNextMonth := date_add( @beginOfMonth, interval 1 month ) ) SqlVars,

        loan_applications_tbl a
    
            LEFT JOIN topup_or_reapplication_tbl c
                ON  a.ippis = c.ippis   
                AND c.current_loan='1'
                AND c.status IN ('pending', 'corrected', 'Rejected', 
                                'Processing', 'Captured', 'Reviewed', 'top up') 
                AND 
                (
                        (@beginOfMonth <= c.date_created 
                    AND c.date_created < @beginNextMonth)
        
                OR
                        (@beginOfMonth <= a.date_updated 
                    AND a.date_updated < @beginNextMonth )
                )

    WHERE
            -- forces only activity for the single month in question
            -- since the "a" table knows of any "updates" to the "C",
            -- its updated basis will keep overall restriction to any accounts

            -- updated within this month in question only
            -- testing specifically for created OR updated within the
            -- current month in question

        a.date_created >= @howFarBack
        AND
            (
                    (@beginOfMonth <= a.date_created 
                AND a.date_created < @beginNextMonth)
        
            OR
                    (@beginOfMonth <= a.date_updated 
                AND a.date_updated < @beginNextMonth )
            )
        
        -- and NOW we can easily apply the OR without requiring
        -- to run against the ENTIRE set of BOTH tables.
        AND (
                    c.ippis IS NOT NULL
                OR 
                    ( a.loan_status IN (  'pending', 'corrected', 'Rejected', 'Processing', 
                            'Captured', 'Reviewed', 'top up')
                    AND (   
                            a.current_loan = '1' 
                        OR  (   a.current_loan = '0' 
                            AND a.loan_status IN ('Approved', 'Closed')
                            )
                        )
                    )
            )

KOMENTARZE KOŃCOWE DO ZAPYTANIA

Zmodyfikowałem zapytanie, a także indeks podstawowy w pierwszej tabeli, aby INCLUDE (pierwsza pozycja) data utworzenia rekordu. Dodałem również dodatkową zmienną @howFarBack, aby była to maksymalny czas powrotu do rozważenia przy pożyczce. Zwlekałem z 6 miesięcy wstecz. Czy kiedykolwiek musiałbyś rozważyć pożyczkę na konto starsze niż 6 miesięcy? A może konto „a” rejestruje coś, co może sięgać 10 lat wstecz i warto je uwzględnić? Mam wrażenie, że jest to nowa data dodania WNIOSKU KREDYTOWEGO. Jeśli tak, umożliwienie cofnięcia się o 6 miesięcy wstecz przed zatwierdzeniem, sfinalizowaniem i anulowaniem nadal uniemożliwiłoby przejrzenie tylu miesięcy danych w przeszłości.

W klauzuli WHERE dodałem wyraźny dodatek dla CREATED_DATE>=@howFarBack. Nigdy nie byłoby możliwe utworzenie rekordu podrzędnego, nie mówiąc już o aktualizacji w dowolnym momencie przed pierwotną datą dodania. Wymusi to zakwalifikowanie się tylko do aktywności w bieżącym miesiącu LUB DO PRZODU.

Np.:utwórz pożyczkę 28 kwietnia. Uruchamiając zapytanie, początek miesiąca to 1 kwietnia, ale MNIEJ niż 1 maja (pozwala to na uwzględnienie 30 kwietnia o 23:59:59)

Teraz wkraczamy w maj, a zmiana kredytu następuje 4 maja. Jesteśmy w nowym miesiącu, a @howFarBack nadal pozwala starszym aplikacjom do grudnia 2020 r. BYĆ MOŻLIWE zakwalifikować się w porównaniu z całą tabelą aplikacji, które mogą sięgać roku 2005, o ile wiemy. Zawsze pozostajesz z najbardziej aktualnymi danymi i możesz łatwo zmienić @howFarBack jako maksymalny czas powrotu. Powinno to pomóc w spełnieniu Twoich potrzeb w zakresie wydajności.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL - Pobierz wartość wiersza z innej tabeli w zależności od wartości wiersza w tabeli

  2. mysql + php pobierają liście potomne ze ścieżką

  3. Mysql pracujący z listą oddzieloną przecinkami - Tabela połączeń

  4. Nie można pobrać pliku binarnego w PHP

  5. Mysql SET NAMES UTF8 - jak się go pozbyć?