Mysql 교묘 한 join 최적화 sql 방법 상세 설명

0.관련 표를 준비 하여 다음 테스트 진행
관련 건축 표 문 구 는 다음 과 같 습 니 다.https://github.com/YangBaohust/my_sql

user1 ,   
+----+-----------+-----------------+---------------------------------+
| id | user_name | comment   | mobile       |
+----+-----------+-----------------+---------------------------------+
| 1 |     |        | 138245623,021-382349   |
| 2 |     |       | 159384292,022-483432,+86-392432 |
| 3 |     |       | 183208243,055-8234234   |
| 4 |     |       | 293842295,098-2383429   |
| 5 | NULL  |       | 993267899      |
+----+-----------+-----------------+---------------------------------+

user2 ,      
+----+--------------+-----------+
| id | user_name | comment |
+----+--------------+-----------+
| 1 |      |     |
| 2 |      |     |
| 3 |       |     |
| 4 |       |     |
| 5 | NULL   |     |
+----+--------------+-----------+

user1_kills ,          
+----+-----------+---------------------+-------+
| id | user_name | timestr    | kills |
+----+-----------+---------------------+-------+
| 1 |     | 2013-01-10 00:00:00 | 10 |
| 2 |     | 2013-02-01 00:00:00 |  2 |
| 3 |     | 2013-02-05 00:00:00 | 12 |
| 4 |     | 2013-02-12 00:00:00 | 22 |
| 5 |     | 2013-01-11 00:00:00 | 20 |
| 6 |     | 2013-02-07 00:00:00 | 17 |
| 7 |     | 2013-02-08 00:00:00 | 35 |
| 8 |     | 2013-01-10 00:00:00 |  3 |
| 9 |     | 2013-01-22 00:00:00 |  9 |
| 10 |     | 2013-02-11 00:00:00 |  5 |
+----+-----------+---------------------+-------+

user1_equipment ,     
+----+-----------+--------------+-----------------+-----------------+
| id | user_name | arms   | clothing  | shoe   |
+----+-----------+--------------+-----------------+-----------------+
| 1 |     |       |       |      |
| 2 |     |      |        |        |
| 3 |     |       |      |      |
| 4 |     |       |      |      |
+----+-----------+--------------+-----------------+-----------------+
1.left join 을 사용 하여 자구 에 최적화 하지 않 음
예:취 경 팀 에서 오 공 친구 권 에 속 하지 않 는 사람 을 찾 아 라.

+----+-----------+-----------------+-----------------------+
| id | user_name | comment   | mobile    |
+----+-----------+-----------------+-----------------------+
| 1 |     |        | 138245623,021-382349 |
| 3 |     |       | 183208243,055-8234234 |
| 4 |     |       | 293842295,098-2383429 |
+----+-----------+-----------------+-----------------------+
not in 서법:

select * from user1 a where a.user_name not in (select user_name from user2 where user_name is not null);
left join 쓰기:
우선 username 연 결 된 외부 연결 데이터 세트

select a.*, b.* from user1 a left join user2 b on (a.user_name = b.user_name);

+----+-----------+-----------------+---------------------------------+------+-----------+-----------+
| id | user_name | comment   | mobile       | id | user_name | comment |
+----+-----------+-----------------+---------------------------------+------+-----------+-----------+
| 2 |     |       | 159384292,022-483432,+86-392432 | 1 |     |     |
| 1 |     |        | 138245623,021-382349   | NULL | NULL  | NULL  |
| 3 |     |       | 183208243,055-8234234   | NULL | NULL  | NULL  |
| 4 |     |       | 293842295,098-2383429   | NULL | NULL  | NULL  |
| 5 | NULL  |       | 993267899      | NULL | NULL  | NULL  |
+----+-----------+-----------------+---------------------------------+------+-----------+-----------+
a 표 의 모든 데 이 터 를 볼 수 있 습 니 다.b 표 의 데 이 터 는 b.user 밖 에 없습니다.name 과 a.username 이 같 아야 표시 되 고 나머지 는 null 값 으로 채 워 집 니 다.취 경 팀 에서 오 공 친구 권 에 속 하지 않 는 사람 을 찾 으 려 면 b.username 에 필터 조건 추가 b.username is null 이면 됩 니 다.

