TOPICS

EC-CUBE MYSQLでの速度改善01

今週から、全4回に分けてEC-CUBEのMYSQLにおける速度改善について書いていきます。

EC-CUBEでの速度改善は主にMYSQLのクエリ部分の改善で対応できます。

例えば 商品データを取得する場合

SELECT
*
FROM
    dtb_products LEFT JOIN
    dtb_products_class ON (dtb_products.product_id = dtb_products_class.product_id)

WHERE
    dtb_products.del_flg = 0 AND
    dtb_products.status = 1 AND 
    dtb_products_class.del_flg = 0
ORDER BY product_id DESC
LIMIT 10 

というクエリがあった場合、このままでいいように見えますが 実際には

SELECT
    *
FROM
    (
        SELECT
            *
        FROM
            dtb_products
        WHERE
            dtb_products.del_flg = 0 AND
            dtb_products.status = 1    
        ORDER BY product_id DESC
        LIMIT 10 
    ) p INNER JOIN
    dtb_products_class ON (p.product_id = dtb_products_class.product_id)
WHERE
    dtb_products_class.del_flg = 0
ORDER BY p.product_id

のように書いた方が早くなります。

商品データが多ければ多いほど劇的に。

EC-CUBEのデフォルトで効果がある場所は

    public function alldtlSQL($where_products_class = '')
    {
        if (!SC_Utils_Ex::isBlank($where_products_class)) {
            $where_products_class = 'AND (' . $where_products_class . ')';
        }
        /*
         * point_rate, deliv_fee は商品規格(dtb_products_class)ごとに保持しているが,
         * 商品(dtb_products)ごとの設定なので MAX のみを取得する.
         */
        $sql = <<< __EOS__
            (
                SELECT
                     dtb_products.*
                    ,T4.product_code_min
                    ,T4.product_code_max
                    ,T4.price01_min
                    ,T4.price01_max
                    ,T4.price02_min
                    ,T4.price02_max
                    ,T4.stock_min
                    ,T4.stock_max
                    ,T4.stock_unlimited_min
                    ,T4.stock_unlimited_max
                    ,T4.point_rate
                    ,T4.deliv_fee
                    ,dtb_maker.name AS maker_name
                FROM dtb_products
                    INNER JOIN (
                        SELECT product_id
                            ,MIN(product_code) AS product_code_min
                            ,MAX(product_code) AS product_code_max
                            ,MIN(price01) AS price01_min
                            ,MAX(price01) AS price01_max
                            ,MIN(price02) AS price02_min
                            ,MAX(price02) AS price02_max
                            ,MIN(stock) AS stock_min
                            ,MAX(stock) AS stock_max
                            ,MIN(stock_unlimited) AS stock_unlimited_min
                            ,MAX(stock_unlimited) AS stock_unlimited_max
                            ,MAX(point_rate) AS point_rate
                            ,MAX(deliv_fee) AS deliv_fee
                        FROM dtb_products_class
                        WHERE del_flg = 0 $where_products_class
                        GROUP BY product_id
                    ) AS T4
                        ON dtb_products.product_id = T4.product_id
                    LEFT JOIN dtb_maker
                        ON dtb_products.maker_id = dtb_maker.maker_id
            ) AS alldtl
__EOS__;

        return $sql;
    }

この部分で、オススメ商品とか一覧で使われている、商品IDの配列を渡して商品のデータを取得する部分で、メソッドに対して配列をこのalldtlSQLのメソッドに対して引き渡し、INNER JOINされている dtb_products_classに対して絞り込むクエリを追加することで効果が現れます。

MYSQLの場合はJOINのコストが結構高くなる場合があり、EC-CUBEにおいては顕著にその影響が出てきます。

細かい所ですが、後々サイトが重たくなるとかを防ぐ為に先に色々負荷対策を行っておいた方が安心です。

速度改善の依頼はこちらから。

CONTACT US