2010-11-20 14 views
1

私は迷っています。私は約100K行のテーブルを持っています。このテーブルの結果を照会すると、通常約2ms程度の結果が得られます。しかし、ORDER BYのパフォーマンスを使うたびに、約120msの岩のように落ちます。私はMySQL ORDER BY Optimizationのページを読んだが、私はすべてを理解するとは言えない。特にインデックスは私には不透明です。ORDER BYクエリを最適化する

SELECT * 
    FROM `affiliate_new_contracts` 
WHERE phone_brand IN ('Apple','Blackberry','HTC','LG','Motorola','Nokia', 
         'Samsung','Sony Ericsson') 
    AND contract_length IN ('12','24') 
    AND (addon IS NULL OR addon IN('Telfort Sms 300','Surf & Mail')) 
    AND (plan_name = 'Telfort 100' 
     AND 
     credible_shop = 1 
     ) 
    ORDER BY average_price_per_month ASC, phone_price_guestimate DESC, 
      contract_length ASC; 

をしかし、私は基本的な原理を理解している場合、私は幸せになる:

最終的に私は次のクエリを実行したいと思います。前のクエリにORDER BY句を削除
は、それが120msのの代わりに20msの中で実行します。私はaverage_price_per_monthフィールドにインデックスを持っていますが、ORDER BY average_price_per_monthにORDER BY句を簡素化しても性能の向上は得られませんでした。私は理解していない。私はまた、究極のクエリで私を助けることができるはずですいわゆるマルチカラムのインデックスについては暗闇の中にいる。

ご協力いただければ幸いです。この悪い男の子をどのように演じさせるのですか?それとも、クエストユートピアンですか?次のように

CREATE TABLE構文は次のとおりです。

$ show create table affiliate_new_contracts; 
CREATE TABLE `affiliate_new_contracts` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `plan_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `contract_length` int(11) DEFAULT NULL, 
    `phone_brand` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `price` float DEFAULT NULL, 
    `average_price_per_month` float DEFAULT NULL, 
    `phone_price_guestimate` float DEFAULT NULL, 
    `credible_shop` tinyint(1) DEFAULT '0', 
    `addon` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `addon_price` float DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_affiliate_new_contracts_on_plan_name` (`plan_name`), 
    KEY `index_affiliate_new_contracts_on_average_price_per_month` (`average_price_per_month`), 
    KEY `index_affiliate_new_contracts_on_price` (`price`) 
) ENGINE=InnoDB AUTO_INCREMENT=2472311 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

ところでこの表は毎週再作成され、その間に更新されません。

+1

水平スクロールバーを避けるために、クエリを再フォーマットしました。クエリ名の最後の数(プラン名と信頼できる店舗)は残りのクエリと一貫して書かれていません(他の用語はテーブル名を使用しません)。私はコメントせずに修正するかどうか議論し、そうしないことにしました。これらの用語を一貫性のあるものにすることに決めた場合は、このコメントを削除します。 –

+0

優秀なコメント。クエリの一部が生成されました(私がクエリに適していないという証拠が増えています)。余分なテーブル名を削除しました。 – harm

答えて

3

あなたはORDER BY句に行うことができますどのくらいの最適化には限界があります。主に役立つ主なものは、正しい順序で正しい列セットに索引を付けることです。だから、あなたたとえば、上の(単一、複合)インデックス:

average_price_per_month ASC, phone_price_guestimate DESC, contract_length ASC 

が役立つかもしれないが、オプティマイザはまだクエリのフィルタ条件に対処するためにいくつかの他のインデックスを使用することをお勧めしていることを決めるかもしれませんし、選択したデータをソートします。索引が正確なソート順でデータを提供し、索引を使用して問合せ全体を高速化しない限り、オプティマイザは索引を使用しないことに注意してください。ソートされる列のうちの1つのみの索引は、オプティマイザにとっては限定的な利点です。通常、このような索引は使用されません。考慮すべき

つの質問:

  • どのくらいの速さクエリにORDER BY句なしで実行しません。あなたのソートのコストが非常に直接的な測定を提供します

。オーダーなしで20ミリ秒、オーダーで120ミリ秒と言われているので、ORDER BYは適度に高価です。次の質問は、「あなたのアプリケーションでそのソートを実行できますか?」です。あなたはそれを行うことができるかもしれませんが、DBMSのソートパッケージは、通常、かなりうまく最適化されており、あなたはそれを打ち負かすために努力する必要があります。

0

私はそれが主キーとクエリの選択ロジック(句)、それを使用していないではありませんので、あなたのインデックスがあなたに何か良いをやっていないと思われます。索引を使用して行を選択していないため、選択後に結果をソートする必要があります。あなたのプライマリキーではないということは、結果が既に月額平均価格で注文されていないことを意味し、すでに発注されているので、ソート時間を短縮または排除します。

一つの解決策は、最も選択コラム(プラン名)と順序カラム(average_price_per_month)を備えて複合インデックスを使用することです。選択後も並べ替えが必要になりますが、結果は主注文列で並べ替えられて、費やされる時間が短縮されます。

CREATE TABLE `affiliate_new_contracts` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `plan_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `contract_length` int(11) DEFAULT NULL, 
    `phone_brand` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `price` float DEFAULT NULL, 
    `average_price_per_month` float DEFAULT NULL, 
    `phone_price_guestimate` float DEFAULT NULL, 
    `credible_shop` tinyint(1) DEFAULT '0', 
    `addon` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `addon_price` float DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_affiliate_new_contracts_on_plan_name` (`plan_name`,`average_price_per_month`), 
    KEY `index_affiliate_new_contracts_on_price` (`price`) 
) ENGINE=InnoDB AUTO_INCREMENT=2472311 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

はまた、(私の直感が正しくない場合)クエリが実行されているかを理解するためにEXPLAINを使用し、それに応じてインデックスを調整したい場合があります。