テーブルの主キーが文字列の場合、通し番号に置き換えて検索を速くする方法はあるか?

このQ&Aのポイント
  • データベースのテーブルで主キーが文字列の場合、その主キーを通し番号に置き換えることで検索の速度を向上させることができるのかについて調査しています。
  • 長いテスト項目名など40文字以上の文字列の場合、主キーを通し番号に置き換えることで検索速度が向上する可能性があります。
  • 通し番号に置き換えるときにどの文字数以上から効果が現れるのかについて、皆さんのご意見や経験を教えていただきたいです。
回答を見る
  • ベストアンサー

データベース:主キーが文字列の場合IDを振るべき?

テーブルの主キーが文字列の場合、 その主キーの文字列を通し番号に置き換えて、 その文字列は別テーブルに移したほうが検索が速いですか? 例えば、テーブルが CREATE TABLE spec ( test_name VARCHAR(40) NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_name) ); で、40文字という長いテスト項目名の場合、 CREATE TABLE spec ( test_id INTEGER NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_id) ); と CREATE TABLE test ( test_id INTEGER NOT NULL, test_name VARCHAR(40) NOT NULL, PRIMARY KEY(test_id) ); という二つのテーブルに分けたほうが検索は速くなりますか? (もちろん、結合する時間も含めてです。) もし速くなるとしても、文字数が3文字など少ない場合は 通し番号に置き換えてもきっと効果は薄いですよね? 何文字以上の文字列なら通し番号に置き換えたほうが速いですか? 皆さんはどのように決めていますか?

  • sucker
  • お礼率91% (213/234)

質問者が選んだベストアンサー

  • ベストアンサー
  • t_ohta
  • ベストアンサー率38% (5071/13250)
回答No.1

検索する時の条件は何ですか? upper_limit , lower_limit を検索するのであればどちらも違いが無いでしょう。 test_name を検索するのであれば、プライマリキーに指定されてインデックスが作成されている方が速いので前者です。 プライマリキーにするくらいですから test_name が完全なユニーク値でしょうから、別途数値キーを作らなくてもいいと思います。 もし、このテーブルと結合するテーブルが他にもいっぱいあるのであれば数値キーをプライマリーキーにした方がインデックスが小さくなってメモリの使用効率が上がり速くなると思いますが、例示されているようなテーブル分割は意味が無いと思います。

sucker
質問者

お礼

ベストアンサーを差し上げます。 今回の場合は、わざわざ数値キーを別途作らなくてもいいんですね。 お察しの通り、検索条件はテスト項目名で、各テスト項目名はユニーク値です。 では、結合するテーブルが増えてきたら数値キーの追加を考えます。 自分はインデックスの仕組みが数値の場合(B-tree)しか知らないので、今度文字列のインデックスについて調べてみます。 ご回答ありがとうございました!

