if you have MS SQL and "something else" on the same server it is important to restrict the memory for SQL server otherwise, by default, it will take "everything" and that's likely to make SQL and the-other-thing thrash.
Assuming that is not the problem:
There is a very useful Stored Procedure script by Adam Machanic called sp_WhoIsActive
That will show you where one session is blocking another
The parameters take a bit of getting-your-head around, so in case helpful here are the ones I use for "Who is blocking who"
@output_column_list = '[start_time][dd%][session_id][block%][wait_info][status][open_tran_count][login_name][tasks][tran_log%][cpu%][temp%][reads%][writes%][context%][physical%][query_plan][locks][sql_command][sql_text][%]'
, @sort_order = '[session_id] ASC,[start_time] ASC'
Longshot: We had dire performance once, with severe blocking, and we traced it to a user Defined Function which was recompiling every time it was used (and it was used everywhere ) and the re-compile was the thing that was blocking the other users.
Similarly changing Auto Recreate Stats from SYNC to ASYNC might help - if SYNC then anytime SQL triggers an update of Stats all queries needing that Stat sit-and-wait, whereas at ASYNC they just use the existing, now-stale, Stats - which were good enough 10ms ago!! so probably still good enough for one-last-query before the new Stats update has completed.