63421


レコードに一意な値が入るカラムが2つあります  
・id  
・url

この時、下記SQL文の取得結果速度に違いはあると考えられますか？

[code]

    SQL1.SELECT * FROM テーブル名　WHERE id = 1;
    
    SQL2.SELECT * FROM テーブル名　WHERE id = 1 AND url ='https://ja.stackoverflow.com/';
    
[/code]

  * どちらも同じ
  * SQL1.の方が速い
  * SQL2.の方が速い
  * 環境(メモリやデータ内容)による

* * *

**追記**  
回答を読んで知りたいと思った内容を改めて整理してみました。

レコード例(下記のような一意の組み合わせがあります)

[code]

    1　スタック・オーバーフロー　'https://ja.stackoverflow.com/'
    2　Google　'https://www.yahoo.co.jp/'
    3　Yahoo! JAPAN　'https://www.google.com/'
    
[/code]

Q1(AUTOINCREMENET属性も、インデックスも、設定していない時)  
・1レコード目を取得したい場合、1だけを指定するSELECTと、1と'<https://ja.stackoverflow.com/>'を指定するSELECTに違いはありますか？

Q2(AUTOINCREMENET属性だけを設定している時)  
・1レコード目を取得したい場合、1だけを指定するSELECTと、1と'<https://ja.stackoverflow.com/>'を指定するSELECTに違いはありますか？

Q3(複合インデックスを設定している時)  
・1レコード目を取得したい場合、1だけを指定するSELECTと、1と'<https://ja.stackoverflow.com/>'を指定するSELECTに違いはありますか？


CC BY-SA 4.0
2020-02-27T22:55:39.310
63416
2020-03-01T03:30:10.477
2020-02-28T22:37:13.783
7886
7886
question
mysql
レコードに一意な値が2つある場合、SELECT文のWHEREで AND 指定した方が良い？


こんにちは。同じ環境であれば、このケースではSQL1.が速くなると思われます。

複合インデックスがはられてない場合は言うまでもありませんので、複合インデックスがはられていることを前提に話を進めます。

idは(おそらくは)固定長の数値一個のインデックスとなるからです。複合インデックスがはられている場合は、インデックスをはられているコラムの内容により検索性能に差が出ます。  
urlは文字列であり、固定長の文字列の場合も配列となるので、数値一個の時より性能は落ちます。またこれが可変長の文字列だった場合さらに状況は悪くなるでしょう。

(SQL Serverの話題になりますが)類似の質問と回答が本家にありましたのでPerformanceDBA氏の回答を一部参考にしています。  
<https://stackoverflow.com/questions/4011600/sql-server-performance-
difference-with-single-or-multi-column-primary-key>

[ **追記への回答** ]  
AUTOINCREMENTだけ指定しているという状況がわかりませんが、これはつまり、PKEYになっているという想定で話を進めます。PKEYの場合は暗黙的にインデックスが貼られてUNIQUEになっています。(実運用上は文字列フィールドにもUNIQUEをつけてくださいね)

Q1.
この場合ともにフルスキャンがかかりますが、比較にかかるコストが数値の方が低いためIDを指定して検索したほうが早くなります。ただし主キーがないテーブルは作らないでください。  
Q2.
PKEYがIDに設定されているものとして話をすすめます。この場合もIDを検索した方がはやくなります。二つ目の条件では文字列フィールドに対してフルスキャンがかかるためかなり遅くなります。  
Q3.
これは先に挙げた回答のとおりです。この場合IDへのインデックスと、複合インデックスの速度の比較になりますが、インデックスの性能差から、やはりID指定の検索が早くなります。

MySQLのお話だと思いますのでインデックスについては下記を参照にしてください  
<https://dev.mysql.com/doc/refman/5.6/ja/optimization-indexes.html>

インデックスとフルスキャンの違いについて補足すると  
フルスキャンの概念としては文字通り、辞書を1ページ目から調べて対象が見つかるまで調べ続ける状態となります。(UNIQUEがないと頭から終わりまで調べます)。インデックスがある場合は用語集を見てそのページに直接移動して調べる感じです。より深い理解のためには上述の章を確認してBツリーや、ハッシュなどについて学習を行うことをお勧めします。


CC BY-SA 4.0
2020-02-28T01:08:31.197
63421
2020-02-29T01:25:08.660
2020-02-29T01:25:08.660
37777
37777
63416
answer


**追記された条件に対する回答**

  2. > SQL2.SELECT * FROM テーブル名 WHERE id = 1 AND url ='<https://ja.stackoverflow.com/>';

の方が速くなり得るのは以下の場合だけだと思います。

  * 主キーが`url`、`id`には索引が張られていない
  * `url`に索引が張られている、`id`は主キーではなく、索引も張られていない

よって。回答は以下のとおりです。

> Q1(AUTOINCREMENET属性も、インデックスも、設定していない時)

A1 `1だけを指定するSELECT`

> Q2(AUTOINCREMENET属性だけを設定している時)

A2 どちらともいえない。