select a.* from user1 a left join user2 b on (a.user_name = b.user_name) where b.user_name is null;

+----+-----------+-----------------+-----------------------+
| id | user_name | comment   | mobile    |
+----+-----------+-----------------+-----------------------+
| 1 |     |        | 138245623,021-382349 |
| 3 |     |       | 183208243,055-8234234 |
| 4 |     |       | 293842295,098-2383429 |
| 5 | NULL  |       | 993267899    |
+----+-----------+-----------------+-----------------------+
여기 보 니 집중 적 으로 백 룡 마 가 하나 더 생 겼 습 니 다.여과 조건 a.user 을 계속 추가 하 세 요.name is not null 이면 됩 니 다.

select a.* from user1 a left join user2 b on (a.user_name = b.user_name) where b.user_name is null and a.user_name is not null;
2.left join 을 사용 하여 양자 조회 최적화
예:취 경 팀 의 오 공 친구 들 의 닉네임 보기

+-----------+-----------------+-----------+
| user_name | comment   | comment2 |
+-----------+-----------------+-----------+
|     |        | NULL  |
|     |       |     |
|     |       | NULL  |
|     |       | NULL  |
| NULL  |       | NULL  |
+-----------+-----------------+-----------+
하위 검색 쓰기:

select a.user_name, a.comment, (select comment from user2 b where b.user_name = a.user_name) comment2 from user1 a;
left join 쓰기:

select a.user_name, a.comment, b.comment comment2 from user1 a left join user2 b on (a.user_name = b.user_name);
3.join 을 사용 하여 집합 서브 조회 최적화
예:추출 팀 에서 모든 사람 이 몬스터 를 가장 많이 때 리 는 날 짜 를 조회 합 니 다.

+----+-----------+---------------------+-------+
| id | user_name | timestr    | kills |
+----+-----------+---------------------+-------+
| 4 |     | 2013-02-12 00:00:00 | 22 |
| 7 |     | 2013-02-08 00:00:00 | 35 |
| 9 |     | 2013-01-22 00:00:00 |  9 |
+----+-----------+---------------------+-------+
집합 서브 조회 쓰기:

select * from user1_kills a where a.kills = (select max(b.kills) from user1_kills b where b.user_name = a.user_name);
join 쓰기:
먼저 두 표 가 연 결 된 결과 집 을 보고 지면 을 절약 하기 위해 저팔계 의 몬스터 데이터 만 추출 한 것 을 보면

select a.*, b.* from user1_kills a join user1_kills b on (a.user_name = b.user_name) order by 1;

+----+-----------+---------------------+-------+----+-----------+---------------------+-------+
| id | user_name | timestr    | kills | id | user_name | timestr    | kills |
+----+-----------+---------------------+-------+----+-----------+---------------------+-------+
| 5 |     | 2013-01-11 00:00:00 | 20 | 5 |     | 2013-01-11 00:00:00 | 20 |
| 5 |     | 2013-01-11 00:00:00 | 20 | 6 |     | 2013-02-07 00:00:00 | 17 |
| 5 |     | 2013-01-11 00:00:00 | 20 | 7 |     | 2013-02-08 00:00:00 | 35 |
| 6 |     | 2013-02-07 00:00:00 | 17 | 7 |     | 2013-02-08 00:00:00 | 35 |
| 6 |     | 2013-02-07 00:00:00 | 17 | 5 |     | 2013-01-11 00:00:00 | 20 |
| 6 |     | 2013-02-07 00:00:00 | 17 | 6 |     | 2013-02-07 00:00:00 | 17 |
| 7 |     | 2013-02-08 00:00:00 | 35 | 5 |     | 2013-01-11 00:00:00 | 20 |
| 7 |     | 2013-02-08 00:00:00 | 35 | 6 |     | 2013-02-07 00:00:00 | 17 |
| 7 |     | 2013-02-08 00:00:00 | 35 | 7 |     | 2013-02-08 00:00:00 | 35 |
+----+-----------+---------------------+-------+----+-----------+---------------------+-------+
두 표 가 user 를 통과 하 는 것 을 볼 수 있 습 니 다.name 자체 연결 을 진행 하려 면 a 표 의 모든 필드 에 group by 를 진행 하고 b 표 의 max(kills)를 가 져 오 십시오.a.kills=max(b.kills)만 있 으 면 요 구 를 만족 시 킬 수 있 습 니 다.sql 은 다음 과 같 습 니 다.

