3

次のテーブルがあります(無関係なものは削除されています):

create table Payment (
    id int not null auto_increment,
    status int not null,
    primary key(id)
);
create table Booking (
    id int not null auto_increment,
    paymentId int not null,
    nrOfPassengers int not null,
    primary key(id),
    key paymentFK (paymentId),
    constraint paymentFK foreign key (paymentId) references Payment(id)
);

Booking~456k 行をPayment含み、~331k 行を含みます。次のクエリは 0.06 秒かかり、97 行を返します。

select * from Booking b
join Payment p on b.paymentId = p.id
where p.status = 3

句を追加するorder byと、代わりにクエリに 4.4 秒かかり、ほぼ 100 倍遅くなります。

select * from Booking b
join Payment p on b.paymentId = p.id
where p.status = 3
order by b.nrOfPassengers

最初のクエリの EXPLAIN:

id, select_type, table, type, possible_keys, key,       key_len, ref,  rows,   Extra
1,  SIMPLE,      p,     ALL,  PRIMARY,       NULL,      NULL,    NULL, 331299, Using where
1,  SIMPLE,      b,     ref,  paymentFK,     paymentFK, 9,       p.id, 1,      Using where

そして2番目:

id, select_type, table, type, possible_keys, key,       key_len, ref,  rows,   Extra
1,  SIMPLE,      p,     ALL,  PRIMARY,       NULL,      NULL,    NULL, 331299, Using where; Using temporary; Using filesort
1,  SIMPLE,      b,     ref,  paymentFK,     paymentFK, 9,       p.id, 1,      Using where

MySQL 5.1.34 を使用しています。

whereクエリで使用される句は、 からの大部分の行を除外しますPayment。(非常に選択的な)where句でフィルタリングする前に、MySQL が結果セットをソートするという印象を受けます。私はこれで正しいですか?もしそうなら、なぜそれはこれをするのですか?両方のテーブルを分析してみましたが、クエリ プランに変更はありません。

4

2 に答える 2

1

問題は、削除した無関係なものの中に、MySQLを一時テーブルからの中間結果を格納するためにディスク上に移動させるTEXTor列があることです。BLOB

いずれにせよ、実行プランからわかること:テーブルの各行について、ディスクからフェッチし、条件を確認します。これが、一時テーブルの結果にPayment一致する各行に当てはまるかどうかを確認します。Bookingテーブル全体をすべてのデータで並べ替えてnrOfPassengers出力します。Textまたはフィールドがある場合、BlobMySQLはテーブルのサイズを予測できないため、中間テーブルはディスクに保存およびソートされます。

(いつものように)できることは、ディスク操作を最小限に抑えることです。@ajrealが提案したように、status列にインデックスを追加します。選択性が高い場合は、他のインデックスは必要ありませんが、拡張するpaymentFK(paymentId, nrOfPassengers)さらに優れたものになります。次に、クエリを次のように書き直します。

SELECT p.*, b.*
FROM (
  select p.id as paymentId, b.id as bookingId
  from Booking b
  join Payment p on b.paymentId = p.id
  where p.status = 3
  order by b.nrOfPassengers
) as ids
JOIN Payment p ON ids.paymentId = p.id
JOIN Booking b ON ids.bookingId = b.id;

データはサブクエリ順に出力されます。

于 2013-02-01T12:13:19.267 に答える
1

まず、テーブルに適切なインデックスがあることを確認してください。実行しても予想よりもまだ遅いと仮定すると、結果を順序付けせずにサブクエリにスローしてから、ORDER BY 句を追加し直すことができます。

SELECT * 
FROM (
   select * from Booking b
   join Payment p on b.paymentId = p.id
   where p.status = 3
)
ORDER BY nrOfPassengers

実行計画を表示すると行が追加されるため、これがどれだけ役立つか(または役立つかどうか)はわかりませんが、より高速になる可能性があります。

幸運を。

于 2013-01-30T16:37:19.790 に答える