※ Q2を「主キーまたは索引が張られている時」に読み替えています。

> Q3(複合インデックスを設定している時)

A3 `1だけを指定するSELECT`

**質問に対する疑問**

まだ、質問に対する疑問が解消していません。

以下の比較であればまだわかるのですが、どちらの列を指定しても同じ行になるものを、両方の列の条件をANDで指定する意図がわからないです。

  * `id`による`SELECT`と`url`による`SELECT`の差異
  * ANDでなくOR  
`SELECT * FROM テーブル名 WHERE id = 1 OR url ='<https://ja.stackoverflow.com/>';

* * *

* * *

以下は条件が追記される前の回答です。

**今回の質問の回答**

細部の条件が提示されていないため、回答は以下が妥当だと考えます。

> 環境(メモリやデータ内容)による

主キー、ユニークキー、索引の、有無や内容によって取得に要する時間は変わると思います。

* * *

**質問に対する疑問**

比較したい意図がよく分かりません。

  1. > SQL1.SELECT * FROM テーブル名 WHERE id = 1;

  2. > SQL2.SELECT * FROM テーブル名 WHERE id = 1 AND url '<https://ja.stackoverflow.com/>';

1.と2.は機能が異なります。idが一意で、urlが一意でも同じ行を示すとは限りません。  
異なる機能の速度性能を比較する意味が見いだせません。

どちらの列でも同じ行を示すと仮定したとき、単純に考えると1.の方が速そうですが、「状況によって2.の方が早くなるか」を知りたいのでしょうか。

* * *

**速度性能の比較**

可能であれば、RDBMSの仕様から見当をつけた後、実際にモデルを作って、実測したり、EXPLAIN等のツールを使用して、実行計画を調べてみるのがよいと思います。

当初の予想(期待)が裏切られることはよくあることですので、単純なモデルを作ることをお勧めしたいと思います。

**実行計画**

簡単なモデルを作成し、実行計画を取得してみました。

実行結果

[code]

    mysql> EXPLAIN SELECT count(*) FROM tsttbl01 where id = 1;
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | tsttbl01 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1000 |    10.00 | Using where |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    mysql> EXPLAIN SELECT count(*) FROM tsttbl01 where id = 1 and url ='AAA_1ZZZ';
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | tsttbl01 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1000 |     1.00 | Using where |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    mysql> EXPLAIN SELECT count(*) FROM tsttbl02 where id = 1;
    +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
    | id | select_type | table    | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
    +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
    |  1 | SIMPLE      | tsttbl02 | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | Using index |
    +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    mysql> EXPLAIN SELECT count(*) FROM tsttbl02 where id = 1 and url ='AAA_1ZZZ';
    +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
    | id | select_type | table    | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
    +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | tsttbl02 | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
    +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
    1 row in set, 1 warning (0.00 sec)
    mysql> EXPLAIN SELECT count(*) FROM tsttbl03 where id = 1;
    +----+-------------+----------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
    | id | select_type | table    | partitions | type | possible_keys | key      | key_len | ref   | rows | filtered | Extra       |
    +----+-------------+----------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
    |  1 | SIMPLE      | tsttbl03 | NULL       | ref  | tstidx03      | tstidx03 | 4       | const |    1 |   100.00 | Using index |
    +----+-------------+----------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    mysql> EXPLAIN SELECT count(*) FROM tsttbl03 where id = 1 and url ='AAA_1ZZZ';
    +----+-------------+----------+------------+------+---------------+----------+---------+-------------+------+----------+-------------+
    | id | select_type | table    | partitions | type | possible_keys | key      | key_len | ref         | rows | filtered | Extra       |
    +----+-------------+----------+------------+------+---------------+----------+---------+-------------+------+----------+-------------+
    |  1 | SIMPLE      | tsttbl03 | NULL       | ref  | tstidx03      | tstidx03 | 2054    | const,const |    1 |   100.00 | Using index |
    +----+-------------+----------+------------+------+---------------+----------+---------+-------------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    
[/code]

**実行計画による回答**

A1 filteredが大きいため1.が速いです。

  1. > SQL1.SELECT * FROM テーブル名 WHERE id = 1; 

A2 indexを使用するため1.が速いです。AUTO_INCREMENT属性を指定するにはキーが必要のようなので`id`を`PRIMARY
KEY`としました。早いのは`PRIMARY KEY`だからだと思います。

  1. > SQL1.SELECT * FROM テーブル名 WHERE id = 1; 

A3 実行計画からは読み取れませんでしたが、読み取るキーのサイズが小さいため、おそらく1.が速いです。

  1. > SQL1.SELECT * FROM テーブル名 WHERE id = 1; 

一番早いのはA2の1.でした。

実行計画の解釈は[MySQL
EXPLAINのそれぞれの項目についての覚書](https://qiita.com/kzbandai/items/ea02727f4bb539fcedb5)を参考にしました。


CC BY-SA 4.0
2020-02-28T02:16:33.417
63423
2020-03-01T03:30:10.477
2020-03-01T03:30:10.477
35558
35558
63416
answer