select a.* from user1_kills a join user1_kills b on (a.user_name = b.user_name) group by a.id, a.user_name, a.timestr, a.kills having a.kills = max(b.kills);
4.join 을 사용 하여 그룹 선택
예:세 번 째 예 에 대해 업 그 레이 드 를 하고 추출 팀 에서 모든 사람 이 몬스터 를 가장 많이 때 리 는 앞의 두 날 짜 를 조회 합 니 다.

+----+-----------+---------------------+-------+
| id | user_name | timestr       | kills |
+----+-----------+---------------------+-------+
| 3 |      | 2013-02-05 00:00:00 |  12 |
| 4 |      | 2013-02-12 00:00:00 |  22 |
| 5 |      | 2013-01-11 00:00:00 |  20 |
| 7 |      | 2013-02-08 00:00:00 |  35 |
| 9 |      | 2013-01-22 00:00:00 |   9 |
| 10 |      | 2013-02-11 00:00:00 |   5 |
+----+-----------+---------------------+-------+
Oacle 에서 분석 함 수 를 통 해 실현 할 수 있 습 니 다.

select b.* from (select a.*, row_number() over(partition by user_name order by kills desc) cnt from user1_kills a) b where b.cnt <= 2;
유 감 스 럽 지만 위의 sql 은 my sql 에서 ERROR 1064(42000)를 잘못 보 고 했 습 니 다.You have an error in your SQL syntax;my sql 은 분석 함 수 를 지원 하지 않 기 때 문 입 니 다.하지만 아래 의 방식 으로 이 루어 질 수 있다.
먼저 두 표 에 대해 자체 관 계 를 하고 편폭 을 절약 하기 위해 손오공 의 데이터 만 꺼낸다.

select a.*, b.* from user1_kills a join user1_kills b on (a.user_name=b.user_name and a.kills<=b.kills) order by a.user_name, a.kills desc;

+----+-----------+---------------------+-------+----+-----------+---------------------+-------+
| id | user_name | timestr       | kills | id | user_name | timestr       | kills |
+----+-----------+---------------------+-------+----+-----------+---------------------+-------+
| 4 |      | 2013-02-12 00:00:00 |  22 | 4 |      | 2013-02-12 00:00:00 |  22 |
| 3 |      | 2013-02-05 00:00:00 |  12 | 3 |      | 2013-02-05 00:00:00 |  12 |
| 3 |      | 2013-02-05 00:00:00 |  12 | 4 |      | 2013-02-12 00:00:00 |  22 |
| 1 |      | 2013-01-10 00:00:00 |  10 | 1 |      | 2013-01-10 00:00:00 |  10 |
| 1 |      | 2013-01-10 00:00:00 |  10 | 3 |      | 2013-02-05 00:00:00 |  12 |
| 1 |      | 2013-01-10 00:00:00 |  10 | 4 |      | 2013-02-12 00:00:00 |  22 |
| 2 |      | 2013-02-01 00:00:00 |   2 | 1 |      | 2013-01-10 00:00:00 |  10 |
| 2 |      | 2013-02-01 00:00:00 |   2 | 3 |      | 2013-02-05 00:00:00 |  12 |
| 2 |      | 2013-02-01 00:00:00 |   2 | 4 |      | 2013-02-12 00:00:00 |  22 |
| 2 |      | 2013-02-01 00:00:00 |   2 | 2 |      | 2013-02-01 00:00:00 |   2 |
+----+-----------+---------------------+-------+----+-----------+---------------------+-------+
위의 표 에서 우 리 는 손오공 이 몬스터 를 때 리 기 전 두 명의 수량 이 22 와 12 라 는 것 을 알 고 있다.그러면 a 표 의 모든 필드 에 대해 group by 를 하고 b 표 의 id 에 대해 count 를 해 야 한다.count 값 이 2 보다 적 으 면 요 구 를 만족 시 킬 수 있다.sql 은 다음 과 같이 바 꾸 었 다.

