You are missing the feature of partition pruning that is crutial for large partitioned tables. Check the concepts in the documentation first.
To demonstrate the partition pruning the following setup will be used
create table TABLE1 
   PARTITION BY RANGE (EFF_DATE)
   INTERVAL(NUMTODSINTERVAL(1, 'DAY'))
( 
   PARTITION p_init VALUES LESS THAN (TO_DATE('01-01-2019', 'DD-MM-YYYY'))
)
as
select rownum tb_id, 
       date'2019-01-01' + (rownum -1) as EFF_DATE
from dual connect by level <= 365;
The table is interval partitioned with one day partitions on the column EFF_DATE. The TABLE2 is created identically.
Now let's look on the execution plan of your query, referencing the tables and not the partitions:
SELECT
    TB1.TB_ID,
    TB1.EFF_DATE
FROM TABLE1 TB1, TABLE2 TB2
WHERE
    TB1.EFF_DATE >= TO_DATE(:p_req_date, 'yyyymmdd')
AND 
    TB1.EFF_DATE < TO_DATE(:p_req_date, 'yyyymmdd') + 1
AND
    TB1.TB_ID = TB2.TB_ID;
See here how to produce the following execution plan.
Plan hash value: 3726328978
-----------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name   | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |        |     2 |    32 |  3724   (1)| 00:00:01 |       |       |
|*  1 |  FILTER                    |        |       |       |            |          |       |       |
|*  2 |   HASH JOIN                |        |     2 |    32 |  3724   (1)| 00:00:01 |       |       |
|   3 |    PARTITION RANGE ITERATOR|        |     2 |    24 |  1849   (1)| 00:00:01 |   KEY |   KEY |
|*  4 |     TABLE ACCESS FULL      | TABLE1 |     2 |    24 |  1849   (1)| 00:00:01 |   KEY |   KEY |
|   5 |    PARTITION RANGE ALL     |        |   365 |  1460 |  1874   (1)| 00:00:01 |     1 |1048575|
|   6 |     TABLE ACCESS FULL      | TABLE2 |   365 |  1460 |  1874   (1)| 00:00:01 |     1 |1048575|
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(TO_DATE(:P_REQ_DATE,'yyyymmdd')+1>TO_DATE(:P_REQ_DATE,'yyyymmdd'))
   2 - access("TB1"."TB_ID"="TB2"."TB_ID")
   4 - filter("TB1"."EFF_DATE"<TO_DATE(:P_REQ_DATE,'yyyymmdd')+1 AND 
              "TB1"."EFF_DATE">=TO_DATE(:P_REQ_DATE,'yyyymmdd'))
The relevant part is in the columns Pstart and Pstop. You see that in the TABLE1 only one partition is accessed. KEY - KEY  means that the partition is not fixed (you used bind variables), but only data from one partition will be scanned.
The problem is on table TABLE2 which is accessed fully (all partitions).
Why?
Oracle does not know that the rows with the same ID in both tables have the same effective date. 
This is exect what you want to teach Oracle by passing the identical partition names in the join.
Much better way is to do in the WHERE clause by adding the predicate on EFF_DATE for the TABLE2
SELECT
    TB1.TB_ID,
    TB1.EFF_DATE
FROM TABLE1 TB1, TABLE2 TB2
WHERE
    TB1.EFF_DATE >= TO_DATE(:p_req_date, 'yyyymmdd')
AND 
    TB1.EFF_DATE < TO_DATE(:p_req_date, 'yyyymmdd') + 1
AND
    TB1.TB_ID = TB2.TB_ID
AND 
    TB2.EFF_DATE >= TO_DATE(:p_req_date, 'yyyymmdd')  /* filter for EFF_DATE in TABLE2 added */
AND 
    TB2.EFF_DATE < TO_DATE(:p_req_date, 'yyyymmdd') + 1;
Now Oracle knows that in both tables only one  partition should be accessed.
-----------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name   | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |        |     2 |    48 |  3724   (1)| 00:00:01 |       |       |
|*  1 |  FILTER                    |        |       |       |            |          |       |       |
|*  2 |   HASH JOIN                |        |     2 |    48 |  3724   (1)| 00:00:01 |       |       |
|   3 |    PARTITION RANGE ITERATOR|        |     2 |    24 |  1849   (1)| 00:00:01 |   KEY |   KEY |
|*  4 |     TABLE ACCESS FULL      | TABLE1 |     2 |    24 |  1849   (1)| 00:00:01 |   KEY |   KEY |
|   5 |    PARTITION RANGE ITERATOR|        |     2 |    24 |  1874   (1)| 00:00:01 |   KEY |   KEY |
|*  6 |     TABLE ACCESS FULL      | TABLE2 |     2 |    24 |  1874   (1)| 00:00:01 |   KEY |   KEY |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(TO_DATE(:P_REQ_DATE,'yyyymmdd')+1>TO_DATE(:P_REQ_DATE,'yyyymmdd'))
   2 - access("TB1"."TB_ID"="TB2"."TB_ID")
   4 - filter("TB1"."EFF_DATE"<TO_DATE(:P_REQ_DATE,'yyyymmdd')+1 AND 
              "TB1"."EFF_DATE">=TO_DATE(:P_REQ_DATE,'yyyymmdd'))
   6 - filter("TB2"."EFF_DATE"<TO_DATE(:P_REQ_DATE,'yyyymmdd')+1 AND 
              "TB2"."EFF_DATE">=TO_DATE(:P_REQ_DATE,'yyyymmdd'))
So you solved your task without a need of dynamic SQL, which is always the prefered way to go.