2016-09-02 11 views
5

私は10〜20秒かかるクエリがありますが、最適化できると確信しています。私はいくつかの助けと説明をして、同様のクエリに適用できるように説明したいと思います。あなたがそこに見るように、私が試したし、あまり成功に関与列を持ついくつかのインデックスを作成している enter image description here2つの結合とグループ句でmysqlクエリを最適化する

ここ
SELECT 
     `store_formats`.`Store Nbr`, 
     `store_formats`.`Store Name`, 
     `store_formats`.`Format Name`, 
     `eds_sales`.`Date`, 
     sum(`eds_sales`.`EPOS Sales`) AS Sales, 
     sum(`eds_sales`.`EPOS Quantity`) AS Quantity 
     FROM 
     `eds_sales` 
     INNER JOIN `item_codes` ON `eds_sales`.`Prime Item Nbr` = `item_codes`.`Customer Item` 
     INNER JOIN `store_formats` ON `eds_sales`.`Store Nbr` = `store_formats`.`Store Nbr` 
     WHERE 
     `eds_sales`.`Store Nbr` IN ($storenbr) AND 
     `eds_sales`.`Date` BETWEEN '$startdate' AND '$enddate' AND 
     `eds_sales`.`Client` = '$customer' AND 
     `eds_sales`.`Retailer` IN ($retailer) AND 
     `store_formats`.`Format Name` IN ($storeformat) AND 
     `item_codes`.`Item Number` IN ($products) 
     GROUP BY 
     `store_formats`.`Store Name`, 
     `store_formats`.`Store Nbr`, 
     `store_formats`.`Format Name`, 
     `eds_sales`.`Date` 

がExplain出力です: はここに私のクエリです。主な遅延は私が考える一時的なテーブルへのコピーから発生します。

これらは関係する表のとおりです。

store_formats:

