sql >> Databasteknik >  >> RDS >> Mysql

Optimera fråga (indexering, EXPLAIN) Mysql

Jag glömmer hela tiden termen eftersom den kommer upp väldigt sällan för mig, men hur som helst kan dina index inte optimeras genom att använda MONTH() och YEAR() eftersom de är funktioner på underliggande data. Genom att tillämpa ett datumintervall kan de. Så du kan behålla din månad/år som om något skapades i januari 2021 och uppdaterades i mars 2021, men dessutom lägga till en "och c.date_created>=aktuell_datum OCH aktuell_datum <=c.datum_uppdaterad" , du KAN använda indexet om det har skapat datum i sig (mindre viktigt i det här fallet för det uppdaterade datumet. På samma sätt för din andra tabell.

Dessutom, när du har din left-join från "a" till "c"-tabellen, och sedan applicera where, är det nästan som att du försöker tvinga sammanfogningen men förblir left-join på grund av OR.

Jag skulle flytta det "c"-baserade villkoret till vänsterkopplingen och sedan bara testa för posten som finns där som NULL eller inte.

Även om det inte är klart (förtydligades inte när jag frågade), TROR JAG att när en ny "A"-post skapas, så kan systemet faktiskt lägga in skapelsedatumet i både det skapade datumet och det uppdaterade datumet. OM DET ÄR FALLET behöver vi bara fråga/bekymra det senast uppdaterade datumfältet med aktuell månad/år av aktivitet. Det är nu det PRIMÄRA kravet för where-satsen -- OAVSETT det underliggande ELLER-villkoret till "C"-tabellen.

Dessutom, eftersom månad() och år() inte är sargebara (Tack Ollie), jag gör en förfrågan för att få början av innevarande månad och nästa månad så att jag kan bygga ut en

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

När det gäller index skulle jag börja uppdatera till

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

Sista fråga att prova 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')
                            )
                        )
                    )
            )

AVSLUTNINGSKOMMENTARER FÖR FÖRFRÅGAN

Jag modifierade frågan och även det primära indexet på den första tabellen för att INKLUDERA (första positionen) det datum som posten skapades. Jag har också lagt till en extra variabel @howFarBack för att vara den maximala återgångstiden att överväga för ett lån. Jag ställde som standard till 6 månader sedan. Skulle du någonsin behöva överväga ett visst konto som är äldre än 6 månader för ett lån? Eller är "a"-kontot något som kan gå tillbaka 10 år och vill inkludera? Mitt intryck är att det är en ny LÅNEANSÖKAN lägga till datum. Om så är fallet skulle det ändå förhindra att man går igenom så många månaders data historiskt om man tillåter att gå 6 månader tillbaka innan den godkänns, slutförs, avbryts.

I WHERE-satsen lade jag till explicit tillägg för CREATED_DATE>=@howFarBack. Det skulle aldrig vara möjligt för en underordnad post att skapas, än mindre uppdaterad någon gång före det ursprungliga tilläggsdatumet. Detta tvingar endast aktuell månadsaktivitet ELLER FRAMÅT för att kvalificera sig.

Ex:Skapa ett lån den 28 april. Så när frågan körs, är början av månaden 1 april men MINDRE än 1 maj (detta tillåter inkludering av 30 april kl. 23:59:59)

Nu går vi in ​​i maj och en förändring av lånet görs den 4 maj. Vi är inne i en ny månad och @howFarBack tillåter fortfarande att äldre applikationer så långt som till december 2020 MÖJLIGT är kvalificerade jämfört med hela tabellen med ansökningar som kan gå tillbaka så långt som till 2005 för allt vi vet. Du stannar alltid med den senaste informationen och du kan enkelt ändra @howFarBack som den maximala återgångstiden. Detta bör hjälpa dina prestationsbehov.




  1. ORA-08177:kan inte serialisera åtkomst för denna transaktion

  2. Hur man minimerar RPO för dina PostgreSQL-databaser med hjälp av punktåterställning

  3. Hur får man en korrekt dump med mysqldump och single-transaction när DDL används samtidigt?

  4. Oracle Database BLOB till InputStream i Java?