Once you execute the query, process goes through a couple phases :
In the first phase it checks whether your code is correct
Second phase it binds the tables and columns you have provided. Gives you an error of non existing table/column if it fails
In the third phase query is passed to a query optimizer which (assuming you`re not using Query Store feature) checks if it has cached plan, and if statistics are up to date. Depending on result, it can either create a new plan, or use existing one. It can even create a trivial plan, if query is simple enough but that is not a concern right now.
Query optimizer decision making can hardly have any on your query execution because it has certain amount of time to create a plan no matter how complicated the query is, that is why it can create a non optimal plan for non-optimized queries and outdated statistics.
What you can do is use this query to get most expensive queries, and how many times certain query has executed. If number of executions_count of concerning query is not increasing it means it creates a new a plan for it(which mostly happens with ad-hoc queries).
Also pay attention on last_logical_reads,elapsed_time,last_rows if it makes sense to have etc 100000 logical reads for result set of 10 rows, in that case you would need to optimize the query, same can be applied for last_elapsed time, if its too long, and you`re having low num of logical reads and rows, check if it contains some sort of scalar function, use UDF instead, and so on.
SELECT TOP 10
total_worker_time / execution_count AS [Avg CPU Time] ,last_worker_time ,max_dop,last_logical_reads,last_elapsed_time,last_rows,
CASE WHEN deqs.statement_start_offset = 0
AND deqs.statement_end_offset = -1
THEN '-- see objectText column--'
ELSE '-- query --' + CHAR(13) + CHAR(10)
+ SUBSTRING(execText.text, deqs.statement_start_offset / 2,
( ( CASE WHEN deqs.statement_end_offset = -1
END ) - deqs.statement_start_offset ) / 2)
END AS queryText
FROM sys.dm_exec_query_stats deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.plan_handle) AS execText
ORDER BY deqs.total_worker_time DESC ;
In summary, try to avoid ad-hoc queries as much as possible, using stored procedures or indexed_views.
Hope it helps!