2017-01-11 4 views
0

두 개의 테이블이 있으며, 사용자 테이블과 날짜 테이블을 말할 수 있습니다. 그들은 다음과 같이 보일 것입니다 :여러 개의 동일한 테이블 왼쪽 조인 매우 느림

사용자

ID_User | Title | Firstname | Surname | JobNumber 
1  | Mr | Bob  | Smith | JOB001 
2  | Mrs | Bobbi  | Smythe | JOB001 
... 
13000 

날짜

ID_Date | ID_User | DateType | DateAssigned | JobNumber 
1  | 1  | Intent | 21-Jun-2016 | JOB001 
2  | 1  | Reg  | 21-Apr-2017 | JOB001 
3  | 1  | Flight | 21-May-2017 | JOB001 
4  | 2  | Intent | 09-Dec-2016 | JOB001 
5  | 2  | Flight | 01-Jan-2017 | JOB001 
... 
5000 

고유 인덱스가 ID_User + DateType + JobNumber입니다.

DateTypes가있을 수 있습니다.

다음과 같은 쿼리를 실행하면 시간이 오래 걸립니다.

select 
    ID_User, 
    Title, 
    Firstname, 
    Surname, 
    JobNumber, 
    DI.DateAssigned as Date_Intent, 
    DR.DateAssigned as Date_Reg, 
    DF.DateAssigned as Date_Flight 
from 
    User as U 
    left join Dates as DI on U.ID_User = DI.ID_User 
    and DI.JobNumber = "JOB001" 
    and DI.DateType = "Intent" 
    left join Dates as DR on U.ID_User = DR.ID_User 
    and DR.JobNumber = "JOB001" 
    and DR.DateType = "Reg" 
    left join Dates as DF on U.ID_User = DF.ID_User 
    and DF.JobNumber = "JOB001" 
    and DF.DateType = "Flight" 
where 
    U.JobNumber = "JOB001" 
order by 
    U.Surname, 
    U.Firstname; 

각 JobNumber에는 최대 300 개의 사람들이 있으며 최대 5 개의 다른 날짜 유형이 있습니다.

왜 그렇게 오래 걸립니까? 우리 2 분 얘기하고있어.

다른 방법으로 이것을 쓰고 있습니까?

날짜 테이블 :

explain select 
    U.ID_User, 
    U.Title, 
    U.Firstname, 
    U.Surname, 
    U.JobNumber, 
    DI.DateAssigned as Date_Intent, 
    DR.DateAssigned as Date_Reg, 
    DF.DateAssigned as Date_Flight 
from 
    ATL_Users as U 
    left join ATL_V2_Assigned_Dates as DI on U.ID_User = DI.ID_User 
    and DI.JobNumber = "ACI001" 
    and DI.DateType = "Deadline - Intention" 
    left join ATL_V2_Assigned_Dates as DR on U.ID_User = DR.ID_User 
    and DR.JobNumber = "ACI001" 
    and DR.DateType = "Event - Registration" 
    left join ATL_V2_Assigned_Dates as DF on U.ID_User = DF.ID_User 
    and DF.JobNumber = "ACI001" 
    and DF.DateType = "Deadline - Flight" 
where 
    U.JobNumber = "ACI001" 
order by 
    U.Surname, 
    U.Firstname; 

+----+-------------+-------+--------+------------------------------------+-----------+---------+------------------------------------+------+----------------------------------------------------+ 
| id | select_type | table | type | possible_keys      | key  | key_len | ref        | rows | Extra            | 
+----+-------------+-------+--------+------------------------------------+-----------+---------+------------------------------------+------+----------------------------------------------------+ 
| 1 | SIMPLE  | U  | ref | JobNumber       | JobNumber | 32  | const        | 506 | Using index condition; Using where; Using filesort | 
| 1 | SIMPLE  | DI | eq_ref | unq_idx,JobNumber,ID_User,DateType | unq_idx | 342  | const,cclliveo_atl.U.ID_User,const | 1 | Using where          | 
| 1 | SIMPLE  | DR | eq_ref | unq_idx,JobNumber,ID_User,DateType | unq_idx | 342  | const,cclliveo_atl.U.ID_User,const | 1 | Using where          | 
| 1 | SIMPLE  | DF | eq_ref | unq_idx,JobNumber,ID_User,DateType | unq_idx | 342  | const,cclliveo_atl.U.ID_User,const | 1 | Using where          | 
+----+-------------+-------+--------+------------------------------------+-----------+---------+------------------------------------+------+----------------------------------------------------+ 

I 돈 :

