複合インデックスの列の順序を決定する

列を複合インデックスに入れる順序を決定するために使用する簡単な経験的方法を共有したいと思います。 この方法はMySQLに適しているだけでなく、Bツリーインデックスを使用するDBMSにも適用できます。



空の結果を返すクエリから始めましょう。ただし、テーブル全体をスキャンします。 EXPLAINは、使用可能なインデックスがないことを示します(つまり、possible_keys = NULL)



SELECT * FROM tbl

WHERE

status= 'waiting' AND

source= 'twitter' AND

no_send_before <= '2009-05-28 03:17:50' AND

tries <= 20

ORDER BY date ASC LIMIT 1;







このリクエストの意味を理解しようとしないでください、それは例としてのみ与えられています。 最も単純なケースでは、一致する行の可能な数が最小限になるように、最も選択的な列を最初にインデックスに入れて、必要な行をできるだけ早く見つけるようにします。 すべての列に値の分布があると仮定すると、各条件の一致数を簡単に計算できます。



SELECT

sum (status= 'waiting' ),

sum (source= 'twitter' ),

sum (no_send_before <= '2009-05-28 03:17:50' ),

sum (tries <= 20),

count (*)

FROM tbl\G



*************************** 1. row ***************************

sum (status = 'waiting' ): 550

sum (source= 'twitter' ): 37271

sum (no_send_before <= '2009-05-28 03:17:50' ): 36975

sum (tries <= 20): 36569

count (*): 37271









簡単です-MySQLの場合、COUNT(number_time_when_tru)と同等のSUM()関数で各条件をラップしました。 ご覧のとおり、最も選択的な条件は「status = waiting」です。 この列を最初にインデックスに入れてから、条件をSELECTからWHEREに転送し、クエリを再度実行して、残りのセットの一致をカウントします。



SELECT

sum (source= 'twitter' ),

sum (no_send_before <= '2009-05-28 03:17:50' ),

sum (tries <= 20),

count (*)

FROM tbl

WHERE

status= 'waiting' \G

*************************** 1. row ***************************

sum (source= 'twitter' ): 549

sum (no_send_before <= '2009-05-28 03:17:50' ): 255

sum (tries <= 20): 294

count (*): 549









これで、許容可能な行数になりました。 「ソース」には選択性がまったくないことがわかります。つまり、 これを使用すると、何もフィルタリングできなくなり、インデックスに追加しても何のメリットもありません。 「no_send_before」または「tries」を使用して、残りのセットをフィルタリングできます。 whereのいずれかでクエリを実行すると、別の条件の一致の数がゼロに減ります。



SELECT

sum (source= 'twitter' ),

sum (no_send_before <= '2009-05-28 03:17:50' ),

sum (tries <= 20),

count (*)

FROM tbl

WHERE

status= 'waiting' AND

no_send_before <= '2009-05-28 03:17:50' \G

*************************** 1. row ***************************

sum (source= 'twitter' ): 255

sum (no_send_before <= '2009-05-28 03:17:50' ): 255

sum (tries <= 20): 0

count (*): 255



***************************************************************



SELECT

sum (source= 'twitter' ),

sum (no_send_before <= '2009-05-28 03:17:50' ),

sum (tries <= 20),

count (*)

FROM tbl

WHERE

status= 'waiting' AND

tries <= 20\G

*************************** 1. row ***************************

sum (source= 'twitter' ): 294

sum (no_send_before <= '2009-05-28 03:17:50' ): 0

sum (tries <= 20): 294

count (*): 294

* This source code was highlighted with Source Code Highlighter .








これは、(status、trys)または(status、no_send_before)のいずれかでインデックスを作成できることを意味し、ゼロ行を非常に効率的に見つけることができます。 どちらが良いかは、このテーブルが実際に使用されているもの(およびこのテーブルに対する他のクエリの可用性と構造-およそTrans。)によって決まります



All Articles