Q: SQL script runs VERY slowly with small change I am relatively new to SQL.  I have a script that used to run very quickly (<0.5 seconds) but runs very slowly (>120 seconds) if I add one change - and I can't see why this change makes such a difference.  Any help would be hugely appreciated!
This is the script and it runs quickly if I do NOT include "tt2.bulk_cnt
" in line 26:
with bulksum1 as
(
select  t1.membercode,
        t1.schemecode,
        t1.transdate
from mina_raw2 t1
where t1.transactiontype in ('RSP','SP','UNTV','ASTR','CN','TVIN','UCON','TRAS')
group by  t1.membercode,
          t1.schemecode,
          t1.transdate
),

bulksum2 as
(
select  t1.schemecode,
        t1.transdate,
        count(*) as bulk_cnt
from bulksum1 t1
group by  t1.schemecode,
          t1.transdate
having count(*) >= 10
),

results as
(
select t1.*, tt2.bulk_cnt
from mina_raw2 t1
inner join bulksum2 tt2
on t1.schemecode = tt2.schemecode and t1.transdate = tt2.transdate
where t1.transactiontype in ('RSP','SP','UNTV','ASTR','CN','TVIN','UCON','TRAS')
)

select * from results

EDIT:  I apologise for not putting enough detail in here previously - although I can use basic SQL code, I am a complete novice when it comes to databases.
Database: Oracle (I'm not sure which version, sorry)
Execution plans:
QUICK query:
Plan hash value: 1712123489

---------------------------------------------
| Id  | Operation               | Name      |
---------------------------------------------
|   0 | SELECT STATEMENT        |           |
|   1 |  HASH JOIN              |           |
|   2 |   VIEW                  |           |
|   3 |    FILTER               |           |
|   4 |     HASH GROUP BY       |           |
|   5 |      VIEW               | VM_NWVW_0 |
|   6 |       HASH GROUP BY     |           |
|   7 |        TABLE ACCESS FULL| MINA_RAW2 |
|   8 |   TABLE ACCESS FULL     | MINA_RAW2 |
---------------------------------------------

SLOW query:
Plan hash value: 1298175315

--------------------------------------------
| Id  | Operation              | Name      |
--------------------------------------------
|   0 | SELECT STATEMENT       |           |
|   1 |  FILTER                |           |
|   2 |   HASH GROUP BY        |           |
|   3 |    HASH JOIN           |           |
|   4 |     VIEW               | VM_NWVW_0 |
|   5 |      HASH GROUP BY     |           |
|   6 |       TABLE ACCESS FULL| MINA_RAW2 |
|   7 |     TABLE ACCESS FULL  | MINA_RAW2 |
--------------------------------------------


A: I managed to remove an unnecessary subquery, but this syntax with distinct inside count may not work outside of PostgreSQL or may not be the desired result. I know I've certainly used it there.
select t1.*, tt2.bulk_cnt
from mina_raw2 t1
inner join (select  t2.schemecode,
        t2.transdate,
        count(DISTINCT membercode) as bulk_cnt
from mina_raw2 t2
where t2.transactiontype in ('RSP','SP','UNTV','ASTR','CN','TVIN','UCON','TRAS')
group by  t2.schemecode,
          t2.transdate
having count(DISTINCT membercode) >= 10) tt2
on t1.schemecode = tt2.schemecode and t1.transdate = tt2.transdate
where t1.transactiontype in ('RSP','SP','UNTV','ASTR','CN','TVIN','UCON','TRAS')

When you use those with queries, instead of subqueries when you don't need to, you're kneecapping the query optimizer.

A: A few observations, and then some things to do:
1) More information is needed. In particular, how many rows are there in the MINA_RAW2 table, what indexes exist on this table, and when was the last time it was analyzed? To determine the answers to these questions, run:
SELECT COUNT(*) FROM MINA_RAW2;

SELECT TABLE_NAME, LAST_ANALYZED, NUM_ROWS
  FROM USER_TABLES
  WHERE TABLE_NAME = 'MINA_RAW2';

From looking at the plan output it looks like the database is doing two FULL SCANs on MINA_RAW2 - it would be nice if this could be reduced to no more than one, and hopefully none. It's always tough to tell without very detailed information about the data in the table, but at first blush it appears that an index on TRANSACTIONTYPE might be helpful. If such an index doesn't exist you might want to consider adding it.
2) Assuming that the statistics are out-of-date (as in, old, nonexistent, or a significant amount of data (> 10%) has been added, deleted, or updated since the last analysis) run the following:
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(owner => 'YOUR-SCHEMA-NAME',
                                table_name => 'MINA_RAW2');
END;

substituting the correct schema name for "YOUR-SCHEMA-NAME" above. Remember to capitalize the schema name! If you don't know if you should or shouldn't gather statistics, err on the side of caution and do it. It shouldn't take much time.
3) Re-try your existing query after updating the table statistics. I think there's a fair chance that having up-to-date statistics in the database will solve your issues. If not:
4) This query is doing a GROUP BY on the results of a GROUP BY. This doesn't appear to be necessary as the initial GROUP BY doesn't do any grouping - instead, it appears this is being done to get the unique combinations of MEMBERCODE, SCHEMECODE, and TRANSDATE so that the count of the members by scheme and date can be determined. I think the whole query can be simplified to:
WITH cteWORKING_TRANS AS (SELECT *
                            FROM MINA_RAW2
                            WHERE TRANSACTIONTYPE IN ('RSP','SP','UNTV',
                                                      'ASTR','CN','TVIN',
                                                      'UCON','TRAS')),
     cteBULKSUM AS (SELECT a.SCHEMECODE,
                           a.TRANSDATE,
                           COUNT(*) AS BULK_CNT
                      FROM (SELECT DISTINCT MEMBERCODE,
                                            SCHEMECODE,
                                            TRANSDATE
                              FROM cteWORKING_TRANS) a
                      GROUP BY a.SCHEMECODE,
                               a.TRANSDATE)
SELECT t.*, b.BULK_CNT
  FROM cteWORKING_TRANS t
  INNER JOIN cteBULKSUM b
    ON b.SCHEMECODE = t.SCHEMECODE AND
       b.TRANSDATE = t.TRANSDATE

