NVL: No matter if the first argument is NULL or not, NVL will always evaluate both arguments. This can cause unnecessary computation if the second argument is heavy
SELECT SUM(total)
FROM (
SELECT NVL(5, LENGTH(RAWTOHEX(SYS_GUID()))) AS total
FROM dual
CONNECT BY level <= 10000
)
In this case, the first argument is 5, which is non-NULL. However, this means NVL will try to evaluate the second one as well, which is, in this case, a rather heavy-weight operation (LENGTH of RAWTOHEX of SYS_GUID()). The execution can take up to 0.5 seconds because it generates the SYS_GUID() for each row, which in normal situations might not be necessary. When some of the NVL arguments are NULL, they do not generate unnecessary computations, which is a correct decision from an optimization perspective.
COALESCE: On the other hand, COALESCE will stop evaluations immediately once it sees the first non-null argument. Such techniques of lazy evaluation can provide much better performance. For example:
SELECT SUM(total)
FROM (
SELECT COALESCE(5, LENGTH(RAWTOHEX(SYS_GUID()))) AS total
FROM dual
CONNECT BY level <= 10000
)
Since 5 is the first argument and it is non-null, COALESCE will return 5 and never call the second argument. As a result, the SQL query only generates 1 row, resolving almost instantly without causing any SYS_GUID() to be generated.
Use Case: For cases where it is necessary to replace a NULL value with a predetermined value and only two alternative values exist, NVL is appropriate. The disadvantage, however, is that both arguments are evaluated regardless of the value of the first argument.