select a.* from user1_kills a join user1_kills b on (a.user_name=b.user_name and a.kills<=b.kills) group by a.id, a.user_name, a.timestr, a.kills having count(b.id) <= 2;
5.피리 칼 적 연관 성 을 사용 하여 일렬 로 여러 줄 돌리 기
예:팀 의 모든 전화 번 호 를 한 줄 로 바 꿉 니 다.
원본 데이터:

+-----------+---------------------------------+
| user_name | mobile             |
+-----------+---------------------------------+
|      | 138245623,021-382349      |
|      | 159384292,022-483432,+86-392432 |
|      | 183208243,055-8234234      |
|      | 293842295,098-2383429      |
| NULL   | 993267899            |
+-----------+---------------------------------+
원 하 는 데이터:

+-----------+-------------+
| user_name | mobile   |
+-----------+-------------+
|      | 138245623  |
|      | 021-382349 |
|      | 159384292  |
|      | 022-483432 |
|      | +86-392432 |
|      | 183208243  |
|      | 055-8234234 |
|      | 293842295  |
|      | 098-2383429 |
| NULL   | 993267899  |
+-----------+-------------+
당승 에 게 전화 가 두 통 있 는 것 을 볼 수 있 기 때문에 그 는 두 줄 이 필요 하 다.우 리 는 먼저 모든 사람의 전화번호 수량 을 구 한 후에 서열 표 한 장과 피리 카드 축적 관 계 를 진행 할 수 있다.편폭 을 절약 하기 위해 당승 의 데이터 만 꺼 낼 수 있다.

select a.id, b.* from tb_sequence a cross join (select user_name, mobile, length(mobile)-length(replace(mobile, ',', ''))+1 size from user1) b order by 2,1;

+----+-----------+---------------------------------+------+
| id | user_name | mobile             | size |
+----+-----------+---------------------------------+------+
| 1 |      | 138245623,021-382349      |  2 |
| 2 |      | 138245623,021-382349      |  2 |
| 3 |      | 138245623,021-382349      |  2 |
| 4 |      | 138245623,021-382349      |  2 |
| 5 |      | 138245623,021-382349      |  2 |
| 6 |      | 138245623,021-382349      |  2 |
| 7 |      | 138245623,021-382349      |  2 |
| 8 |      | 138245623,021-382349      |  2 |
| 9 |      | 138245623,021-382349      |  2 |
| 10 |      | 138245623,021-382349      |  2 |
+----+-----------+---------------------------------+------+
a.id 에 대응 하 는 것 은 바로 몇 번 째 전화번호 입 니 다.size 는 전체 전화번호 수량 이기 때문에 관련 조건(a.id<=b.size)을 추가 하여 위의 sql 을 계속 조정 할 수 있 습 니 다.

select b.user_name, replace(substring(substring_index(b.mobile, ',', a.id), char_length(substring_index(mobile, ',', a.id-1)) + 1), ',', '') as mobile from tb_sequence a cross join (select user_name, concat(mobile, ',') as mobile, length(mobile)-length(replace(mobile, ',', ''))+1 size from user1) b on (a.id <= b.size);
6.피리 칼 적 연관 성 을 사용 하여 다 중 열 전환 다 중 줄
예:취 경 조 의 모든 장 비 를 한 줄 로 변환 합 니 다.
원본 데이터:

