• 締切済み

UPDATEとSELECTのEXPLAINの違い

UPDATE、SELECTで共に同一のテーブルの同一の主キーを指定したWHERE検索をEXPLAINで行ったところ、 SELECTに関してはtype値がconstになり、 UPDATEに関してはtype値がrangeになりました。 その他の違いといえば、UPDATEの場合はExtra値がUsing whereになるだけで、他は特に差異がありません。 UPDATEで変更する列にインデックスを作成してみても(WHEREで指定する列も含め)、やはりconstにはなりませんでした。 なぜこのような違いが発生するのでしょうか? また、UPDATEステートメントでもtype値をconstにするためにはどのようにすればよいでしょうか? よろしくお願いいたします。

  • MySQL
  • 回答数1
  • ありがとう数6

みんなの回答

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.1

そもそもUPDATEをEXPLAINする必要があるかどうかはおいとくとして (一般的な環境ではエラーになる?) SELECTは単純にレコードをズバリ指定できればconstになりますが、 UPDATEは1レコードだけみればよいのではなくインデックスやユニークなどの 属性も含めて処理するからrangeになるのではないかと勝手に思っています そういうものだと思うしかないような・・・

関連するQ&A

  • EXPLAINのUsing filesortについて

    explain select * from address where area =1 order by id desc limit 10,1\G 上記クエリーをexplainで確認すると Extra: Using where; Using filesort が表示されてしまいます。 1. Using filesortを消したいのですが、idを降順で表示するのに order by id desc 以外の方法はありますか?このような場合、Using filesortは仕方ないのでしょうか? 2. Using whereは効率の悪いクエリーの要素になるのでしょうか?

    • ベストアンサー
    • MySQL
  • EXPLAINのtypeがALLのときの対応方法

    先日問い合わせたSQLの高速化についてEXPLAINについて教えて頂きました。 そのEXPLAINについて調べながら試していくと、同じphpファイル内で動かしている いくつかのSQL文に対してEXPLAINのtypeがALLとなっていたので対応すべき SQLだとは分かったのですが具体的にどのようなSQL文に書き換えればいいか 分からなかったので再度質問しました。 前提としてWORDPRESSでSQLをPHPファイル内で$wpdb->get_results関数を使って 実行しています。 (例1) 条件一致した件数を求めるSQL SELECT a_mst.a_id FROM a_mst WHERE a_mst.a_price >= 100 AND a_mst.a_price <= 200 AND a_mst.a_print_flg = 0 SQLのSELECT にCOUNT等は使わない方がいいようなので主キーのみを出力させて count関数で件数を求めています。 このSQL文をEXPLAINでphpMyadminで実行すると id=1       select_type=SIMPLE   table=a_mst type=ALL    possible_keys=NULL   key=NULL key_len=NULL  ref=NUL          rows=a_mstに登録してある件数 Extra=Using where でした。SQL文自体はあるマスタにあるデータから値が100~200のもので、フラグが0のものを 出力するというシンプルなSQL文なのでどう改善すればよいのでしょうか? (例2) 2つのテーブルを結合させて条件一致したデータをそれぞれテーブルから出力 SELECT a_mst.a_name, a_mst.a_price, b_mst.b_data FROM a_mst, b_mst WHERE a_mst.a_id = b_mst.b_id AND a_mst.a_price >= 100 AND a_mst.a_price <= 200 AND a_mst.a_print_flg = 0 ORDER BY a_mst.a_price , a_mst.a_id asc LIMIT 20 OFFSET 0 です。a_mstとb_mstをidで結合させて条件一致したあとにそれぞれの テーブルデータをSELECTしています。実際のSQL文はSELECT させている項目数は多いです。 このSQL文をEXPLAINでphpMyadminで実行すると <1行目> id=1       select_type=SIMPLE    table=b_mst type=ALL    possible_keys=PRIMARY key=NULL key_len=NULL  ref=NUL          rows=a_mstに登録してある件数 Extra=Using temporary; Using filesort <2行目> id=1        select_type=SIMPLE    table=a_mst type=eq_ref    possible_keys=PRIMARY  key=PRIMARY key_len=NULL   ref=b_mst.b_id       rows=1 Extra=Using where でした。 EXPLAINを使ったチューニングなどしたことないSQL低級者なのでどのようなSQL文にすればtypeがALLの場合や、ExtraからUsing temporary; Using filesortを消すことができるのか分からないので教えて下さる方がいましたらよろしくお願いします。 ちなみに、a_mstとb_mstはphpMyadminにてそれぞれのテーブルの「構造」を見ると 「インデックスサイズ」のところで、それぞれの主キーであるa_idとb_idがPLIMARY で登録させています。編集ボタンを押したら「インデックスを修正する」画面に変わるので一応それぞれインデックス登録はされているのかな?と思います。

  • 単純なクエリーなのにSELECTしてもEmpty

    | Field  | Type | Null | Key | Default | Extra | +-----------------+--------------+------+-----+---------+----------------+ | page_id | int(10) | NO | PRI | NULL | auto_increment | | site   | varchar(255) | YES | MUL | NULL | | ... ... ... このようなテーブルがあり、以下の様なSELECT文を発行してもEmptyとなってしまいます。 > SELECT `page_id` FROM `table` WHERE `site` = 'hoge'; 自分なりに色々と調べてみたところ、 > UPDATE `table` SET `site` = 'fuga' WHERE `page_id` = 1; > SELECT `page_id` FROM `table` WHERE `site` = 'fuga'; とするとちゃんと1件返ってきます。 ですが、また > UPDATE `table` SET `site` = 'hoge' WHERE `page_id` = 1; > SELECT `page_id` FROM `table` WHERE `site` = 'hoge'; とするとEmptyとなってしまいます。 どうやら、INSERTしたレコードをWHERE `site` = 'hoge'するとEmptyとなるような気がします。 何度も試したので、単純に`site` = 'hoge'の文字列自体が間違っている、などのことは無いはずです。 以下の点も合わせて、どのような原因が考えられるでしょうか。 ・レコードのINSERTは、クローラーによって行われていています。 ・他のフィールドは通常通りSELECTすることができます。 ・ストレージエンジンはmroongaです。 どなたか解決策がわかる方いらっしゃいましたら、ご回答頂ければ幸いです。 宜しくお願い致します。

    • ベストアンサー
    • MySQL
  • select for updateのロック

    オラクルのselect for updateでロックをするタイミングがいつですか? こんなPL/SQLのコードがあったとします。 ---↓↓↓ソースコードここから↓↓↓------------------------- select * from テーブル1 where id = 1 for update; ・・・・・(a) ~ update テーブル1 set kingaku=100 where id = 1 ・・・・・(b) ~ commit; ---↑↑↑ソースコードここまで↑↑↑------------------------- id = 1のレコードがロックされるのは(a)、(b)どちらのタイミングですか? また、このロックは ・他トランザクションから読めるけど更新できない ・他トランザクションからは読むことすらできない のどちらでしょうか? よろしくお願いします。

  • SELECT分での結果の取り出し方

    以下の様なテーブルから SELECT分で条件をWHERE CODE = '0001' の様に指定して 求まった結果を1つの文字列にしたいのですが 良い方法がありましたら、教えて下さい。 SELECT * from testtbl; CODE NAME ------------------------------- 0001 AAAA 0001 BBBB 0002 CCCC 0003 DDDD この例だと、 SELECT NAME FROM testtbl WHERE CODE = '0001'の様な形で NAMEの部分の結果として,'AAAA,BBBB'の文字列を取得したいです。 ファンクションとかで実現できるでしょうか?

  • SELECT FOR UPDATE で該当レコードがなかった場合

    SELECT FOR UPDATE ですが、該当レコードのみ ロックすると思うんですが、 該当レコードがない場合は、 ロックできないんでしょうか? たとえば、(COLUMN_BBB が PK として) SELECT * FROM TABLE_AAA WHERE TABLE_AAA.COLUMN_BBB = 'BBB' FOR UPDATE で、そもそも SELECT * FROM TABLE_AAA WHERE TABLE_AAA.COLUMN_BBB = 'BBB' となるレコードがない場合でも、 他トランザクションによる 該当レコードの INSERT を排他防御できるのか無理なのか、 教えていただけたらありがたいです。 すみません、時間的余裕があまりないので、 (すぐに回答ほしいです)でアップします。

  • MySqlでのデータソートについて

    MySqlバージョン:5.1.61で、下記のSQLを実行すると、 1件しかデータが無いにも関わらず、EXPLAINの結果で 「Extra: Using where; Using filesort」が発生します。 ---------------- CREATE TABLE IF NOT EXISTS tbl ( user int(11) NOT NULL, item int(11) NOT NULL, prm1 int(11) NOT NULL, prm2 int(11) NOT NULL, prm3 int(11) NOT NULL, PRIMARY KEY (user,item) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO tbl (user,item,prm1,prm2,prm3) VALUES (1,1,10,10,10); EXPLAIN SELECT * FROM tbl WHERE user=1 ORDER BY prm1; EXPLAIN SELECT * FROM tbl WHERE user=1 ORDER BY prm2; EXPLAIN SELECT * FROM tbl WHERE user=1 ORDER BY prm3; ---------------- ORDER BY句で使用する項目(prm[n])は10項目以上になりますので 10件を超える複合インデックスを張る事は避けたいと考えております。 また、tbl全体のデータは1億件、1userあたり100~200件を想定しています。 複合インデックスを使用せず「Using filesort」を 発生させなくする事はできるのでしょうか?

    • ベストアンサー
    • MySQL
  • Select Case の条件式

    VBAの初心者です。 家計簿の品目に対して値段を自動で入力したいです。 以下のように、Select Case の条件式の指定方法で、 列に入力された文字列の条件に対して、 自動でとなりのセルに入力したいのですが解らなくて困っております。 Sub TEST() ' A列セルの条件(文字列)でとなりのセルに文字列を入れたい Select Case Range("A1").Value 'A1をどうすればいいのでしょうか。 Case "a": Range("列のセルのとなりに入力したい").Value = "リンゴ" Case "o": Range("列のセルのとなりに入力したい").Value = "オレンジ" Case "b": Range("列のセルのとなりに入力したい").Value = "バナナ" Case Else: Range("列のセルのとなりに入力したい").Value = "error" End Select End Sub ご存じの方がおられましたら教えていただけませんでしょうか。 よろしくお願いします。

  • select結果でのupdate

    テーブルがふたつあります。 片方のテーブルA(hoge1)のnameに、もう片方のB(hoge2)のnameをいれたいのです。 テーブルAとBはidでリレーションを張って、それぞれ対応する列にいれたいと思ってます。 tabale A hoge1 id | name | foo ----+-----+---- 1 | 1111 | xxxx 2 | 2222 | yyy 3 | 3333 | zzzz tabale B hoge2 id | name | bar ----+-----+--- 1 | 1.net | 1 2 | 2.net | 0 3 | 3.net | 1 期待する結果 tabale A hoge1 id | name | foo ----+-----+---- 1 | 1.net | xxxx 2 | 2.net | yyy 3 | 3.net | zzzz Bに変更はなし update hoge1 set name = b.name from hoge2 b , hoge1 a where a.id = b.id ; とやるとname列が全て 1.netになってしまい UPDATE hoge1 SET name = (select b.name from hoge2 b , hoge1 a where b.id = a.id ) ; ERROR: More than one tuple returned by a subselect used as an expression. とするとエラーです。(oracleならうまくいくとnetで調べたのですが。。) どなたかご教授いただけますか。

  • update文におけるwhereとjoinの違いについて

    はじめまして。 副問い合わせを使ったUPDATE文でわからない点があり、質問させていただきます。 使用しているDBはORACLE10gです。 SALARYとEMPLOYEESという二つのテーブルがあり、SALARY列とEMPLOYEES列には主キーとなるEMPLOYEEID列があります。 ここで、以下のSQLを発行した際に【1】は正しく更新され、【2】は「ORA-01427:単一行副問い合わせにより2つ以上の行が戻されます」というエラーが出ます。 whereを使った結合とjoinを使った結合は同じだと思っていたのですが、なぜこのように結果が異なるのかがわかりません。 どなたかご教示いただけないでしょうか。 【1】 UPDATE SALARY SET SALARY.AMOUNT = SALARY.AMOUNT + (SELECT AMOUNT FROM EMPLOYEES INNER JOIN SALARY s ON EMPLOYEES.EMPLOYEEID = s.EMPLOYEEID) 【2】 UPDATE SALARY SET SALARY.AMOUNT = SALARY.AMOUNT + (SELECT AMOUNT FROM EMPLOYEES WHERE SALARY.EMPLOYEEID = EMPLOYEES.EMPLOYEEID) 説明不足の点があればご指摘ください。よろしくお願いします。