2011-01-09 3 views
0

У меня есть огромные данные о сотрудниках в mysql с атрибутом в качестве родительского идентификатора, который хранит супервизора каждого сотрудника и определяется в иерархии. Каждый пользователь работает под другим сотрудником и обслуживает группу из 4-5 членов. Я часто нуждаюсь в дереве супервизора или подчиненных, для которого я использую рекурсивную функцию, чтобы получить работу с ее командой. Пожалуйста, предложите мне метод, чтобы мне не приходилось называть рекурсивную функцию каждый раз, когда мне нужны данные о сотрудниках. Использует «Views или хранимую процедуру» хорошую идею?MySQL Выберите запрос

Спасибо.

+0

Почему, это действительно дает вам проблемы с производительностью делать в запросе каждый раз? Звучит трудно поверить, если это всего лишь несколько десятков записей. –

+0

Но, возможно, кэш кеша mySQL стоит посмотреть (если он еще не активен): http://dev.mysql.com/doc/refman/5.1/en/query-cache.html –

+0

Вы имеете в виду, что вам нужно получить все дерево для одного сотрудника или просто следующий более высокий или древовидный раздел? –

ответ

0

При использовании хранимых процедур вам все равно потребуется рекурсия. Вы перемещаете рекурсию из исходного кода PHP в базу данных.

Вы можете использовать nested sets для хранения иерархических данных. Это избавляет от рекурсий по цене более высоких затрат на вставку, удаление и перемещение. В принципе, вы создаете два дополнительных поля left и right, где left < right и e1 является подчиненным e2 iff e1.left > e2.left && e1.right < e2.right.

Это делает запросы SELECT трудночитаемыми, но эффективными. Делайте это, когда все остальное терпит неудачу.

+0

Большое спасибо, господин Освальд, пожалуйста, напишите мне небольшой подробный код. –

+0

Спасибо, сэр, я получил вашу концепцию по этой ссылке http://dev.mysql.com/tech-resources/articles/hierarchical-data.html –

+0

Извините, что принял этот ответ поздно, так как сегодня я узнал об этом –

2

Ниже приведена нерекурсивная реализация хранимой процедуры, которая, очевидно, требует только одного вызова из вашего кода приложения, а не n вызовов (по одному для каждого уровня дерева). Порекомендую остаться вдали от вложенных наборов и придерживаться вашей реализации списка смежности - подумайте connect by 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

no probs - один день (скрещенные пальцы) mysql будет иметь CTE или соединить по функциональности, что сделает список adj с вложенным аргументом set спорным. –

Смежные вопросы