web-dev-qa-db-ja.com

SELECT *がSELECT fooよりもはるかに速いのはなぜですか?

次のように、値とハッシュのテーブルを考えます。

+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| val        | char(9)  | NO   |     | NULL    |                |
| val_hashed | char(50) | YES  |     | NULL    |                |
+------------+----------+------+-----+---------+----------------+

次のクエリは0.00秒で終了します。

SELECT * FROM hashes ORDER BY 1 DESC LIMIT 1;

ただし、このクエリには3分17秒かかります。

SELECT val FROM hashes ORDER BY 1 DESC LIMIT 1;

クエリの実行中、プロセスリストにステータスSorting resultと表示されます。状況は完全に再現可能です。テーブルに対してINSERT操作を継続的に実行する別のプロセスがあることに注意してください。

より具体的なクエリは、*クエリよりも実行に時間がかかるのはなぜですか?パフォーマンス上の理由から、*クエリは避けるべきだといつも信じていました。

29
dotancohen

ORDER BY 1という句は、異なる列を指します。最初はid、2番目はvalになります。 idはキーなので、インデックスが付けられ、order byは簡単な作業になります。ただし、order by valを実行するには、システムがすべての行を取得し、テーブル全体をvalでソートして、それらの行の1つだけを選択する必要があります。

両方のクエリをorder by idに変更します。実行時間はほぼ同じになると思います。

34
Michael Green

クエリのパフォーマンスの違いは、MGによってよく説明されています。私はこれに対処します:

パフォーマンス上の理由から、*クエリは避けるべきだと常に信じてきました。

select *自体は特にペナルティはありません。誤用すると問題が発生します。単一テーブルのクエリでは、それはうまく機能します。次に、そのテーブルを20列の別のテーブルに結合し、後でそれぞれに多くの列がある5つの他のテーブルに結合を追加します。今それは問題です。理由を説明せずに、バンドエイドで「Xをしない」を教える人もそうです。

6
paul