CREATE TABLE `store_formats` (
`id` int(12) NOT NULL, 
`Store Nbr` smallint(5) UNSIGNED DEFAULT NULL, 
`Store Name` varchar(27) DEFAULT NULL, 
`City` varchar(19) DEFAULT NULL, 
`Post Code` varchar(9) DEFAULT NULL, 
`Region #` int(2) DEFAULT NULL, 
`Region Name` varchar(10) DEFAULT NULL, 
`Distr #` int(3) DEFAULT NULL, 
`Dist Name` varchar(26) DEFAULT NULL, 
`Square Footage` varchar(7) DEFAULT NULL, 
`Format` int(1) DEFAULT NULL, 
`Format Name` varchar(23) DEFAULT NULL, 
`Store Type` varchar(20) DEFAULT NULL, 
`TV Region` varchar(12) DEFAULT NULL, 
`Pharmacy` varchar(3) DEFAULT NULL, 
`Optician` varchar(3) DEFAULT NULL, 
`Home Shopping` varchar(3) DEFAULT NULL, 
`Retailer` varchar(15) DEFAULT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
ALTER TABLE `store_formats` 
ADD PRIMARY KEY (`id`), 
ADD UNIQUE KEY `uniqness` (`Store Nbr`,`Store Name`,`Format`), 
ADD KEY `Store Nbr_2` (`Store Nbr`,`Format Name`,`Store Name`); 

eds_sales:

CREATE TABLE `eds_sales` (
`id` int(12) UNSIGNED NOT NULL, 
`Prime Item Nbr` mediumint(7) NOT NULL, 
`Prime Item Desc` varchar(255) NOT NULL, 
`Prime Size Desc` varchar(255) NOT NULL, 
`Variety` varchar(255) NOT NULL, 
`WHPK Qty` int(5) NOT NULL, 
`SUPPK Qty` int(5) NOT NULL, 
`Depot Nbr` int(5) NOT NULL, 
`Depot Name` varchar(50) NOT NULL, 
`Store Nbr` smallint(5) UNSIGNED NOT NULL, 
`Store Name` varchar(255) NOT NULL, 
`EPOS Quantity` smallint(3) NOT NULL, 
`EPOS Sales` decimal(13,2) NOT NULL, 
`Date` date NOT NULL, 
`Client` varchar(10) NOT NULL, 
`Retailer` varchar(50) NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 
ALTER TABLE `eds_sales` 
ADD UNIQUE KEY `uniqness` (`Prime Item Nbr`,`Prime Item Desc`,`Prime Size Desc`,`Variety`,`WHPK Qty`,`SUPPK Qty`,`Depot Nbr`,`Depot Name`,`Store Nbr`,`Store Name`,`Date`,`Client`) USING BTREE, 
ADD KEY `Store Nbr` (`Store Nbr`), 
ADD KEY `Prime Item Nbr_2` (`Prime Item Nbr`,`Date`), 
ADD KEY `id` (`id`) USING BTREE, 
ADD KEY `Store Nbr_2` (`Prime Item Nbr`,`Store Nbr`,`Date`,`Client`,`Retailer`) USING BTREE, 
ADD KEY `Client` (`Client`,`Store Nbr`,`Date`), 
ADD KEY `Date` (`Date`,`Client`,`Retailer`); 

item_codes:

CREATE TABLE `item_codes` (
`id` int(12) NOT NULL, 
`Item Number` varchar(30) CHARACTER SET latin1 NOT NULL, 
`Customer Item` mediumint(7) NOT NULL, 
`Description` varchar(255) CHARACTER SET latin1 NOT NULL, 
`Status` varchar(15) CHARACTER SET latin1 NOT NULL, 
`Customer` varchar(30) CHARACTER SET latin1 NOT NULL, 
`Sort Name` varchar(255) CHARACTER SET latin1 NOT NULL, 
`EquidataCustomer` varchar(30) CHARACTER SET latin1 NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
ALTER TABLE `item_codes` 
ADD PRIMARY KEY (`id`), 
ADD UNIQUE KEY `uniq` (`Item Number`,`Customer Item`,`Customer`,`EquidataCustomer`), 
ADD KEY `Item Number_2` (`Item Number`,`Sort Name`,`EquidataCustomer`), 
ADD KEY `Customer Item` (`Customer Item`,`Item Number`,`Sort Name`,`EquidataCustomer`), 
ADD KEY `Customer Item_2` (`Customer Item`,`Item Number`,`EquidataCustomer`); 

だから私の質問: ご覧のとおり、私は3つのテーブルに参加していますが、私は店舗形式で日付別に売上を探しています。私は別の種類の結合を試していました。たとえば、store_formatsを他のものに結びつけて、同じ結果をもたらすitem_codesとstore_formatsへの販売に参加する代わりに。私はまた、アプリケーション内の選択ボックスによって供給されるINを使用して、いくつかの変数の配列を渡しています。

  1. はテーブルごとに最適な索引が
  2. は、なぜ私は一時テーブルを得るのですか提案するこれらのテーブルを結合するための最良の方法?それはグループによるものなのでしょうか?回避策はありますか?
  3. 一時テーブルが必要な場合は、とにかくこの作成をスピードアップするにはどうすればよいですか? (私はすでに8枚のディスクを持つRAIDまだ遅くにデータフォルダを持っているもちろん
  4. 任意の提案の選択肢が

UPDATE歓迎されている:。コメントからいくつかの提案

UPDATEと私のテーブルを更新しました:修飾された私のmy.cnfとしてベローズ性能向上(私のRAMは8GB、2つのコアであり、/データ/ tmpが、8ドライブのRAIDにデータがある場合と同じである)

tmpdir   = /dev/shm/:/data/tmp:/tmp 
lc-messages-dir = /usr/share/mysql 
skip-external-locking 
expire_logs_days  = 10 
max_binlog_size = 100M 
innodb_buffer_pool_size = 6G 
innodb_buffer_pool_instances = 6 
query_cache_type=1 
+1

この質問は、[DBA交換](https://dba.stackexchange.com/)でより専門的な注意が喚起される可能性があります。 –

+0

質問を編集してテーブルのすべてのインデックスを表示できますか? –

+0

質問にインデックスを追加 –

答えて

1
サブクエリに

移動を選択します私はMySQLを信じているuldはすでにあなたのためにそれをしています。私はその情報の実行計画をチェックします。

SELECT 
    stores.nbr, stores.name, stores.format, 
    epos.date, 
    sum(epos.sales) AS Sales, 
    sum(epos.qty) AS Quantity 
FROM 
    (SELECT `Date` as `date`, `EPOS Sales` as sales,`EPOS Quantity` as qty, `Prime Item Nbr` as item_number, `Store Nbr` as store_number 
FROM 
    `eds_sales` 
WHERE 
    `eds_sales`.`Store Nbr` IN ($storenbr) AND 
    `eds_sales`.`Date` BETWEEN '$startdate' AND '$enddate' AND 
    `eds_sales`.`Client` = '$customer' AND 
    `eds_sales`.`Retailer` IN ($retailer)) as epos 

    INNER JOIN 

    (SELECT `Customer Item` as custItem 
    FROM `item_codes` 
    WHERE 
    `item_codes`.`Item Number` IN ($products)) as items ON epos.item_number = items.custItem 

    INNER JOIN 

    (SELECT `Store Nbr` as nbr, `Store Name` as name, `Format Name` as format 
    FROM 
    `store_formats` 
    WHERE 
    `store_formats`.`Format Name` IN ($storeformat)) as stores ON epos.store_number = stores.nbr 
GROUP BY 
    stores.name, 
    stores.nbr, 
    stores.format, 
    epos.date 
+0

大きな変更がありますが、まったく同じパフォーマンス –

2

(コメントに入れてあまりにも多く、回答を使用して私をお許しください。)

をあなたはINDEX(a)INDEX(a,b)を持っている場合、前者は冗長であり、削除する必要があります。私はそのようなものの約5例を見る。

store_nbrは、ちょうど1つのstore_nameを持っていますか?その場合、複数のテーブルにstore_nameがあることは冗長です。私はstore_formatsの意図を知らないが、それはstore_nameを収容する1つのテーブルだと思う。 2つのstore_name列とstore_nbr列のデータ型に一貫性のないサイズがあることに注意してください。

、その後、UNIQUE KEY uniqnessStore NbrStore Name)を追加もしそうならばすべてのストアは、一意の番号を持つべきであるように思えるが、おそらくPRIMARY KEY(store_nbr)にオンにする必要があります。 (申し訳ありませんが、私はあなたの中に、列名を空白を置くつもりはありません。)

日付とインデックスを開始することがまれに有用であるので、KEY Date_2DateClient)を取り除きます。代わりに、INDEX(Client, store_nbr, Date)を追加します。クエリーのスピードに直接影響するはずです。 EXPLAIN SELECT...の変更が表示されます。

int(4) - おそらくSMALLINT UNSIGNEDを意味しますか?

UNIQUE(またはPRIMARY)キーでDateを持つことは、 "間違った" 普通です。それは 'クライアント'が同じ日に同じものを2回購入したのですか?

変更を加えたら、もう少し話しましょう。

表示の一貫性のために、SHOW CREATE TABLEを入力してください。

は、この構造物を避けてください:どちらのサブクエリがJOINを効率化するためのインデックスを持っているので

FROM (SELECT ...) 
JOIN (SELECT ...) ON ... 

それは非効率的です。 WHERE句から結合されたテーブル上の

+0

こんにちは、最初の点ありがとうございました。繰り返される列の場合、それらの列はExcelファイルから取得され、mysqlに直接インポートされます。私はそれらを将来的に削除するつもりですが、今のところいくつかのクイッククエリーでそれらを使用しています。 uniqnessについては、私はこのユニークなキーをプライマリに変換すると、それはまだ一意になりますか?日付でインデックスを変更しました。すべてのテーブルで一致する変更されたデータ型。ユニークな日付のために、それは私がクライアントを扱っていないので、そのようにする必要がありますが、データは店舗に来るので、uniqnessはdate-storenbrなどで定義されます –

+0

私はショーを作成しますテーブルとパフォーマンスtommorow。ありがとうございます –

+0

'PRIMARY KEY'は' UNIQUE'キーが 'INDEX'です。 –

0

移動条件の参加ON句へ:

SELECT 
`store_formats`.`Store Nbr`, 
`store_formats`.`Store Name`, 
`store_formats`.`Format Name`, 
`eds_sales`.`Date`, 
sum(`eds_sales`.`EPOS Sales`) AS Sales, 
sum(`eds_sales`.`EPOS Quantity`) AS Quantity 
FROM `eds_sales` 
JOIN `item_codes` 
    ON `eds_sales`.`Prime Item Nbr` = `item_codes`.`Customer Item` 
    AND `item_codes`.`Item Number` IN ($products) 
JOIN `store_formats` 
    ON `eds_sales`.`Store Nbr` = `store_formats`.`Store Nbr` 
    AND `store_formats`.`Format Name` IN ($storeformat) 
WHERE `eds_sales`.`Store Nbr` IN ($storenbr) 
AND `eds_sales`.`Date` BETWEEN '$startdate' AND '$enddate' 
AND `eds_sales`.`Client` = '$customer' 
AND `eds_sales`.`Retailer` IN ($retailer) 
GROUP BY 
`store_formats`.`Store Name`, 
`store_formats`.`Store Nbr`, 
`store_formats`.`Format Name`, 
`eds_sales`.`Date` 

次のインデックスを作成します。

CREATE INDEX IDX001 ON eds_sales (Client,`Store Nbr`,`Retailer`,`Date`); 
CREATE INDEX IDX002 ON store_formats (`Store Nbr`,`Format Name`); 

それが動作する場合、私に知らせてくださいと私理由を説明します。