 <p>I have tidied up your query a little (although this won't make a massive amount of difference to performance, and there may be typos as I don't have VS to hand). From your edit it seems you are a little confused by deferred execution in LINQ. <code>callDetailsForNodes</code> does not represent your results - it is a query that will provide your results once it is executed.</p> <p>If you have to do all this querying in process I suggest you add a <code>ToList</code> after the first select and run that in isolation. Then add <code>ToList</code> to the <code>Where</code> clause. Calling <code>ToList</code> will force your query to execute and you will see where the delays are.</p> <p>One final note - you should pass your records directly to <code>ObservableCollection</code> constructor rather than calling <code>Add</code> for each item. Calling <code>Add</code> will (I think) cause the collection to raise a changed notification which is not a big deal for small lists but will slow things down for larger lists.</p> <pre><code>var callDetailsForNodes = dtRowForNode.AsEnumerable() .Select(dr =&gt; new { caller1 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) &lt; 0 ? dr["F1"] : dr["F2"], caller2 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) &lt; 0 ? dr["F2"] : dr["F1"], time = Convert.ToDateTime(dr["F3"]), filters = dr.Field&lt;string&gt;("F9")}) .Where(dr =&gt; (dtMin &lt;= dr.time) &amp;&amp; (dtMax &gt;= dr.time) &amp;&amp; (lstCallType.Contains(dr.filters)) &amp;&amp; (dtMinTime &lt;= dr.time.TimeOfDay) &amp;&amp; (dtMaxTime &gt;= dr.time.TimeOfDay) &amp;&amp; caller1 == VerSelected || caller2 == VerSelected)) .GroupBy(drg =&gt; new { drg.caller1, drg.caller2 }) .Select(drg =&gt; new { drg.Key.caller1, drg.Key.caller2, count = drg.Count()); </code></pre>