+----+-----------+--------------+-----------------+-----------------+
| id | user_name | arms     | clothing    | shoe      |
+----+-----------+--------------+-----------------+-----------------+
| 1 |      |        |         |         |
| 2 |      |        |         |         |
| 3 |      |        |         |         |
| 4 |      |        |         |         |
+----+-----------+--------------+-----------------+-----------------+
원 하 는 데이터:

+-----------+-----------+-----------------+
| user_name | equipment | equip_mame   |
+-----------+-----------+-----------------+
|      | arms   |         |
|      | clothing |         |
|      | shoe   |         |
|      | arms   |         |
|      | clothing |         |
|      | shoe   |         |
|      | arms   |         |
|      | clothing |         |
|      | shoe   |         |
|      | arms   |         |
|      | clothing |         |
|      | shoe   |         |
+-----------+-----------+-----------------+
union 의 표기 법:

select user_name, 'arms' as equipment, arms equip_mame from user1_equipment
union all
select user_name, 'clothing' as equipment, clothing equip_mame from user1_equipment
union all
select user_name, 'shoe' as equipment, shoe equip_mame from user1_equipment
order by 1, 2;
join 의 쓰기:
우선 피리 칼 데이터 세트 의 효 과 를 보면 당승 을 예 로 들 면

select a.*, b.* from user1_equipment a cross join tb_sequence b where b.id <= 3;

+----+-----------+--------------+-----------------+-----------------+----+
| id | user_name | arms     | clothing    | shoe      | id |
+----+-----------+--------------+-----------------+-----------------+----+
| 1 |      |        |         |         | 1 |
| 1 |      |        |         |         | 2 |
| 1 |      |        |         |         | 3 |
+----+-----------+--------------+-----------------+-----------------+----+
케이스 를 사용 하여 위의 결 과 를 처리 합 니 다.

select user_name, 
case when b.id = 1 then 'arms' 
when b.id = 2 then 'clothing'
when b.id = 3 then 'shoe' end as equipment,
case when b.id = 1 then arms end arms,
case when b.id = 2 then clothing end clothing,
case when b.id = 3 then shoe end shoe
from user1_equipment a cross join tb_sequence b where b.id <=3;

+-----------+-----------+--------------+-----------------+-----------------+
| user_name | equipment | arms     | clothing    | shoe      |
+-----------+-----------+--------------+-----------------+-----------------+
|      | arms   |        | NULL      | NULL      |
|      | clothing | NULL     |         | NULL      |
|      | shoe   | NULL     | NULL      |         |
+-----------+-----------+--------------+-----------------+-----------------+
coalesce 함 수 를 사용 하여 다 열 데 이 터 를 통합 합 니 다.

select user_name, 
case when b.id = 1 then 'arms' 
when b.id = 2 then 'clothing'
when b.id = 3 then 'shoe' end as equipment,
coalesce(case when b.id = 1 then arms end,
case when b.id = 2 then clothing end,
case when b.id = 3 then shoe end) equip_mame
from user1_equipment a cross join tb_sequence b where b.id <=3 order by 1, 2;
7.join 을 사용 하여 필터 조건 에 자신 을 포함 하 는 표를 업데이트 합 니 다.
예:취 경 팀 과 오 공 친구 권 에 동시에 존재 하 는 사람 을 취 경 팀 에서 comment 필드 를'이 사람 이 오 공의 친구 권 에 있다'로 업데이트 한다.
우 리 는 자 연 스 럽 게 user 1 과 user 2 중 user 를 먼저 찾 고 싶 습 니 다.name 이 존재 하 는 사람,그리고 user 1 표를 업데이트 합 니 다.sql 은 다음 과 같 습 니 다.