関連するQ&A

  • データベース:二つのテーブルの繋ぎ方

    私(あなた)が検査担当者だとします。 そして、測定担当者から CREATE TABLE measurement ( lot VARCHAR(10) NOT NULL, test_id INTEGER NOT NULL, data NUMERIC(17,7), PRIMARY KEY(lot, test_id) ); という、あるロットでのテスト番号に対する測定値データが送られてきたとします。 そして、設計担当者から CREATE TABLE spec ( test_name VARCHAR(10) NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_name) ); という、テスト項目名に対する上限・下限の仕様データが送られてきたとします。 ここで、テスト番号とテスト項目名は同じ数だけあって、お互いが一致するように同じ順番で並んでいるとします。 この二つのテーブルを使って、測定値が範囲内か範囲外かを調べるのが目的です。 この場合、どうやって二つのテーブルを繋ぐのが一般的ですか? 自分の考えだと、一旦、specテーブルにtest_idを加えて CREATE TABLE spec ( test_id INTEGER NOT NULL, test_name VARCHAR(10) NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_id, test_name) ); とするのですが、第二(第三?)正規化に基づいて CREATE TABLE spec ( test_id INTEGER NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_id) ); と CREATE TABLE test ( test_id INTEGER NOT NULL, test_name VARCHAR(10), PRIMARY KEY(test_id) ); の二つに分けるのかな、と思っています。 正規化の観点から言うと、きっとこれが正しいのかなと思っています。 でも、元々、specテーブルにはテスト項目名が入っていたのでテスト項目名と上限・下限が一目で分かっていたのに、このように分けると、いちいちspecテーブルでテスト番号を確認してから、testテーブルでそのテスト番号に該当するテスト項目名を見つけなくてはならなくなってしまいます。クエリーでの検索もJOINをしなければならなくなって遅くなりませんか? 敢えて正規化しないでおく、なんて手段もありますか? こんな場合、皆さんならどうしますか? 「こうするように決められている」なのか、 「ああもできるし、こうもできるんですが、どっちでもいいですよ」なのか、 温度差みたいなものもできれば知りたいです。

  • varchar型を主キーに…

    現在サーブレット/JSPを利用してDBにユーザアカウントを登録、削除、更新、一覧をできるようするシステムを作成しています。 テーブルを create table loginuser ( userId char(16) not null default '', passwd char(16) not null default '', name varchar(50) not null default '', accessFlg int(1) not null default '0', primary key(userId)); で作成しました。 IDが数字の時はDBに登録ができるのですがIDに文字を入力するとDBに登録されません。 主キーをvarchar型で使用するのは不可能なのでしょうか? ご返答をよろしくお願いします。

  • MySQL SELECTの指定について

    まず、御覧頂きありがとうございます。 早速質問なのですが、 CREATE TABLE `hoge` ( `id` int(8) NOT NULL, `name` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `hoge` (`id`, `name`) VALUES (1, 'hogeA'), (2, 'hogeB'), (3, 'hogeC'), (4, 'hogeD'); CREATE TABLE `test` ( `id` int(8) NOT NULL, `name` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `test` (`id`, `name`) VALUES (1, 'testA'), (4, 'testD'); という値が入ってるテーブルがあるとします。(長くなってすみません) で、 hoge.id と test.id が重複した場合 test.name を表示させたいです。 期待値としては id,name 1.testA 2,hogeB 3,hogeC 4,testD になります。 業務でJoinを使うようなテーブル構造にそもそもしないというのもあり、クリティカルなSQLコードに不慣れで御知恵を借りたく質問させて頂きました。 よろしくお願いします。

    • ベストアンサー
    • MySQL
  • 同じ構成の2つのテーブルの更新について

    はじめまして、下のような2つの同じ構成のテーブルがあった場合に create table test1 ( key1 varchar(8) not null, key2 varchar(4) not null, key3 varchar(6) not null, key4 varchar(11) not null, suryo int(9), kingaku int(11), constraint test1_key primary key (key1,key2,key3,key4) ); create table test2 ( key1 varchar(8) not null, key2 varchar(4) not null, key3 varchar(6) not null, key4 varchar(11) not null, suryo int(9), kingaku int(11), constraint test2_key primary key (key1,key2,key3,key4) ); 10万件のtest1テーブルに 5件のtest2テーブルの内容をキー集計した結果を test1に反映するにはどうのようなSQL文を書けば、効率的なのでしょうか? 片方のテーブルはデータ量が多く、もう片方は数件の更新処理となります。 宜しくお願いいたします。 ・処理前 (test1テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","1111","111111","11111111111",10,1000 "20070521","2222","222222","22222222222",5,5000 "20070521","3333","333333","33333333333",1, 100 (test2テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","2222","222222","22222222222",10,30000 ↓ ・処理後 (test1テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","1111","111111","11111111111",10,1000 "20070521","2222","222222","22222222222",15,35000 "20070521","3333","333333","33333333333",1, 100

    • ベストアンサー
    • MySQL
  • Oracleでテーブルを作成する際に、インデクスの作成先を指定したい。

    以下のようにテーブルを作成しようとしてます。 CREATE TABLE TEST_USER.M_USER ( ID char(4), NAME varchar2(40) NOT NULL), CONSTRAINT PK_USER PRIMARY KEY(ID) ); さて、プライマリキーを定義しているので、インデクスが作成されるはずです。 この作成先のテーブルスペースを指定したいのですが、方法が解りません。 CREATE TABLEの紹介をしているサイトにものっていなくて、途方にくれています・・・。 CONSTRAINT句を使えばいいのでしょうか?

  • TABLE名に使えない文字列をエスケープするには?

    aaa.bbbのように、TABLE名に.(ドット)を使いたいのですが、このままだとエラーが発生してしまいます。 mysql> CREATE TABLE aaa.bbb ( id MEDIUMINT NOT NULL AUTO_INCREMENT, abc varchar(16), xyz varchar(16), PRIMARY KEY (id) ); ERROR 1049 (42000): Unknown database 'aaa' .(ドット)をエスケープするにはどうすればよいでしょうか? ちなみに\(バックスラッシュ)を.(ドット)に前置してもエラーになってしまいます。

    • ベストアンサー
    • MySQL
  • MySQLでのテーブル作成

    MySQLでこういったテーブルを作成したのですが、 CREATE TABLE NOSGI ( GNRE_CD CHAR(5) NOT NULL, GNRE_NAME VARCHAR(20) NOT NULL, PRIMARY KEY (GNRE_CD) ); GNRE_CDはCHAR型で作成したのに、カラムの情報を見ると、 VARCHAR型にしまうのですが、どうしてでしょうか?

  • auto_incrementを任意の数字から開始するには

    次のようなテーブルで入力するとidが1~始まりますが、 これを1000~開始する方法が分かりません、ご教授お願いします。 CREATE TABLE addressbook ( id smallint(4) UNSIGNED NOT NULL auto_increment, name1 varchar(20) default NULL, birthday date default NULL, PRIMARY KEY (id) ) ENGINE=MyISAM DEFAULT CHARSET=sjis;

    • ベストアンサー
    • MySQL
  • データベースの考え方で。

    データベースの考え方、で教えてください。 路線検索と、路線にひもづく駅名の時刻表を表示させる、データベースを作りたいと思っているのですが、 その場合、考え方としては、以下のような感じになるのでしょうか? 路線名のtbl sql文: create table transit ( id integer not null, name varchar(20) not null ); 路線名tblにひもづく、駅名tbl sql文: create table station ( id integer not null primary key, transit_id integer not null, name varchar(20) not null ); 駅名tblにひもづく、時刻表tbl sql文: create table timetable ( id integer not null primary key, station_id integer not null, hour integer not null, minute integer not null ); 表示パターンとしては、 ================================= ○○線: XX駅 6:10 20 7:30 55 . . . . . . 22:15 36 ================================== のような感じです。 よろしくお願いします。

  • 基本的なSQL文

    とても基本的なことだと思うのですが、以下のようなテーブルがあるとします。 create table test ( id numeric primary key, name varchar(45), age numeric ); これに例えば以下のようにデータを詰めたとします。 +----+----------+------+ | id | name | age | +----+----------+------+ | 1 | takeshi1 | 50 | | 2 | takeshi2 | 25 | | 3 | takeshi3 | 30 | | 4 | takeshi4 | 35 | | 5 | takeshi5 | 40 | | 6 | takeshi6 | 45 | +----+----------+------+ ここで最年少のレコードを取り出したいだけなのですが mysql> select id, name, min(age) from test;とすると +----+---------+----------+ | id | name | min(age) | +----+---------+----------+ | 1 | takeshi1| 25 | +----+---------+----------+ 年は最年少が取り出されますがidとnameは一行目が取り出されているようです。どのようなSQLを書けば以下のようになるのでしょうか。 +----+---------+----------+ | id | name | min(age) | +----+---------+----------+ | 2 | takeshi2| 25 | +----+---------+----------+

    • ベストアンサー
    • MySQL