sql >> データベース >  >> RDS >> Mysql

クエリの最適化(インデックス作成、EXPLAIN)Mysql

    この用語はめったに出てこないので忘れ続けていますが、とにかく、MONTH()とYEAR()は基になるデータの関数であるため、インデックスを最適化することはできません。日付範囲を適用することにより、彼らはそうすることができます。したがって、2021年1月に作成され、2021年3月に更新された場合など、月/年を保持できますが、さらに、"およびc.date_created>=current_date AND current_date <=c.date_updated" 、インデックスに作成日が含まれている場合は、インデックスを利用できます(この場合、更新された日付の場合はそれほど重要ではありません。他のテーブルの場合も同様です。

    さらに、「a」テーブルから「c」テーブルへの左結合がある場合、どこに適用するかは、結合を強制しようとしているのとほぼ同じですが、ORのために左結合のままです。

    「c」ベースの条件を左結合に移動し、そこで見つかったレコードがNULLかどうかをテストします。

    明確ではありませんが(私が尋ねたときに明確にされていませんでした)、新しい「A」レコードが作成されると、システムは実際に作成日を作成日と更新日の両方に入れる可能性があると思います。これがケースの場合、最後に更新された日付フィールドを現在の月/年のアクティビティで照会/懸念するだけで済みます。これが、where句の主要な要件です。「C」テーブルの基になるOR条件に関係なく。

    さらに、month()とyear()はsargeable ではないため (Ollieに感謝)、私は今月と来月の初めを取得するために事前クエリを実行しているので、

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

    インデックスについては、更新を開始します

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

    試す最後のクエリ。

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

    質問に対する最後のコメント

    クエリと最初のテーブルのプライマリインデックスを変更して、レコードの作成日をINCLUDE(最初の位置)にしました。また、ローンを検討するための最大の遡及時間となるように、追加の変数@howFarBackを追加しました。私はデフォルトで6か月前に戻しました。ローンのために6か月以上経過した特定のアカウントを検討する必要がありますか?または、「a」アカウントは、10年前にさかのぼって、含めたいものを記録していますか?私の印象では、これは新しいローン申請の追加日です。その場合、承認、確定、キャンセルされる前に6か月前に戻ることを許可しても、過去に何ヶ月ものデータを処理することはできません。

    WHERE句で、CREATED_DATE>=@howFarBackの明示的な追加を追加しました。元の追加日の前にいつでも更新されることは言うまでもなく、子レコードを作成することは決して不可能です。これにより、当月のアクティビティまたはフォワードのみが対象となります。

    例:4月28日にローンを作成します。したがって、クエリを実行すると、月の初めは4月1日ですが、5月1日よりも少なくなります(これにより、4月30日午後11時59分59秒を含めることができます)

    さて、5月に入り、5月4日にローンの変更が行われます。私たちは新しい月になり、@ howFarBackは、2020年12月までの古いアプリケーションが、2005年まで遡ることができるアプリケーションのテーブル全体に対して、可能性のある資格を得ることができます。あなたは常に最新のデータを維持しており、@howFarBackを最大のバックタイムとして簡単に変更できます。これは、パフォーマンスのニーズに役立つはずです。




    1. MySQL5.7のmax_connections

    2. SQLServer2008のシンボルの前の文字列内のサブ文字列を分離する

    3. 新しいデータソース(mysql)Wildflyを追加する

    4. OracleAppsのアプリケーション実行可能ファイルにコアダンプファイルとデバッグコードを追加する