sql >> Database teknologi >  >> RDS >> Mysql

Optimer forespørgsel (indeksering, FORKLAR) Mysql

Jeg bliver ved med at glemme udtrykket, da det kommer meget sjældent op for mig, men under alle omstændigheder kan dine indekser ikke optimeres ved at bruge MONTH() og YEAR(), da de er funktioner på de underliggende data. Ved at anvende en dato RANGE kan de. Så du kan beholde din måned/år, som hvis noget blev oprettet i januar 2021 og opdateret i marts 2021, men derudover tilføje en "and c.date_created>=current_date AND current_date <=c.date_updated" , du KAN bruge indekset, hvis det har oprettelsesdatoen i sig (mindre vigtigt i dette tilfælde for den opdaterede dato. På samme måde for din anden tabel.

Derudover, når du har din venstre-join fra "a" til "c"-tabellen og derefter anvender hvor, er det næsten som om du forsøger at tvinge sammenføjningen, men forbliver venstre-join på grund af OR.

Jeg ville flytte den "c"-baserede betingelse til venstre-join og derefter bare teste for posten fundet der som NULL eller ej.

Selvom det ikke er klart (blev ikke afklaret, da jeg spurgte), TROR JEG, at når en ny "A"-record oprettes, kan systemet faktisk lægge oprettelsesdatoen ind i både oprettelsesdatoen og datoen for opdatering. HVIS DETTE ER TILFÆLDET, så behøver vi kun at forespørge/bekymre det sidst opdaterede datofelt med den aktuelle måned/år for aktivitet. Det er nu det PRIMÆRE krav til where-sætningen -- UANSET den underliggende OR-betingelse til "C"-tabellen.

Da måneden() og året() desuden ikke er sargeable (Tak Ollie), jeg laver en forespørgsel for at få begyndelsen af ​​den nuværende måned og næste måned, så jeg kan bygge en

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

Hvad angår indekser, ville jeg begynde at opdatere til

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

Sidste forespørgsel at prøve med.

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')
                            )
                        )
                    )
            )

SLUTTEKOMMENTARER TIL FORESPØRGSEL

Jeg ændrede forespørgslen og også det primære indeks på den første tabel til at INKLUDERE (første position) datoen for oprettelsen af ​​posten. Jeg har også tilføjet en ekstra variabel @howFarBack for at være den maksimale tilbagegangstid at overveje for et lån. Jeg misligholdt for 6 måneder siden. Ville du nogensinde skulle overveje en given konto ældre end 6 måneder for et lån? Eller er "a"-kontoens registreringer noget, der kunne gå 10 år tilbage, og som gerne vil medtages? Mit indtryk er, at det er en ny LÅNEANSØGNING tilføjelsesdato. Hvis det er tilfældet, vil det stadig forhindre, at man går gennem så mange måneders data historisk set, hvis man giver mulighed for at gå 6 måneder tilbage, før det er godkendt, afsluttet, annulleret.

I WHERE-sætningen tilføjede jeg eksplicit tilføjelse til CREATED_DATE>=@howFarBack. Det ville aldrig være muligt for en underordnet post at blive oprettet, endsige opdateret på noget tidspunkt før den oprindelige tilføjelsesdato. Dette vil tvinge kun den aktuelle måneds aktivitet ELLER FREM til at kvalificere sig.

Eks:Opret et lån den 28. april. Så ved at køre forespørgslen er begyndelsen af ​​måneden den 1. april, men MINDRE end den 1. maj (dette tillader medtagelse af den 30. april kl. 23:59:59)

Nu går vi ind i maj, og en ændring på lånet sker den 4. maj. Vi er inde i en ny måned, og @howFarBack tillader stadig ældre applikationer, så langt som til december 2020, MULIGT at kvalificere sig i forhold til hele tabellen over applikationer, der kan gå så langt tilbage som 2005, så vidt vi ved. Du forbliver altid med de mest aktuelle data, og du kan nemt nok ændre @howFarBack som den maksimale tilbagegangstid. Dette burde hjælpe dine præstationsbehov.




  1. Hvordan installerer jeg Rails MySQL-adapteren?

  2. Script til import af mysql-database fra en bestemt filplacering

  3. Hvorfor forbinder du ikke Android til databasen direkte?

  4. Ebean manuel dekryptering