sql >> Base de Datos >  >> RDS >> Mysql

Optimizar consulta (Indización, EXPLICAR) Mysql

Sigo olvidando el término ya que me aparece muy raramente, pero de todos modos, sus índices no se pueden optimizar usando MONTH() y YEAR() ya que son funciones en los datos subyacentes. Al aplicar un RANGO de fechas, pueden hacerlo. Por lo tanto, puede mantener su mes/año como si algo se creara en enero de 2021 y se actualizara en marzo de 2021, pero además, agregue un "and c.date_created >= current_date AND current_date <= c.date_updated" , PUEDE utilizar el índice si tiene la fecha de creación (menos importante en este caso para la fecha de actualización. De manera similar para su otra tabla.

Además, cuando tiene su combinación izquierda de la tabla "a" a la tabla "c", luego aplica where, es casi como si estuviera tratando de forzar la combinación, pero sigue siendo combinación izquierda debido al OR.

Movería la condición basada en "c" a la unión izquierda, luego probaría el registro que se encuentra allí como NULL o no.

Aunque no está claro (no se aclaró cuando pregunté), PIENSO que cuando se crea un nuevo registro "A", el sistema puede poner la fecha de creación tanto en la fecha de creación como en la fecha de actualización. SI ESTE ES EL CASO, entonces solo necesitamos consultar/preocupar el campo de fecha de última actualización con el mes/año actual de actividad. Ese es ahora el requisito PRIMARIO para la cláusula where, INDEPENDIENTEMENTE de la condición OR subyacente de la tabla "C".

Además, dado que el mes() y el año() no son sargeable (Gracias Ollie), estoy haciendo una consulta previa para obtener el comienzo del mes actual y el mes próximo para poder construir un

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

En cuanto a los índices, comenzaría a actualizar a

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

Consulta final para probar.

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

COMENTARIOS DE CIERRE PARA LA CONSULTA

Modifiqué la consulta y también el índice principal en la primera tabla para INCLUIR (primera posición) la fecha de creación del registro. También agregué una variable adicional @howFarBack para que sea el tiempo de retroceso máximo a considerar para un préstamo. Yo por defecto a 6 meses atrás. ¿Alguna vez necesitaría considerar una cuenta determinada con más de 6 meses de antigüedad para un préstamo? ¿O son los registros de la cuenta "a" algo que podría retroceder 10 años y desea incluir? Mi impresión es que es una nueva fecha de adición de SOLICITUD DE PRÉSTAMO. Si es así, permitir retroceder 6 meses antes de que se apruebe, finalice o cancele aún evitaría revisar tantos meses de datos históricos.

En la cláusula WHERE, agregué un complemento explícito para CREATED_DATE>=@howFarBack. Nunca sería posible crear un registro secundario, y mucho menos actualizarlo en cualquier momento antes de la fecha de adición original. Esto forzará solo la actividad del mes actual O ADELANTE para calificar.

Ej:Crear un préstamo el 28 de abril. Entonces, al ejecutar la consulta, el comienzo del mes es el 1 de abril pero MENOS que el 1 de mayo (esto permite la inclusión del 30 de abril a las 11:59:59 p. m.)

Ahora, llegamos a mayo y se realiza un cambio en el préstamo el 4 de mayo. Estamos en un nuevo mes y @howFarBack aún permite que las solicitudes anteriores hasta diciembre de 2020 POSIBLEMENTE califiquen frente a la tabla completa de solicitudes que podrían remontarse hasta 2005, por lo que sabemos. Siempre se mantiene con los datos más actuales y puede cambiar @howFarBack con la suficiente facilidad como el tiempo máximo de retroceso. Esto debería ayudarte con tus necesidades de rendimiento.