Mysql
 sql >> Base de données >  >> RDS >> Mysql

Optimiser la requête (Indexation, EXPLAIN) Mysql

J'oublie sans cesse le terme car il me revient très rarement, mais de toute façon, vos index ne peuvent pas être optimisés en utilisant MONTH() et YEAR() car ce sont des fonctions sur les données sous-jacentes. En appliquant une plage de dates, ils le peuvent. Ainsi, vous pouvez conserver votre mois/année comme si quelque chose avait été créé en janvier 2021 et mis à jour en mars 2021, mais en plus, en ajoutant un "and c.date_created >= current_date AND current_date <= c.date_updated" , vous POUVEZ utiliser l'index s'il contient la date de création (moins important dans ce cas pour la date de mise à jour. De même pour votre autre table.

De plus, lorsque vous avez votre jointure gauche de la table "a" à la table "c", puis appliquez où, c'est presque comme si vous essayiez de forcer la jointure mais que vous restiez jointe à gauche en raison de l'OR.

Je déplacerais la condition basée sur "c" vers la jointure gauche, puis je testerais simplement l'enregistrement qui s'y trouve comme NULL ou non.

Bien que cela ne soit pas clair (n'a pas été clarifié lorsque j'ai demandé), JE PENSE que lorsqu'un nouvel enregistrement "A" est créé, le système peut en fait mettre la date de création à la fois dans la date de création et la date de mise à jour. SI C'EST LE CAS, nous n'avons qu'à interroger/concerner le dernier champ de date mis à jour avec le mois/l'année d'activité en cours. C'est maintenant l'exigence PRIMAIRE pour la clause WHERE - QUELLE QUE SOIT la condition OU sous-jacente de la table "C".

De plus, puisque le mois() et l'année() ne sont pas sargeable (Merci Ollie), je fais une pré-requête pour obtenir le début du mois en cours et le mois prochain afin que je puisse créer un

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

En ce qui concerne les index, je commencerais la mise à jour vers

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

Dernière requête à essayer.

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

COMMENTAIRES FINAUX POUR LA REQUÊTE

J'ai modifié la requête ainsi que l'index primaire sur la première table pour INCLURE (première position) la date de création de l'enregistrement. J'ai également ajouté une variable supplémentaire @howFarBack pour être le temps de retour maximum à considérer pour un prêt. J'ai par défaut à 6 mois en arrière. Auriez-vous jamais besoin d'envisager un compte donné de plus de 6 mois pour un prêt ? Ou le compte « a » enregistre-t-il quelque chose qui pourrait remonter à 10 ans et que vous souhaitez inclure ? J'ai l'impression qu'il s'agit d'une nouvelle date d'ajout de DEMANDE DE PRÊT. Si tel est le cas, permettre de remonter 6 mois en arrière avant qu'il ne soit approuvé, finalisé, annulé empêcherait toujours de parcourir autant de mois de données historiquement.

Dans la clause WHERE, j'ai ajouté un ajout explicite pour CREATED_DATE>=@howFarBack. Il ne serait jamais possible de créer un enregistrement enfant, et encore moins de le mettre à jour à tout moment avant la date d'ajout d'origine. Cela forcera uniquement l'activité du mois en cours OR FORWARD à se qualifier.

Ex :Créer un prêt le 28 avril. Donc, en exécutant la requête, le début du mois est le 1er avril mais MOINS que le 1er mai (cela permet l'inclusion du 30 avril à 23h59:59)

Maintenant, nous entrons en mai et un changement sur le prêt est effectué le 4 mai. Nous sommes dans un nouveau mois et le @howFarBack permet toujours aux applications plus anciennes jusqu'en décembre 2020 de se qualifier POSSIBLEMENT par rapport à l'ensemble du tableau des applications qui pourraient remonter jusqu'en 2005 pour autant que nous sachions. Vous restez toujours avec les données les plus récentes et vous pouvez modifier le @howFarBack assez facilement comme temps de retour maximum. Cela devrait répondre à vos besoins en termes de performances.