2016-09-21 4 views
0

Oracle을 사용 중이며 모든 인덱스가 삽입됩니다.카운트 쿼리의 SQL 성능

내 테이블은 다음과 같습니다 :

CREATE TABLE users 
(user_id number(10) NOT NULL, 
    name varchar2(50) NOT NULL, 
    type_id number(10) NOT NULL, 
    is_deleted varchar2(1) NOT NULL 
); 

INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (1,'John',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (2,'Mark',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (3,'Leon',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (4,'David',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (5,'Mike',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (6,'Sam',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (100,'Nike',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (200,'Adidas',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (300,'Reebook',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (400,'Puma',0,'F'); 
INSERT INTO users (user_id, name, type_id, is_deleted) VALUES (500,'Kinetix',0,'F'); 

CREATE TABLE ROLE 
(role_id number(10) NOT NULL, 
    role_name varchar2(50) NOT NULL 
); 

INSERT INTO ROLE (role_id, role_name) VALUES (10, 'User'); 
INSERT INTO ROLE (role_id, role_name) VALUES (11, 'Company'); 

CREATE TABLE ROLE_REL 
(id number(10) NOT NULL, 
    user_id number(10) NOT NULL, 
    role_id number(10) NOT NULL 
); 

INSERT INTO role_rel (id,user_id,role_id) VALUES (1,1, 10); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (2,2, 10); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (3,3, 10); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (4,4, 10); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (5,5, 10); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (6,6, 10); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (7,100, 11); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (8,200, 11); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (9,300, 11); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (10,400, 11); 
INSERT INTO role_rel (id,user_id,role_id) VALUES (11,500, 11); 

CREATE TABLE COMPANY_USER 
(id number(10) NOT NULL, 
    user_id number(10) NOT NULL, 
    company_id number(10) NOT NULL, 
    is_deleted varchar2(1) NOT NULL 
); 

INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (1,1,100,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (2,1,200,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (3,1,300,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (4,3,400,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (5,1,500,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (6,2,100,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (7,3,100,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (8,4,100,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (9,4,200,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (10,5,100,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (11,6,100,'F'); 
INSERT INTO company_user(id,user_id,company_id,is_deleted) VALUES (12,6,200,'F'); 

CREATE TABLE CITY 
(id number(10) NOT NULL, 
    city_name varchar2(50) NOT NULL 
); 

INSERT INTO city(id,city_name) VALUES (1,'New York'); 
INSERT INTO city(id,city_name) VALUES (2,'Sacramento'); 
INSERT INTO city(id,city_name) VALUES (3,'Washington'); 
INSERT INTO city(id,city_name) VALUES (4,'New Jersey'); 
INSERT INTO city(id,city_name) VALUES (5,'Toronto'); 

CREATE TABLE CITY_USER 
(id number(10) NOT NULL, 
    user_id number(10) NOT NULL, 
    city_id number(10) NOT NULL, 
    is_deleted varchar2(1) NOT NULL 
); 

INSERT INTO CITY_USER(id,user_id,city_id,is_deleted) VALUES (1,1,3,'F'); 
INSERT INTO CITY_USER(id,user_id,city_id,is_deleted) VALUES (2,2,4,'F'); 
INSERT INTO CITY_USER(id,user_id,city_id,is_deleted) VALUES (3,3,4,'F'); 
INSERT INTO CITY_USER(id,user_id,city_id,is_deleted) VALUES (4,4,1,'F'); 
INSERT INTO CITY_USER(id,user_id,city_id,is_deleted) VALUES (5,5,1,'F'); 
INSERT INTO CITY_USER(id,user_id,city_id,is_deleted) VALUES (6,6,2,'F'); 
INSERT INTO CITY_USER(id,user_id,city_id,is_deleted) VALUES (7,1,1,'F'); 

CREATE TABLE BRANCH 
(id number(10) NOT NULL, 
    branch_name varchar2(50) NOT NULL 
); 

INSERT INTO branch(id,branch_name) VALUES (1,'Black'); 
INSERT INTO branch(id,branch_name) VALUES (2,'White'); 
INSERT INTO branch(id,branch_name) VALUES (3,'Blue'); 
INSERT INTO branch(id,branch_name) VALUES (4,'Yellow'); 
INSERT INTO branch(id,branch_name) VALUES (5,'Orange'); 

CREATE TABLE BRANCH_USER(
id number(10) NOT NULL, 
user_id number(10) NOT NULL, 
branch_id number(10) NOT NULL, 
is_deleted varchar2(1) NOT NULL 
); 

INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (1,1,5,'F'); 
INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (2,2,1,'F'); 
INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (3,3,1,'F'); 
INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (4,4,2,'F'); 
INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (5,5,3,'F'); 
INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (6,6,3,'F'); 
INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (7,1,1,'F'); 
INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (8,2,3,'F'); 
INSERT INTO BRANCH_USER(id,user_id,branch_id,is_deleted) VALUES (9,1,3,'F'); 

아래의 내 쿼리입니다.

SELECT count(CU.company_ID) as TypeID, CU.Company_ID, C.Name 
FROM Company_User CU 
INNER JOIN USERS C 
on CU.Company_ID = c.user_ID 
INNER JOIN (SELECT Distinct U.user_ID 
    FROM users U 
    INNER JOIN Role_Rel RR 
    on RR.user_ID = U.user_ID 
    WHERE U.is_deleted = 'F' 
    and RR.Role_ID = 10) U 
on CU.User_ID = U.user_ID 
INNER JOIN (SELECT Distinct PU.user_ID 
    FROM users PU 
    INNER JOIN city_user SUL 
    on SUL.user_ID = PU.user_ID 
    WHERE sul.city_id = 1 and PU.is_deleted = 'F') PU 
    on CU.User_ID = PU.user_ID 
INNER JOIN (SELECT Distinct KU.user_ID 
    FROM users KU 
    INNER JOIN branch_user hd 
    on hd.user_ID = KU.user_ID 
    WHERE hd.branch_id = 3 and KU.is_deleted = 'F' and hd.is_deleted = 'F') KU 
    on CU.User_ID = KU.user_ID 
GROUP BY CU.Company_Id, C.Name 
ORDER BY count(CU.Company_ID) Desc; 

내 결과는 원하는대로 회사가 사용자 수로 표시됩니다.

TypeID Company_id  Name 
6   100   Nike 
3   200   Adidas 
2   400   Puma 
1   300   Reebok. 

내 결과

TYPEID COMPANY_ID NAME 
2  100   Nike 
1  500   Kinetix 
1  200   Adidas 
1  300   Reebook 

SQL-FIDDLE is here.

저는 @xQbert 대답에 따라 제 질문을 편집했으며 branch_user 및 city_user 테이블에 따라 쿼리에 두 가지 새로운 제한 사항을 추가했습니다. 더 나은 수행을 위해 내 질문을 어떻게 수정할 수 있습니까?

필요한 모든 색인이 추가된다고 상상해보십시오. 나는 새로운 질의 또는 질의에 있어야하는 새로운 색인이 필요하다. 질의는 내 문제를 해결하여 쿼리를보다 최적화되도록하고 싶습니다.

미리 감사드립니다.

+2

어떤 DBMS를 사용하고 있습니까? –

+0

Oracle을 사용하고 있습니다. 지금 내 질문을 편집 할 것입니다. –

+0

테이블 및 인덱스 정의 등 추가 실행 계획/설명? – jarlh

답변

2

인덱스가 없으면 실행 계획과 테이블 통계가 향상되지 않아 평가할 정보가 필요하지 않습니다. 간단히 말해, 질문에는 분석 또는 정보가 부족하여 적용 할 개선 사항을 알 수 없습니다. 나는 아마이 방법을 쓴 것

... 그것은 비록 빨리 나 더 나은 실행 계획의 결과 경우

말할 수 없습니다.

SELECT count(CU.company_ID) as TypeID, CU.Company_ID, C.Name 
FROM Company_User CU 
INNER JOIN Company C 
on CU.Company_ID = c.Company_ID 
INNER JOIN (SELECT Distinct U.user_ID 
      FROM users U 
      INNER JOIN Role_Rel RR 
       on RR.user_ID = U.user_ID 
      WHERE U.deleted = 'F' 
       and RR.Role_ID = 10) U 
on CU.User_ID = U.user_ID 
GROUP BY CU.Company_Id, C.Name 
ORDER BY count(CU.Company_ID) Desc; 
+0

열리스트의'select'는 성능상의 큰 문제였습니다.이 대답은 수정되었습니다. – Allan

+1

동의하지만 작은 데이터 세트에서는 성능 차이가별로 없을 것이라고 생각합니다. 이를 제거함으로써 select의 반복적 인 호출을 제거하여 각 이름을 파생시키고 데이터베이스가 여러 select 문 대신 단일 조인을 허용하는 집합 기반 연산에서 작동하도록합니다. – xQbert

+0

@xQbert 나는 company와 users 테이블을 결합하고이 새로운 변경에 따라 어떻게 쿼리를 재 표기 할 수 있는지 역할 테이블에 새로운 역할을 넣었습니까? –

0

고유 한 사용자 수를 원하는 회사를 원하십니까? 그런 다음 사용자를 선택하고 사용자 수에 참여하십시오.

select 
    c.company_id, 
    c.companyname, 
    cu.users 
from company c 
join 
(
    select company_id, count(distinct user_id) as users 
    from company_user 
    where user_id in (select user_id from role_rel where role_id = 10) 
    and user_id in (select user_id from users where deleted = 'F') 
    group by company_id 
) cu on cu.company_id = c.company_id 
order by cu.users desc; 

좋아, 더 이상 어떤 회사 테이블 ...

select 
    c.user_id as company_id, 
    c.name as companyname, 
    cu.users 
from 
(
    select * 
    from users 
    where user_id in (select user_id from role_rel where role_id = 11) 
    and deleteted = 'F' 
) c 
join 
(
    select company_id, count(distinct user_id) as users 
    from company_user 
    where user_id in 
    (
    select user_id 
    from users 
    where user_id in (select user_id from role_rel where role_id = 10) 
    and deleteted = 'F' 
) 
    group by company_id 
) cu on cu.company_id = c.company_id 
order by cu.users desc; 
만약 당신이 좋아하면 당신은 절 대신 직접 파생 된 테이블로 사용할 수 있습니다

더 나은 그 :

with company_data as 
(
    select * 
    from users 
    where user_id in (select user_id from role_rel where role_id = 11) 
    and deleteted = 'F' 
) 
, user_data as 
(
    select * 
    from users 
    where user_id in (select user_id from role_rel where role_id = 10) 
    and deleteted = 'F' 
) 
... 
0

하위 쿼리를 사용하여이 버전을 사용해보세요 :

SELECT 
    count(DISTINCT user_id) AS type_id, 
    company_id AS id, 
    (
    SELECT name 
    FROM users 
    WHERE user_id = com_user.company_id 
) AS name 
FROM company_user com_user 
WHERE 1=1 
    -- check that "user_id" is associated 
    -- with role named "User" and this user 
    -- was not deleted 
    AND user_id IN 
    (
    SELECT user_id 
    FROM users 
    WHERE 1=1 
     AND deleted = 'F' 
     AND user_id IN 
     (
     SELECT user_id 
     FROM role_rel 
     WHERE role_id IN (SELECT id FROM role WHERE roleName = 'User') 
    ) 
) 
    -- check that "company_id" is associated 
    -- with role named "Company" and this user 
    -- was not deleted 
    AND company_id IN 
    (
    SELECT user_id 
    FROM users 
    WHERE 1=1 
     AND deleted = 'F' 
     AND user_id IN 
     (
     SELECT user_id 
     FROM role_rel 
     WHERE role_id IN (SELECT id FROM role WHERE roleName = 'Company') 
    ) 
) 
GROUP BY company_id 
ORDER BY count(company_id) DESC 
; 

하위 쿼리를 사용하여 name 열을 검색하는 것이 좋지 않지만이 쿼리가 제대로 작동하지 않으면 나중에 변경하려고합니다.