Execution plan of on-premises sql server and Azure sql server is not the same
If the plan is the same (which it looks to be), and the query speeds up when you bump up to more DTUs, it's likely you're simply being limited by the Azure tier you're on.
You can confirm this by looking in the execution plan at the wait stats - if you're being CPU-capped by your Azure tier, there will be RESOURCE_GOVERNOR_IDLE waits (and related SOS_SCHEDULER_YIELD waits as well).
I've blogged about this here: RESOURCE_GOVERNOR_IDLE in Azure
Looking at the Azure plan you provided:
&lt;WaitStats&gt;
  &lt;Wait WaitType=&quot;SOS_SCHEDULER_YIELD&quot; WaitTimeMs=&quot;597&quot; WaitCount=&quot;686&quot; /&gt;
  &lt;Wait WaitType=&quot;RESOURCE_GOVERNOR_IDLE&quot; WaitTimeMs=&quot;570&quot; WaitCount=&quot;77&quot; /&gt;
&lt;/WaitStats&gt;
&lt;QueryTimeStats CpuTime=&quot;2756&quot; ElapsedTime=&quot;3351&quot; /&gt;

The difference between elapsed and CPU time is 595 - which is almost exactly the amount of RESOURCE_GOVERNOR_IDLE waits that were incurred.  Without those waits, the query would have finished in 2.7 seconds in theory, which is still slower than the 1.1 seconds it took the SQL Server 2014 query.
The main solutions are to either increase the service tier, or change the query / indexes so it uses less CPU.
My guess would be that the other hosting provider machine has a faster clock speed on the CPU, as well as not being limited by the resource governor.
To be clear though, you're client may not be considering the manageability &quot;wins&quot; with Azure, even at a more expensive / higher tier.  You'll get many advantages (including high availability, automated backups, automated tuning, all the latest database engine and security patches, and not having to deal with SQL Server instance level or VM maintenance) that are included in the slightly higher cost.

For this specific query, you might try creating an indexed view of this data if it is needed frequently, to &quot;pre-calculate&quot; this distinct list of user groups that have placed orders.  Then the query would only need to read the 20 rows from that view, which would be less likely to be impacted by the service tier.
Note that you would have to use GROUP BY instead of DISTINCT in the view definition due to the limitations on indexed views.