Azure SQL cross-database queries returns too many rows with joins
Recreating the issue

Test data below

SELECT o.OrderId, c.CustomerID, c.CustomerName
FROM OrderInformation o
JOIN CustomerInformation c ON o.CustomerID = c.CustomerID
WHERE o.OrderId = 155;




All records are returned by the remote query operator, to filter down to one when the inner join is applied.



Some more background on pushing down the predicate to a remote database:


  Previously, elastic database query could not push parameterized
  operations to remote databases. As a result, sometimes large row sets
  had to be unnecessarily brought local to evaluate these operations.
  With the recent improvements, parameterized operations can now be
  pushed to remote databases and be evaluated remotely. For a query over
  an external table and a local table like the following, this can now
  avoid transferring millions of rows by evaluating the selective filter
  in the WHERE clause on the remote database:


DECLARE @low int
DECLARE @high int
SET @low = 100
SET @high = 200

SELECT c.CustomerId, c.Name, count(OrderId) 
FROM remote_customers c
JOIN local_orders o
ON c.CustomerId = o.CustomerId 
WHERE c.CustomerId &gt; @low and c.CustomerId &lt; @high
GROUP BY c.CustomerId, c.Name;


Source

Above query shows an example of using parameters to define a range from where to read the data. The difference with your problem is that the filtering is happening on the local table.



If we know that this predicate can be pushed down to the remote table

SELECT o.OrderId,c.CustomerID, c.CustomerName
FROM CustomerInformation c 
JOIN OrderInformation o on o.CustomerId = c.CustomerID
WHERE o.customerID &gt; 1 and o.Customerid &lt; 10;




You could look for a range of customerid's and filter on these

MAX() and MIN() functions on o.Customerid are  used to get the upper and lower boundaries for WHERE o.OrderId = 155

DECLARE @MAX INT, @MIN INT;

SELECT @MAX= max(o.Customerid) , @MIN = MIN(o.Customerid)
FROM OrderInformation o 
WHERE o.OrderId = 155;

SELECT o.OrderId,c.CustomerID, c.CustomerName
FROM CustomerInformation c 
WHERE c.customerID &gt;= @MIN and c.Customerid &lt;= @MAX;




The complete result

 DECLARE @MAX INT, @MIN INT;

 SELECT @MAX= max(o.Customerid) , @MIN = MIN(o.Customerid)
 FROM
 OrderInformation o 
 WHERE o.OrderId = 155;

 ;WITH CTE as(
 SELECT c.CustomerID, c.CustomerName
 FROM CustomerInformation c 
 WHERE c.customerID &gt;= @MIN 
 AND c.Customerid &lt;= @MAX
 )

 SELECT o.OrderId, c.CustomerID, c.CustomerName
 FROM CTE c
 INNER JOIN  OrderInformation o
 on o.customerID = c.CustomerID
 where o.Orderid = 155;


Pushing down the predicates:



Execution plan of this query

RemoteQuery="SELECT [c].[CustomerID] [Col1005],[c].[CustomerName] [Col1007] FROM [CustomerInformation] [c] WHERE [c].[CustomerID]&amp;gt;=? AND [c].[CustomerID]&amp;lt;=?"


It depends on your data &amp; parameters passed how much this could filter out on the remote table. YMMV



Test data

Customerinformation (remote db)

CREATE TABLE dbo.CustomerInformation (CustomerID int identity(1,1) , CustomerName nvarchar(255));

DECLARE @i int = 1;
WHILE @i &lt; 20000
BEGIN
INSERT INTO CustomerInformation(CustomerName)
VALUES ('Frodo');

SET @i += 1;
END


On the database that will use the external table

CREATE TABLE OrderInformation(OrderId Int identity(1,1), CustomerId int,Ordervalue int);


SET NOCOUNT ON;
DECLARE @i int = 1;
WHILE @i &lt; 200 
BEGIN
INSERT INTO OrderInformation(CustomerId,Ordervalue)
Values (@I,111);

set @i += 1;
END

CREATE EXTERNAL TABLE  [dbo].CustomerInformation(
    CustomerID [int],
CustomerName nvarchar(255))
    WITH  
(  
    DATA_SOURCE = Stackoverflow  
);