update user1 set comment = '         ' where user_name in (select a.user_name from user1 a join user2 b on (a.user_name = b.user_name));
유 감 스 럽 지만 위의 sql 은 my sql 에서 오 류 를 보 고 했 습 니 다.ERROR 1093(HY 000):You can't specify target table'user 1'for update in FROM clause,목표 표 가 from 자구 에 있 는 표를 업데이트 할 수 없 음 을 알려 줍 니 다.
그럼 다른 방법 은 없 을까요?우 리 는 in 의 쓰기 방법 을 join 의 방식 으로 바 꿀 수 있다.

select c.*, d.* from user1 c join (select a.user_name from user1 a join user2 b on (a.user_name = b.user_name)) d on (c.user_name = d.user_name);

+----+-----------+--------------+---------------------------------+-----------+
| id | user_name | comment | mobile | user_name |
+----+-----------+--------------+---------------------------------+-----------+
| 2 |     |      | 159384292,022-483432,+86-392432 |     |
+----+-----------+--------------+---------------------------------+-----------+
그리고 join 이후 의 보 기 를 업데이트 하면 됩 니 다.

update user1 c join (select a.user_name from user1 a join user2 b on (a.user_name = b.user_name)) d on (c.user_name = d.user_name) set c.comment = '         ';
user 1 을 다시 보면 user 1 이 수정 되 었 음 을 볼 수 있 습 니 다.

select * from user1;

+----+-----------+-----------------------------+---------------------------------+
| id | user_name | comment           | mobile             |
+----+-----------+-----------------------------+---------------------------------+
| 1 |      |               | 138245623,021-382349      |
| 2 |      |               | 159384292,022-483432,+86-392432 |
| 3 |      |               | 183208243,055-8234234      |
| 4 |      |               | 293842295,098-2383429      |
| 5 | NULL   |               | 993267899            |
+----+-----------+-----------------------------+---------------------------------+
8.join 으로 중복 데이터 삭제
우선 user 2 표 에 두 개의 데 이 터 를 삽입 합 니 다.

insert into user2(user_name, comment) values ('   ', '   ');
insert into user2(user_name, comment) values ('   ', '  ');
예:user 2 표 의 중복 데 이 터 를 삭제 하고 id 번호 가 큰 것 만 유지 합 니 다.

+----+--------------+-----------+
| id | user_name  | comment  |
+----+--------------+-----------+
| 1 |        |      |
| 2 |        |      |
| 3 |        |      |
| 4 |        |      |
| 5 | NULL     |      |
| 6 |        |      |
| 7 |        |      |
+----+--------------+-----------+
우선 중복 기록 보기

select a.*, b.* from user2 a join (select user_name, comment, max(id) id from user2 group by user_name, comment having count(*) > 1) b on (a.user_name=b.user_name and a.comment=b.comment) order by 2;

+----+-----------+-----------+-----------+-----------+------+
| id | user_name | comment  | user_name | comment  | id  |
+----+-----------+-----------+-----------+-----------+------+
| 1 |      |      |      |      |  6 |
| 6 |      |      |      |      |  6 |
| 2 |      |      |      |      |  7 |
| 7 |      |      |      |      |  7 |
+----+-----------+-----------+-----------+-----------+------+
이 어(a.id delete a from user2 a join (select user_name, comment, max(id) id from user2 group by user_name, comment having count(*) > 1) b on (a.user_name=b.user_name and a.comment=b.comment) where a.id < b.id;user 2 를 보면 중복 데이터 가 삭제 되 었 음 을 볼 수 있 습 니 다.

select * from user2;

+----+--------------+-----------+
| id | user_name  | comment  |
+----+--------------+-----------+
| 3 |        |      |
| 4 |        |      |
| 5 | NULL     |      |
| 6 |        |      |
| 7 |        |      |
+----+--------------+-----------+
요약:
여기까지 소개 하 겠 습 니 다.여러분 이 관심 이 있 으 면 데 이 터 를 많이 만 든 다음 에 서로 다른 sql 쓰기 가 실행 시간 에서 의 차 이 를 비교 할 수 있 습 니 다.본 논문 의 예 는 모 과 망 에서 따 온 것 이다.
자,이상 이 이 글 의 모든 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.여러분 의 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기