CREATE TABLE `ATL_V2_Assigned_Dates` (
    `ID_Date` bigint(7) unsigned NOT NULL AUTO_INCREMENT, 
    `JobNumber` varchar(10) NOT NULL DEFAULT '', 
    `ID_User` bigint(7) unsigned NOT NULL DEFAULT '0', 
    `DateAssigned` datetime NOT NULL, 
    `DateType` varchar(100) NOT NULL, 
    `Comment` text NOT NULL, 
    `Updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `Inserted` datetime NOT NULL, 
    PRIMARY KEY (`ID_Date`), 
    UNIQUE KEY `ID_Date` (`ID_Date`) USING BTREE, 
    UNIQUE KEY `unq_idx` (`JobNumber`,`ID_User`,`DateType`) USING BTREE, 
    KEY `JobNumber` (`JobNumber`) USING BTREE, 
    KEY `ID_User` (`ID_User`) USING BTREE, 
    KEY `DateType` (`DateType`) USING BTREE 
) ENGINE=MyISAM AUTO_INCREMENT=3975 DEFAULT CHARSET=utf8; 

UPDATE 2017년 1월 12일

아주 이상한, 쿼리가 지금 여기 0.06s에서 실행되고이의 출력입니다 내가 한 일과 우리가 한 일이 누군가 당신이 대답을 제공했다고 생각하는 사람에게 나를 가리킬 수 있는지, 나는 그것을 똑딱 거리게 할 수 있습니다. 고마워.

+0

두 테이블 모두에 대해 'SHOW CREATE TABLE'을 제공하십시오. 확인하고 싶은 몇 가지 사항이 있습니다. 또한'EXPLAIN SELECT ... '를 제공하십시오. –

답변

0

는 감안할 때

drop table if exists Userjobs; 
create table userjobs (ID_User int, Title varchar(10), Firstname varchar(10), Surname varchar(10), JobNumber varchar(10)); 
insert into userjobs values 
(1  , 'Mr' , 'Bob' ,  'Smith' , 'JOB001'), 
(2  , 'Mrs' , 'Bobbi',  'Smythe' , 'JOB001'); 


drop table if exists jobDates; 
create table jobdates(ID_Date int, ID_User int, DateType varchar(10), DateAssigned date, JobNumber varchar(10)); 
insert into jobdates values 
(1  , 1  , 'Intent' , '2016-06-21' , 'JOB001'), 
(2  , 1  , 'Reg'  , '2017-04-21' , 'JOB001'), 
(3  , 1  , 'Flight' , '2017-05-21' , 'JOB001'), 
(4  , 2  , 'Intent' , '2016-12-09' , 'JOB001'), 
(5  , 2  , 'Flight' , '2017-01-01' , 'JOB001'); 

MariaDB [sandbox]> select 
    -> u.ID_User, 
    -> Title, 
    -> Firstname, 
    -> Surname, 
    -> u.JobNumber, 
    -> max(case when datetype = 'intent' then dateassigned else null end) as intent, 
    -> max(case when datetype = 'reg' then dateassigned else null end) reg, 
    -> max(case when datetype = 'flight' then dateassigned else null end) as flight 
    -> from 
    -> Userjobs as U 
    -> left join jobDates as jd on U.ID_User = jd.ID_User 
    ->  and jd.JobNumber = u.jobnumber 
    -> where u.jobnumber = 'JOB001' 
    -> group by u.ID_User, 
    -> Title, 
    -> Firstname, 
    -> Surname, 
    -> u.JobNumber; 
+---------+-------+-----------+---------+-----------+------------+------------+------------+ 
| ID_User | Title | Firstname | Surname | JobNumber | intent  | reg  | flight  | 
+---------+-------+-----------+---------+-----------+------------+------------+------------+ 
|  1 | Mr | Bob  | Smith | JOB001 | 2016-06-21 | 2017-04-21 | 2017-05-21 | 
|  2 | Mrs | Bobbi  | Smythe | JOB001 | 2016-12-09 | NULL  | 2017-01-01 | 
+---------+-------+-----------+---------+-----------+------------+------------+------------+ 
2 rows in set (0.00 sec) 
+0

그 일을하는 좋은 방법 인 것처럼 보입니다. 시도해 보겠습니다. – Marty

0

아마도 적절한 색인이 부족합니다. 시도하십시오 :

create index idx_user (jobnumber, id_user); 
create index idx_dates (jobnumber, datetype, id_user, dateassigned); 
+0

나는 그 색인을 가지고있다. – Marty

+0

너무 나쁨. 'create index idx_dates2 (id_user, jobnumber, datetype, dateassigned);도 시도해 볼 수 있습니다. 어쩌면 user_id를 통한 직접 액세스가 더 빠르며 먼저 작업 번호와 datetime으로 필터링 할 수 있습니다. 나는 그것을 의심하지만 여전히 시도할만한 가치가있다. –

+0

귀찮은 것은 세 가지 데이터 유형에 대해 3 개의 subselect를 사용하고 테이블에 전혀 조인하지 않는 것이 빠르다는 것입니다. 쿼리는 분이 아니라 초가 걸립니다. 하지만, subselects가 싫어 정말 조인이 빨라야한다고 생각합니다. – Marty

0

이것은 동일한 테이블에 참여하는 가장 좋은 방법입니다. 소요 시간은 확실하지 않습니다. 30,000 개의 레코드를 쿼리해도 2 분이 소요되지 않습니다. 이것은 데이터베이스에 대한 다중 연결과 같은 다른 문제로 인해 야합니다. 당신은 모든 사람을 피하기 위해 조건부 집계를 시도 할 수

0

U 요구 INDEX(JobNumber, Surname, Firstname)을 결합한다. 그것은 WHEREORDER BY을 포함해야하며, 따라서 '파일 공유'를 피할 수 있습니다.

Dates의 경우 UNIQUE(ID_User, DateType, JobNumber)이 맞습니까? 의 그 테이블에서 id 제거하자, 다음 BTREE의 바닥이 인접 것이다 필요한 DateAssigned 세 개의 행이 포함되므로 UNIQUE

PRIMARY KEY(JobNumber, ID_User, DateType) 

이는 조회가보다 효율적으로 만들 것이다 교체의 때문에 PK의 "클러스터링".

다른 쿼리 (읽기 또는 수정)가 Dates이 아닌 경우 해당 테이블에 다른 인덱스가 없어야합니다.

이 테이블의 크기는 어느 정도입니까? 당신은 당신이 그들 모두를 완전히 읽을 것이라는 것을 깨닫게됩니다. 그러나 제 제안은 각 행을 한 번만 읽고 여러 번 읽지 않게 할 것입니다.

+0

Dates 테이블의 원래 게시물을 수정했습니다. 위 참조하십시오, 그것은 그것을 여기 게시 할 수 없습니다. – Marty