Much of the data stored within New Relic relates to other data: Transaction and TransactionError, PageView and PageAction, Log and infrastructure events, and more. You can perform analysis and calculate correlations between these events using subquery joins.
How to write a subquery join
A subquery is a query that is nested inside another query. With subquery joins, you can combine the result of a subquery with the result of its outer query based on a key, allowing for analysis and enrichment across datasets.
A subquery join requires three components: two datasets and a primary key to link the two together.
FROM Event [INNER|LEFT] JOIN (subquery) ON [key =] key SELECT ...Subquery joins contain simple rules to the syntax:
- The
JOINclause must always follow immediately after theFROMclause. - You can prefix the
JOINwith the join type.INNERorLEFTis optional, and defaults toINNERwhen omitted. - Parentheses containing a subquery must immediately follow the
JOINclause. - The
ONclause must immediately follow the subquery and has two forms (more details below).
You can have multiple JOIN clauses in one query, too. For example, this query uses two JOINs within subqueries:
FROM JavaScriptError JOIN ( FROM PageAction JOIN ( FROM PageView SELECT count(*) FACET session AS pageViewSession, city LIMIT MAX ) ON session = pageViewSession SELECT count(*) FACET city, currentUrl, session AS pageActionSession ) ON session = pageActionSessionSELECT count(*) FACET city, currentUrl, session, errorClassThe image below contains two datasets: the average CPU percentage of infrastructure containers (ProcessSample) and the average duration of app transactions by container.

Often, data from different sources is correlated. In this case, you can determine if a container's higher CPU usage is causing slower transactions by using the following subquery join:
FROM Transaction JOIN (FROM ProcessSample SELECT average(cpuPercent) AS cpu FACET containerId LIMIT MAX) ON containerIdSELECT average(duration)/latest(cpu) FACET containerId, containerName
With this query, you can see the containers that have a higher average transaction duration given their CPU usage, and investigate outliers to see if there is a bug to fix or optimizations to be made.
Subquery join limitations
Subquery joins have the following limitations:
- The joined subquery will continue to have a default
LIMITof 10, with a maximumLIMITof 5,000. Note that the outer query'sLIMITdoes not affect the inner query. - The use of
TIMESERIESin the joined subquery is not supported. If your outer query usesTIMESERIES, keep in mind that the joined subquery will provide a single result for the full query timespan. - The use of
COMPARE WITHin the joined subquery is not supported. If your outer query usesCOMPARE WITH, keep in mind that the joined subquery will provide a single result based on the queries base timespan, and will not provide a separate value for the outer queries compare with timespan. - Like all subqueries, joined subqueries cannot be used in alert conditions.
- While
SELECT *is supported in the parent query, it is not supported in the joined subquery. - The cardinality of the join is limited to 1:100, meaning a single join key cannot map to more than one hundred rows in the subquery result.
- The
ONclause only supports equality conditions. - The
JOINkey cannot be a complex attribute, like a metric value. - We do no coercion of attribute types in the
JOINcondition. The left side of theJOIN'sONcondition needs to be the same type as the right side of theONcondition. - Metric wildcards are not supported in the
JOIN'sONcondition - The subquery cannot be a metric row-wise query.
- The right-hand side of the
JOIN'sONcondition must be an identifier projected by the query. It cannot use a function or mathematical operation. - The joined subquery cannot project a
uniques()result.
Subquery join examples
Here are some example subquery joins:



