2011-01-09 7 views
0

私は、各従業員のスーパーバイザを格納し、階層で定義されている親IDとしての属性を持つmysqlの巨大な従業員データを持っています。各ユーザーは他の従業員の下で働いており、4-5人のメンバーのチームを扱っています。私は頻繁に私はそのチームと雇用をフェッチするために再帰的な関数を使用しているスーパーバイザーまたは従属ツリーが必要です。従業員データが必要なたびに再帰関数を呼び出す必要がないようにメソッドを提案してください。 "ビューまたはストアドプロシージャ"を使用していますか?MySQL Selectクエリ

ありがとうございました。

+0

なぜ、それは実際にクエリを毎回行うためにあなたのパフォーマンスの問題を与えていますか?単なる数十のレコードであれば信じがたいです。 –

+0

しかし、多分mySQLのクエリキャッシュは価値があります(まだアクティブでない場合):http://dev.mysql.com/doc/refman/5.1/en/query-cache.html –

+0

1人の従業員、または次の上位またはツリーセクションのツリー全体をフェッチしますか? –

答えて

0

ストアドプロシージャを使用する場合でも、再帰が必要です。再帰は、PHPソースコードからデータベースに移動するだけです。

nested setsを使用して階層データを格納できます。これにより、挿入、削除、再配置のコストが高くなるという再帰がなくなります。基本的に、2つの追加フィールドleftrightを作成します。left < righte1e2の場合、e1.left > e2.left && e1.right < e2.rightの従属です。

これは、SELECTクエリを読みにくく効率的にします。他のすべてが失敗したときにこれを行います。

+0

多くのありがとうMr Oswald、少し詳細なコードを私に書いてください。 –

+0

ありがとうございました。このリンクからあなたのコンセプトを得ました。http://dev.mysql.com/tech-resources/articles/hierarchical-data.html –

+0

申し訳ありませんが、遅くともこの回答を受け付けました。私は今日それについて知りました。 –

2

ここでは、明らかにn個の呼び出しではなく、アプリケーションコードからの呼び出しを1回だけ必要とする非再帰ストアドプロシージャの実装を示します(ツリーの各レベルに1つ)。ネストされたセットからうまく離れず、隣接リストの実装を守ることをお勧めします。は、 OracleとCTEによってSQLサーバーに接続します。

drop table if exists employees; 
create table employees 
(
emp_id smallint unsigned not null auto_increment primary key, 
name varchar(255) not null, 
boss_id smallint unsigned null, 
key (boss_id) 
) 
engine = innodb; 

insert into employees (name, boss_id) values 
('f00',null), 
    ('ali later',1), 
    ('megan fox',1), 
     ('jessica alba',3), 
     ('eva longoria',3), 
     ('keira knightley',5), 
      ('liv tyler',6), 
      ('sophie marceau',6); 


drop procedure if exists employees_hier; 

delimiter # 

create procedure employees_hier 
(
in p_emp_id smallint unsigned 
) 
begin 

declare v_done tinyint unsigned default(0); 
declare v_dpth smallint unsigned default(0); 

create temporary table hier(
boss_id smallint unsigned, 
emp_id smallint unsigned, 
depth smallint unsigned 
)engine = memory; 

insert into hier select boss_id, emp_id, v_dpth from employees where emp_id = p_emp_id; 

/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */ 

create temporary table emps engine=memory select * from hier; 

while not v_done do 

    if exists(select 1 from employees e inner join hier on e.boss_id = hier.emp_id and hier.depth = v_dpth) then 

     insert into hier select e.boss_id, e.emp_id, v_dpth + 1 
      from employees e inner join emps on e.boss_id = emps.emp_id and emps.depth = v_dpth; 

     set v_dpth = v_dpth + 1;    

     truncate table emps; 
     insert into emps select * from hier where depth = v_dpth; 

    else 
     set v_done = 1; 
    end if; 

end while; 

select 
e.emp_id, 
e.name as emp_name, 
p.emp_id as boss_emp_id, 
p.name as boss_name, 
hier.depth 
from 
hier 
inner join employees e on hier.emp_id = e.emp_id 
left outer join employees p on hier.boss_id = p.emp_id; 

drop temporary table if exists hier; 
drop temporary table if exists emps; 

end # 

delimiter ; 

-- call this sproc from your php 

call employees_hier(1); 
+0

多くのありがとう、レームそれを試してみてくださいこれは私のために動作します。 :) –

+0

probs - 1日(指が交差)mysqlはCTEを持っているか、adjリストとネストされたset引数mootを作る機能によって接続します。 –