[前][次][番号順一覧][スレッド一覧]

mysql:15349

From: MATSUNAGA Ichiro <MATSUNAGA Ichiro <vikke.bsd@xxxxxxxxxx>>
Date: Mon, 28 Jun 2010 21:38:23 +0900
Subject: [mysql 15349] 検索条件カラムを縦持ちにした場合の検索の性能について。

松永です。

あるテーブルに紐付く検索条件項目が非常に多くある場合のテーブル設計/検索の仕方で悩んでいます。

普通に横持ちの場合、
create table a (
	a_id int(10) not null,
	fk_id int(10) not null,
	name varchar(255) not null,
	cond1 int(2),
	cond2 int(2),
	cond3 int(2),
	....
	primary key (a_id),
	index (cond1, cond2, cond3,...)
)
のような感じで、条件が60以上並び、また条件が追加などされる可能性があるテーブルがあります。このテーブルは他のテーブルをjoinして使います。
検索軸としては、cond1 > 10 and cond3 = 20のように、必ず全ての条件カラムを使うとは限りません。

そこで、条件を下記のように縦持ちにしてみました。
また、条件はコードのようになっているので、cond1自体を001、cond2自体を002等とし、そのcond自体が持つコードを後ろに連結し、cond1が10の場合を00110(正しくは110)というintで表わすようにしました。

create table a (
	a_id int(10) not null,
	o_id int(10) not null,
	name varchar(255) not null,
	primary key (a_id)
)

create table cond (
	a_id int(10) not null,
	cond int(5) not null,
	primary key (a_id, cond)
)

この状態で、他のtable(other)をjoinしつつ、cond1(001)が10あるいは20、かつcond2(002)が70あるいは80あるいは90の条件を見たすrecordが欲しい場合、
select a_id, o.val
from
	a
inner join cond c1 using(a_id)
inner join cond c2 using(a_id)
inner join other o using(o_id)
where 
	c1.cond between 00110 and 00120
	and c2.cond between 00270 and 00290;
というsqlを実行してみたのですが、結構重い状態です。
condにはテストデータが135万件程度入ってる状態で、 初回実行(キャッシュに乗っていないと思われる状態)で、8秒近く掛る場合もある為、ちょっと性能的に問題外な状態になってしまってます。

本番の場合はcondは1000万件になる予定です。また、このqueryは発行される数は、5q/s程度考えられます。

これ、なにか考え方が間違っているのでしょうか。
なにか指摘頂けるとありがたいです。


下記に上記内容を纏めたsqlを添付します。
---------------------------------------------
create table other (
	o_id int(10) not null,
	val varchar(255) not null,
	primary key(o_id)
);
create table a (
	a_id int(10) not null,
 	o_id int(10) not null,
  name varchar(255) not null,
	primary key (a_id),
	index (a_id, o_id)
);
-- 条件テーブル
create table cond (
	a_id int(10) not null,
	cond int(5) not null,
	primary key (a_id, cond)
);
insert into other (o_id, val) values(1,'1'), (2,'2'), (3,'3');
insert into a (a_id, o_id, name) values (1, 1, '1'), (2, 1, '2'), (3,2,'3'),(4,2,'4');
insert into cond (a_id, cond) values(1, 00110), (2, 00120), (1, 00201), (2, 00270), (2,00230), (3,00290);
	
-- explain
select a_id, o.val
from
	a
inner join cond c1 using(a_id)
inner join cond c2 using(a_id)
inner join other o using(o_id)
where 
	c1.cond between 00110 and 00120
	and c2.cond between 00270 and 00290;




-- 
MATSUNAGA Ichiro
e-mail: vikke.bsd@xxxxxxxxxx
/.j: http://slashdot.jp/~vikke/
last.fm: http://www.lastfm.jp/user/vikke_bsd/
twitter: http://twitter.com/vikke

Just remember - when you think all is lost, the future remains.
-- Robert H. Goddard

GPG fingerprint = DCEF C86E 2930 45D0 0941  E977 4DCE A95F 3914 4BED


添付ファイル

[前][次][番号順一覧][スレッド一覧]

-> @ 15349 2010-06-28 21:38 [MATSUNAGA Ichiro <vi] 検索条件カラムを縦持ちにした場合の検索の性能について。
   @ 15350 2010-06-28 21:44 ┣[MATSUNAGA Ichiro <vi]                                       
     15351 2010-06-28 23:35 ┗[とみたまさひろ <tomm]                                       
     15357 2010-07-01 15:57  ┗[Mikiya Okuno <mikiya]