计数查询的SQL性能

时间:2016-09-21 12:42:36

标签: sql oracle

我正在使用Oracle并且插入了所有索引。

我的表格如下:

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表在查询中添加了两个新限制。如何修改我的问题以更好地执行?

想象一下,添加了所有需要的索引。我对新查询或应该在查询中需要的新索引持开放态度。查询解决了我的问题,我想让我的查询更加优化。

提前致谢。

3 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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子句而不是直接派生表:

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'
)
...

答案 2 :(得分: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,但如果此查询对您不适合,我会尝试稍后更改它。