You can use it either way, however there is a one thing you should keep in mind EXEC() function is SQL injection prone
Take a look at this:
DECLARE @Data varchar(50)
SET @Data= ''''';TRUNCATE TABLE corruptTable'
execute (N'select * from corruptTable where Data = ' + @Data)
Executing this command, will give you no results (since we added that our data equals empty string) however, if you query the table ,table will be empty.
Where as in sp_executesql you are explicitly declaring parameters and
@Param = ''''';TRUNCATE TABLE corruptTable'
will be compared as it is
So in the example:
DECLARE @Param varchar(50)
SET @Param= ''''';TRUNCATE TABLE corruptTable'
execute sp_executesql N'select * from corruptTable where Data = @Data',N'@Data varchar(50)',@Data = @Param
It wont yield any results, but it wont execute truncate table, because like i said, it is only treated as a parameters. Other than that, performance vise, there is no difference.
Note that you should call procedure with schema name included, and should be aware that dynamic SQL executions will create a new plan individually from stored procedure each time you call it.