optimise join query with group by SUM
I'm answering from a SQL Server perspective; however, something similar should work in most environments.

/* SET-UP  */

CREATE TABLE #inv (id INT IDENTITY(1,1), refno varchar(20), inv_amt money);
INSERT INTO #inv (refno, inv_amt)
VALUES ('inv001', 100)
      ,('inv001', 30)
      ,('inv002', 150)
      ,('inv003', 50)
;

CREATE TABLE #pay (id INT IDENTITY(1,1), refno varchar(20), pay_amt money);
INSERT INTO #pay (refno, pay_amt)
VALUES ('inv001', 130)
      ,('inv002', 30)
      ,('inv002', 50)
      ,('inv002', 50)
      ,('inv002', 20)
      ,('inv003', 20)
;


/* ANSWER */

CREATE TABLE #inv_total (refno varchar(20) PRIMARY KEY, inv_amt money);
CREATE TABLE #pay_total (refno varchar(20) PRIMARY KEY, pay_amt money);

INSERT INTO #inv_total
SELECT refno, SUM(inv_amt) FROM #inv GROUP BY refno;

INSERT INTO #pay_total
SELECT refno, SUM(pay_amt) from #pay GROUP BY refno;

SELECT COALESCE(i.refno, p.refno) as refno
      ,COALESCE(i.inv_amt, 0) as inv_amt
      ,COALESCE(p.pay_amt, 0) as pay_amt
  FROM #inv_total i
         FULL OUTER JOIN #pay_total p ON (i.refno = p.refno)
 WHERE COALESCE(i.inv_amt, 0) &lt;&gt; COALESCE(p.pay_amt, 0)
;


Executed on SQL Server 2008R2, this does indeed only bring back inv003.

NOTE: Depending on what version of SQL you're working in, you may be able to use the queries that populate the two _total temporary tables as sub-queries in the final query.

If you do need the temp tables, setting refno as a primary key isn't required; however, for very large amounts of data, it might speed up the final query.

ALSO: In my test data, I assumed that the two payment rows with the same id value was a typo. However, it's not relevant to the solution as far as I can tell, so if it was deliberate, change the set-up to not make the id column an IDENTITY column, and to explicitly populate that column in the INSERT statements.