2016-09-21 3 views
0

Я использую Oracle и все индексы вставлены.SQL Performance on count query

Мои таблицы ниже:

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

Какая СУБД вы используете? –

+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

«Выбор» в списке столбцов был большой потенциальной проблемой производительности, которую этот ответ исправляет. – Allan

+1

Согласен, но на небольшом наборе данных я не думаю, что мы увидим большую разницу в производительности. Удалив его, мы в основном исключаем итеративный вызов select для получения каждого имени и позволяем базе данных работать в операциях на основе набора, что позволяет использовать одно соединение вместо нескольких операторов select. – xQbert

+0

@xQbert У меня есть объединенная таблица компаний и пользователей и добавлена ​​новая роль в таблице ролей, как ваш запрос может быть переписан в соответствии с этим новым изменением? –

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 с использованием подзапроса, но я попытаюсь изменить его позже, если этот запрос не подходит для вас.