<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Performance &amp; Tuning</title>
        <link>http://geekswithblogs.net/chrisfalter/category/5200.aspx</link>
        <description>Performance &amp; Tuning</description>
        <language>en-US</language>
        <copyright>Chris Falter</copyright>
        <managingEditor>chrisfalter@yahoo.com</managingEditor>
        <generator>Subtext Version 0.0.0.0</generator>
        <item>
            <title>Health Monitoring in ASP.NET</title>
            <link>http://geekswithblogs.net/chrisfalter/archive/2008/06/06/health-monitoring-in-asp.net.aspx</link>
            <description>&lt;p&gt;While I was busy customizing Microsoft's Exception Management Application Block to classify and log all exceptions thrown in our web and Windows apps, and &lt;a href="http://geekswithblogs.net/chrisfalter/archive/2007/07/13/113923.aspx"&gt;writing instrumentation code&lt;/a&gt; that published timing events via System.Diagnostics.Trace, Microsoft was busy writing ASP.NET Health Monitoring.  Microsoft has more resources, so their product is a little more advanced and customizable.  Here's what it provides:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;An event model:&lt;/strong&gt; There are event classes for web request failures, for authentication failures, for errors, for SQL errors, for heartbeats, and so forth.  You can subclass the WebBaseEvent in order to define your own custom events, as well. &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;A provider model:&lt;/strong&gt; Health monitoring can publish events with 4 built-in providers (email notification, SQL Server, WMI, and event log).  The WMI provider is especially interesting, but you will have to write your own application to manage and report WMI events, &lt;a href="http://msdn.microsoft.com/en-us/library/ms178713(VS.80).aspx"&gt;according to Microsoft&lt;/a&gt;. &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;A customization model:&lt;/strong&gt; You can edit web.config in order to map events to providers and to configure providers (for example, to specify a connection string for the SQL Server provider). &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since we have already customized so much infrastructure, especially by writing a bug portal that makes use of the customized Exception Management block, we will probably not be migrating to the ASP.NET Health Monitor any time soon.  However, for those of you who have been whistling in the dark with respect to the health of your web applications and services, get busy!  I highly recommend Scott Allen's &lt;a href="http://odetocode.com/Blogs/scott/archive/2005/11/01/2402.aspx"&gt;post&lt;/a&gt; as a starting place for your efforts.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=122683"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=122683" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/chrisfalter/aggbug/122683.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Chris Falter</dc:creator>
            <guid>http://geekswithblogs.net/chrisfalter/archive/2008/06/06/health-monitoring-in-asp.net.aspx</guid>
            <pubDate>Sat, 07 Jun 2008 01:03:56 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/chrisfalter/comments/122683.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/chrisfalter/archive/2008/06/06/health-monitoring-in-asp.net.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/chrisfalter/comments/commentRss/122683.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/chrisfalter/services/trackbacks/122683.aspx</trackback:ping>
        </item>
        <item>
            <title>A Tool for Troubleshooting Web Apps and Web Services</title>
            <link>http://geekswithblogs.net/chrisfalter/archive/2008/01/28/119004.aspx</link>
            <description>&lt;p&gt;Recently I discovered a tool that I had needed for a long time.  &lt;a href="http://www.fiddlertool.com/fiddler/"&gt;Fiddler&lt;/a&gt;, a freeware product created and supported by Microsoftie Eric Lawson, can be used to debug HTTP traffic from any web browser (or client application).  Here's how you can use it:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. View/Analyze HTTP traffic.&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;One of our web apps creates a new window and performs a javascript-driven auto-logon to a vendor application.  When we reported an issue to the vendor, they started asking questions about whether we were using the correct version of their javascript module.  Rather than attempting to debug the javascript, I simply used Fiddler to capture all the HTTP traffic between my browser and the vendor's web server.  Fiddler formatted the data quite nicely, which made verifying my browser's behavior quite simple.  Fiddler was also able to save the relevant portions of the HTTP conversation to a log file, which I forwarded to the vendor.  The vendor was able to determine quickly that the error was in the behavior of their web server, rather than in any incorrect use of javascript on our part.  &lt;/p&gt;
&lt;p&gt;Just one day later, another vendor questioned whether one of our web services was correctly returning error data.  Source code-level debugging in the web service would have done me no good, since I had to verify the data being transmitted on the wire.  But Fiddler made the investigation easy.  I used Fiddler to capture an interaction between a test client and the service, and quickly verified that our service was returning the correct error data.  &lt;/p&gt;
&lt;p&gt;You can also use Fiddler to view all the details of a secure HTTP interaction.  Try doing that with netmon!  Just configure Fiddler to view HTTPS traffic, and it will hook any secure HTTP transactions.  It uses the "man-in-the-middle" strategy: it sets up a secure HTTP transaction between the browser and itself, then transmits the data it receives to the target URL over secure HTTP.  Sitting in the middle, it is able to view all the data in the browser-server conversation.  You just have to tell your browser to ignore the any certificate errors associated with the temporary certificate that Fiddler generates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Generate test scripts.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Visual Studio 2005 Test Edition has a tool that allow you to generate a test script for a web app by capturing the interaction between a browser and a web app.  However, this tool only captures interactions (such as form submits) generated by clicking on links and buttons.  So how do you capture javascript-driven AJAX interactions?  Use Fiddler!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Analyze performance enhancements.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you are trying to figure out how various browser settings will affect a website's performance, Fiddler can help.  You can script Fiddler to intercept browser interactions and alter metadata, which allows you to perform a "what if" analysis on the fly.  And Fiddler has a built-in timer to measure wall clock time during the interaction.  &lt;/p&gt;
&lt;p&gt;The Fiddler site has extensive documentation, including some &lt;a href="http://www.fiddlertool.com/Fiddler/help/video/default.asp"&gt;good QuickStart videos&lt;/a&gt;.  If you've been looking for a good tool to analyze HTTP traffic, look no more; go directly to the Fiddler &lt;a href="http://www.fiddlertool.com/fiddler/version.asp"&gt;download page&lt;/a&gt; and get started!&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=119004"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=119004" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/chrisfalter/aggbug/119004.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Chris Falter</dc:creator>
            <guid>http://geekswithblogs.net/chrisfalter/archive/2008/01/28/119004.aspx</guid>
            <pubDate>Mon, 28 Jan 2008 19:20:45 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/chrisfalter/comments/119004.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/chrisfalter/archive/2008/01/28/119004.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/chrisfalter/comments/commentRss/119004.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/chrisfalter/services/trackbacks/119004.aspx</trackback:ping>
        </item>
        <item>
            <title>How To: Instrument Your Code to Time Its Use of Resources</title>
            <link>http://geekswithblogs.net/chrisfalter/archive/2007/07/13/113923.aspx</link>
            <description>&lt;p&gt;Last week we went through a "fire drill" when users of one of our web applications started receiving "Gateway Timeout" errors (HTTP Error 504).  This error indicates that a gateway "server" (any host that forwards the HTTP request, including a router or web server) did not receive a timely response from a server that is supposed to respond.  Naturally we didn't have a clue as to which host in the connection chain from users' browsers to our web farm was reporting the error, but the leading candidate for the ultimate culprit was our web application.  Hence the fire drill; I had to do whatever it took to find out what might be causing a slow response.  Well, there went my 4th of July celebration!&lt;/p&gt;
&lt;p&gt;A quick Performance Monitor analysis showed that the web servers and web application were not causing any delays.  Average CPU utilization was less than 6%, and the web application itself does not have any shared internal resources that could serve as a bottleneck.  So if there &lt;em&gt;was&lt;/em&gt; a bottleneck, it had to be in the interface between our web application and some external resource.  &lt;/p&gt;
&lt;p&gt;That in turn meant that I had to insert instrumentation code to log the time spent in those interfaces.  In the .NET Framework 2.0, you accomplish this with the &lt;a target="_blank" href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx"&gt;System.Diagnostics.Stopwatch&lt;/a&gt; class:&lt;/p&gt;
&lt;p&gt;&lt;span style="COLOR: #2b91af"&gt;Stopwatch&lt;/span&gt;&lt;span style="COLOR: black"&gt; timerCall = &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;&lt;span style="COLOR: black"&gt;;&lt;br /&gt;
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style="FONT-SIZE: 9pt; FONT-FAMILY: monospace; BACKGROUND-COLOR: white"&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;&lt;span style="COLOR: black"&gt; rawResult = &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;String&lt;/span&gt;&lt;span style="COLOR: black"&gt;.Empty;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;span style="COLOR: blue"&gt;try&lt;br /&gt;
&lt;/span&gt;&lt;span style="COLOR: black"&gt;{&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;VendorProxy&lt;/span&gt;&lt;span style="COLOR: black"&gt; p = &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new&lt;/span&gt;&lt;span style="COLOR: black"&gt; &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;&lt;span style="COLOR: #2b91af"&gt;VendorProxy&lt;/span&gt;&lt;/span&gt;&lt;span style="COLOR: black"&gt;();&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;&lt;span style="COLOR: black"&gt; (useTimers)&lt;br /&gt;
    {&lt;br /&gt;
        timerCall = &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new&lt;/span&gt;&lt;span style="COLOR: black"&gt; &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Stopwatch&lt;/span&gt;&lt;span style="COLOR: black"&gt;();&lt;br /&gt;
        timerCall.Start();&lt;br /&gt;
    }&lt;br /&gt;
    rawResult = p.GetVendorData(reqText);&lt;br /&gt;
}&lt;br /&gt;
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;finally&lt;br /&gt;
&lt;/span&gt;&lt;span style="COLOR: black"&gt;{&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;&lt;span style="COLOR: black"&gt; (useTimers)&lt;br /&gt;
    {&lt;br /&gt;
        timerCall.Stop();&lt;br /&gt;
        &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Trace&lt;/span&gt;&lt;span style="COLOR: black"&gt;.WriteLine(&lt;br /&gt;
            &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="COLOR: black"&gt;.Now.ToString() + &lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;","&lt;/span&gt;&lt;span style="COLOR: black"&gt; + &lt;br /&gt;
            responseType + &lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;","&lt;/span&gt;&lt;span style="COLOR: black"&gt; + &lt;br /&gt;
            seibelsId + &lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;","&lt;/span&gt;&lt;span style="COLOR: black"&gt; +&lt;br /&gt;
            timerCall.ElapsedMilliseconds.ToString()&lt;br /&gt;
            );&lt;br /&gt;
        &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Trace&lt;/span&gt;&lt;span style="COLOR: black"&gt;.Flush();&lt;br /&gt;
    }&lt;br /&gt;
&lt;/span&gt;&lt;span style="COLOR: black"&gt;}&lt;br /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="COLOR: black"&gt;In the class' static constructor, we set the value of the useTimers boolean according to a BooleanSwitch in the web.config :&lt;/span&gt;&lt;/p&gt;
&lt;div style="FONT-SIZE: 9pt; FONT-FAMILY: monospace; BACKGROUND-COLOR: white"&gt;&lt;span style="COLOR: blue"&gt;private&lt;/span&gt;&lt;span style="COLOR: black"&gt; &lt;/span&gt;&lt;span style="COLOR: blue"&gt;static&lt;/span&gt;&lt;span style="COLOR: black"&gt; &lt;/span&gt;&lt;span style="COLOR: blue"&gt;bool&lt;/span&gt;&lt;span style="COLOR: black"&gt; useTimers;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div style="FONT-SIZE: 9pt; FONT-FAMILY: monospace; BACKGROUND-COLOR: white"&gt;&lt;span style="COLOR: blue"&gt;static&lt;/span&gt;&lt;span style="COLOR: black"&gt; VendorGatewayService()&lt;br /&gt;
{&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;BooleanSwitch&lt;/span&gt;&lt;span style="COLOR: black"&gt; timerLoggingSwitch = &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new&lt;/span&gt;&lt;span style="COLOR: black"&gt; &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;&lt;span style="COLOR: #2b91af"&gt;BooleanSwitch&lt;/span&gt;&lt;/span&gt;&lt;span style="COLOR: black"&gt;(&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;"TimerLogging"&lt;/span&gt;&lt;span style="COLOR: black"&gt;, &lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;"Determines whether to log timing info"&lt;/span&gt;&lt;span style="COLOR: black"&gt;);&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;&lt;span style="COLOR: black"&gt; (timerLoggingSwitch.Enabled)&lt;br /&gt;
        useTimers = &lt;/span&gt;&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;&lt;span style="COLOR: black"&gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;span style="COLOR: black"&gt;See the MSDN documentation for an &lt;a target="_blank" href="http://msdn2.microsoft.com/en-us/library/t06xyy08(vs.80).aspx"&gt;example&lt;/a&gt; of how to configure a BooleanSwitch in a config file.  Likewise, you may &lt;a target="_blank" href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx"&gt;configure a TraceListener in a config file&lt;/a&gt; as well. We chose to write our output to a comma-separated value (CSV) file due to its ease of use with Excel.  By logging the responseType (i.e., name of method) and our customer's ID, we would be able to determine which methods might be too slow, and which of our customers were affected.  (After all, they sometimes call to ask questions!)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="COLOR: black"&gt;If your application still uses .NET Framework 1.0 or 1.1, you should use Peter Bromberg's &lt;a target="_blank" href="http://www.eggheadcafe.com/articles/20021111.asp"&gt;HiPerfTimer&lt;/a&gt; class in place of the Stopwatch class.  Do not use the built-in TimeSpan class, whose precision is very poor.  Also, notwithstanding the MSDN documentation, it is impossible to configure a TraceListener in a config file prior to .NET Framework 2.0.  As a result, in my 1.1 web app I added the following key/value pairs in the appSettings element:&lt;/span&gt;&lt;/p&gt;
&lt;span style="COLOR: black"&gt;
&lt;div style="FONT-SIZE: 9pt; FONT-FAMILY: monospace; BACKGROUND-COLOR: white"&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;add&lt;/span&gt;&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;key&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;&lt;span style="COLOR: black"&gt;"&lt;/span&gt;&lt;span style="COLOR: blue"&gt;UseTimers&lt;/span&gt;&lt;span style="COLOR: black"&gt;"&lt;/span&gt;&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;value&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;&lt;span style="COLOR: black"&gt;"&lt;/span&gt;&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;&lt;span style="COLOR: black"&gt;"&lt;/span&gt;&lt;span style="COLOR: blue"&gt; /&amp;gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;add&lt;/span&gt;&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;key&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;&lt;span style="COLOR: black"&gt;"&lt;/span&gt;&lt;span style="COLOR: blue"&gt;TraceLogName&lt;/span&gt;&lt;span style="COLOR: black"&gt;"&lt;/span&gt;&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;value&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;&lt;span style="COLOR: black"&gt;"&lt;/span&gt;&lt;span style="COLOR: blue"&gt;c:\\projects\\dev\\agentweb\\mysoln\\1.4\\spweb\\Timer.log&lt;/span&gt;&lt;span style="COLOR: black"&gt;"&lt;/span&gt;&lt;span style="COLOR: blue"&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;span style="COLOR: black"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="COLOR: black"&gt;Here's how I used them in the Application_Start handler of global.asax.cs:&lt;/span&gt;&lt;/p&gt;
&lt;div style="FONT-SIZE: 9pt; FONT-FAMILY: monospace; BACKGROUND-COLOR: white"&gt;&lt;span style="COLOR: blue"&gt;protected&lt;/span&gt;&lt;span style="COLOR: black"&gt; &lt;/span&gt;&lt;span style="COLOR: blue"&gt;void&lt;/span&gt;&lt;span style="COLOR: black"&gt; Application_Start(&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Object&lt;/span&gt;&lt;span style="COLOR: black"&gt; sender, &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;EventArgs&lt;/span&gt;&lt;span style="COLOR: black"&gt; e)&lt;br /&gt;
{&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;bool&lt;/span&gt;&lt;span style="COLOR: black"&gt; useTimers = &lt;/span&gt;&lt;span style="COLOR: blue"&gt;false&lt;/span&gt;&lt;span style="COLOR: black"&gt;;&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;&lt;span style="COLOR: black"&gt; strUseTimers = ConfigurationSettings.AppSettings[&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;"UseTimers"&lt;/span&gt;&lt;span style="COLOR: black"&gt;];&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;&lt;span style="COLOR: black"&gt; (strUseTimers != &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;&lt;span style="COLOR: black"&gt;)&lt;br /&gt;
        useTimers = &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Boolean&lt;/span&gt;&lt;span style="COLOR: black"&gt;.Parse(strUseTimers);&lt;br /&gt;
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;&lt;span style="COLOR: black"&gt; (useTimers)&lt;br /&gt;
    {&lt;br /&gt;
        &lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;&lt;span style="COLOR: black"&gt; traceLogName = ConfigurationSettings.AppSettings[&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;"TraceLogName"&lt;/span&gt;&lt;span style="COLOR: black"&gt;];&lt;br /&gt;
        &lt;/span&gt;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;&lt;span style="COLOR: black"&gt; (traceLogName != &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;&lt;span style="COLOR: black"&gt; &amp;amp;&amp;amp; traceLogName != &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;String&lt;/span&gt;&lt;span style="COLOR: black"&gt;.Empty)&lt;br /&gt;
        {&lt;br /&gt;
            StreamWriter file = File.AppendText(traceLogName);&lt;br /&gt;
            TextWriterTraceListener log = &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new&lt;/span&gt;&lt;span style="COLOR: black"&gt; TextWriterTraceListener(file);&lt;br /&gt;
            Trace.Listeners.Add(log);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;/span&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now that my colleague/manager Chris Glasser has identified the main bottleneck, I can edit the config files to turn off the logging.  And if another resource contention issue rears its nasty-looking head, I can edit the config files to turn the logging back on.  Very convenient.  (For you Michael Jackson fans, it's as "easy as A-B-C.")&lt;/p&gt;
&lt;p&gt;Want to know what the root problem was?  It wouldn't be fair for me to leave my readers hanging, would it?  Okay, you've stuck with me through this article; I'll reward your faithful readership....  The insurance agents' requests were never even reaching our web application due to networking issues at one of big carriers.  When I returned from my delayed vacation, you could almost see the steam come out of my ears when I learned this.  Have any of you ever worked like crazy to solve a problem, only to discover that the root cause was something outside your control?  Leave a comment so we can commiserate!&lt;/p&gt;
&lt;/span&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=113923"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=113923" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/chrisfalter/aggbug/113923.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Chris Falter</dc:creator>
            <guid>http://geekswithblogs.net/chrisfalter/archive/2007/07/13/113923.aspx</guid>
            <pubDate>Fri, 13 Jul 2007 19:46:46 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/chrisfalter/comments/113923.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/chrisfalter/archive/2007/07/13/113923.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/chrisfalter/comments/commentRss/113923.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/chrisfalter/services/trackbacks/113923.aspx</trackback:ping>
        </item>
        <item>
            <title>Solved: The Mystery of DataView's Poor Performance with Large Recordsets</title>
            <link>http://geekswithblogs.net/chrisfalter/archive/2006/08/15/88057.aspx</link>
            <description>&lt;P&gt;Well, maybe I solved it.&amp;nbsp; At least I have a reasonable hypothesis.&lt;/P&gt;
&lt;P&gt;Reader &amp;#8220;Ghassan&amp;#8221; postulated in a comment to &lt;A href="http://geekswithblogs.net/chrisfalter/archive/2006/08/04/87143.aspx"&gt;my earlier post&lt;/A&gt; that it's the extra burden of creating an array of DataRowView that puts the DataView approach&amp;nbsp;at a disadvantage to DataTable.Select.&amp;nbsp; However, a glance at DataView's default indexer in Lutz Roeder's wonderful &lt;A href="http://www.aisto.com/roeder/dotnet/"&gt;Reflector utility&lt;/A&gt; shows that the array of DataRowView is not created while the constructor is executing.&amp;nbsp; Instead, it is created when and if the DataView indexer is called. The DataView indexer calls its private GetElement method in order to return a DataRowView:&lt;/P&gt;&lt;FONT color=#1000a0&gt;&lt;PRE&gt;&lt;FONT color=#1000a0&gt;private&lt;/FONT&gt; &lt;FONT color=#006018&gt;DataRowView&lt;/FONT&gt; &lt;B&gt;GetElement&lt;/B&gt;(&lt;FONT color=#006018&gt;int&lt;/FONT&gt; index)
{
      &lt;FONT color=#1000a0&gt;if&lt;/FONT&gt; ((index &lt;FONT color=#600df0&gt;&amp;lt;&lt;/FONT&gt; &lt;FONT color=#800000&gt;0&lt;/FONT&gt;) || (&lt;A title="int index; // Parameter"&gt;&lt;FONT color=#006018&gt;index&lt;/FONT&gt;&lt;/A&gt; &amp;gt;= &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;recordCount&lt;/FONT&gt;))
      {
            &lt;FONT color=#1000a0&gt;throw&lt;/FONT&gt; &lt;FONT color=#006018&gt;ExceptionBuilder&lt;/FONT&gt;.&lt;FONT color=#006018&gt;GetElementIndex&lt;/FONT&gt;(&lt;A title="int index; // Parameter"&gt;&lt;FONT color=#006018&gt;index&lt;/FONT&gt;&lt;/A&gt;);
      }
      &lt;FONT color=#1000a0&gt;return&lt;/FONT&gt; &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;RowViewCache&lt;/FONT&gt;[&lt;A title="int index; // Parameter"&gt;&lt;FONT color=#006018&gt;index&lt;/FONT&gt;&lt;/A&gt;];
}
&lt;/FONT&gt;&lt;/PRE&gt;
&lt;P&gt;And the RowViewCache uses lazy instantiation for the array of DataRowView:&lt;/P&gt;&lt;PRE&gt;&lt;FONT color=#1000a0&gt;internal&lt;/FONT&gt; &lt;FONT color=#006018&gt;DataRowView&lt;/FONT&gt;[] &lt;B&gt;RowViewCache&lt;/B&gt;
{
      &lt;FONT color=#1000a0&gt;get&lt;/FONT&gt;
      {
            &lt;FONT color=#1000a0&gt;if&lt;/FONT&gt; (&lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;rowViewCache&lt;/FONT&gt; == &lt;FONT color=#800000&gt;null&lt;/FONT&gt;)
            {
                  &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;rowViewCache&lt;/FONT&gt; = &lt;FONT color=#1000a0&gt;new&lt;/FONT&gt; &lt;FONT color=#006018&gt;DataRowView&lt;/FONT&gt;[&lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;Count&lt;/FONT&gt;];
                  &lt;FONT color=#1000a0&gt;for&lt;/FONT&gt; (&lt;FONT color=#006018&gt;int&lt;/FONT&gt; &lt;B&gt;num1&lt;/B&gt; = &lt;FONT color=#800000&gt;0&lt;/FONT&gt;; &lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt; &amp;lt; &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;Count&lt;/FONT&gt;; &lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;++)
                  {
                        &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;rowViewCache&lt;/FONT&gt;[&lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;] = &lt;FONT color=#1000a0&gt;new&lt;/FONT&gt; &lt;FONT color=#006018&gt;DataRowView&lt;/FONT&gt;(&lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;, &lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;);
                  }
            }
            &lt;FONT color=#1000a0&gt;return&lt;/FONT&gt; &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;rowViewCache&lt;/FONT&gt;;
      }
}&lt;/PRE&gt;
&lt;P&gt;In other words, unless and until your code attempts to get a DataRowView via the indexer, the DataView will not create&amp;nbsp;the array of&amp;nbsp;DataRowView at all.&amp;nbsp; And my code did not call the indexer until after the 9 seconds had elapsed.&amp;nbsp; So we must eliminate this hypothesis.&amp;nbsp; Of course, Ghassan, I did not supply a code listing, you could not have known this.&amp;nbsp; Believe me, I appreciate reader comments, and I wish I got more of them!&amp;nbsp;&amp;nbsp;Please keep posting comments.&amp;nbsp; Please.&lt;/P&gt;
&lt;P&gt;So what&amp;nbsp;are the DataView constructor and RowFilter setter doing while the clock ticks off 9 seconds?&amp;nbsp; Here's what the default constructor does:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;It initializes default settings.&amp;nbsp; This involves maybe a couple of dozen assignment statements, which&amp;nbsp;can't take more than a few milliseconds. 
&lt;LI&gt;It instantiates an internal DataViewListener, which creates delegates for the DataTable events that need to be monitored.&amp;nbsp; Again, this should take only a few milliseconds at most. 
&lt;LI&gt;It instantiates an internal Index, which is an array of int members that index into the DataTable.&amp;nbsp; This involves: 
&lt;UL&gt;
&lt;LI&gt;Instantiating the array, which should (once again) involve modest computing resources. 
&lt;LI&gt;Setting the bounds of the array by applying any filter criteria.&amp;nbsp; For the default constructor, there is no filter, so it's a one-step operation; the size is equal to the DataTable's record count. 
&lt;LI&gt;Sorting the array.&amp;nbsp; &lt;BR&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Then my next line of code, the call to the DataView.RowFilter setter, will create a second internal Index.&amp;nbsp; When&amp;nbsp;index sets the bounds of its array, it will have to apply the RowFilter criteria.&amp;nbsp; This should be comparable to the computing resources used by the DataTable.Select method.&lt;/P&gt;
&lt;P&gt;The only significant difference in computing resources, then, must come from the fact that instantiating a DataView and setting its RowFilter involves sorting a rather large&amp;nbsp;array of record indices twice.&amp;nbsp; Let's take a closer look at that sort:&lt;/P&gt;&lt;PRE&gt;&lt;FONT color=#1000a0&gt;private&lt;/FONT&gt; &lt;FONT color=#006018&gt;void&lt;/FONT&gt; &lt;B&gt;Sort&lt;/B&gt;(&lt;FONT color=#006018&gt;int&lt;/FONT&gt; left, &lt;FONT color=#006018&gt;int&lt;/FONT&gt; right)
{
      &lt;FONT color=#006018&gt;int&lt;/FONT&gt; &lt;B&gt;num1&lt;/B&gt;;
      &lt;FONT color=#1000a0&gt;do&lt;/FONT&gt;
      {
            &lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt; = &lt;A title="int left; // Parameter"&gt;&lt;FONT color=#006018&gt;left&lt;/FONT&gt;&lt;/A&gt;;
            &lt;FONT color=#006018&gt;int&lt;/FONT&gt; &lt;B&gt;num2&lt;/B&gt; = &lt;A title="int right; // Parameter"&gt;&lt;FONT color=#006018&gt;right&lt;/FONT&gt;&lt;/A&gt;;
            &lt;FONT color=#006018&gt;int&lt;/FONT&gt; &lt;B&gt;num3&lt;/B&gt; = &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;records&lt;/FONT&gt;[(&lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt; + &lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;) &amp;gt;&amp;gt; &lt;FONT color=#800000&gt;1&lt;/FONT&gt;];
            &lt;FONT color=#1000a0&gt;do&lt;/FONT&gt;
            {
                  &lt;FONT color=#1000a0&gt;while&lt;/FONT&gt; (&lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;CompareRecords&lt;/FONT&gt;(&lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;records&lt;/FONT&gt;[&lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;], &lt;A title="int num3 // Local Variable"&gt;&lt;FONT color=#006018&gt;num3&lt;/FONT&gt;&lt;/A&gt;) &amp;lt; &lt;FONT color=#800000&gt;0&lt;/FONT&gt;)
                  {
                        &lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;++;
                  }
                  &lt;FONT color=#1000a0&gt;while&lt;/FONT&gt; (&lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;CompareRecords&lt;/FONT&gt;(&lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;records&lt;/FONT&gt;[&lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;], &lt;A title="int num3 // Local Variable"&gt;&lt;FONT color=#006018&gt;num3&lt;/FONT&gt;&lt;/A&gt;) &amp;gt; &lt;FONT color=#800000&gt;0&lt;/FONT&gt;)
                  {
                        &lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;--;
                  }
                  &lt;FONT color=#1000a0&gt;if&lt;/FONT&gt; (&lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt; &amp;lt;= &lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;)
                  {
                        &lt;FONT color=#006018&gt;int&lt;/FONT&gt; &lt;B&gt;num4&lt;/B&gt; = &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;records&lt;/FONT&gt;[&lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;];
                        &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;records&lt;/FONT&gt;[&lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;] = &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;records&lt;/FONT&gt;[&lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;];
                        &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;records&lt;/FONT&gt;[&lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;] = &lt;A title="int num4 // Local Variable"&gt;&lt;FONT color=#006018&gt;num4&lt;/FONT&gt;&lt;/A&gt;;
                        &lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;++;
                        &lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;--;
                  }
            }
            &lt;FONT color=#1000a0&gt;while&lt;/FONT&gt; (&lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt; &amp;lt;= &lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;);
            &lt;FONT color=#1000a0&gt;if&lt;/FONT&gt; (&lt;A title="int left; // Parameter"&gt;&lt;FONT color=#006018&gt;left&lt;/FONT&gt;&lt;/A&gt; &amp;lt; &lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;)
            {
                  &lt;FONT color=#1000a0&gt;this&lt;/FONT&gt;.&lt;FONT color=#006018&gt;Sort&lt;/FONT&gt;(&lt;A title="int left; // Parameter"&gt;&lt;FONT color=#006018&gt;left&lt;/FONT&gt;&lt;/A&gt;, &lt;A title="int num2 // Local Variable"&gt;&lt;FONT color=#006018&gt;num2&lt;/FONT&gt;&lt;/A&gt;);
            }
            &lt;A title="int left; // Parameter"&gt;&lt;FONT color=#006018&gt;left&lt;/FONT&gt;&lt;/A&gt; = &lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt;;
      }
      &lt;FONT color=#1000a0&gt;while&lt;/FONT&gt; (&lt;A title="int num1 // Local Variable"&gt;&lt;FONT color=#006018&gt;num1&lt;/FONT&gt;&lt;/A&gt; &amp;lt; &lt;A title="int right; // Parameter"&gt;&lt;FONT color=#006018&gt;right&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=4&gt;&lt;FONT size=3&gt;);
}&lt;/FONT&gt;
&lt;/FONT&gt;&lt;/PRE&gt;
&lt;P&gt;We see that the Sort method implements the &lt;A href="http://en.wikipedia.org/wiki/Quicksort"&gt;Quicksort algorithm&lt;/A&gt;.&amp;nbsp; It chooses an arbitrary midpoint, places all the values lower than the midpoint's to the left and all the higher values to the right.&amp;nbsp; Then it applies itself recursively to the left and right sections.&amp;nbsp; Eventually it will recurse down to sections that cannot be divided into smaller sections (i.e., when a section consists of a single&amp;nbsp;array member), at which point the sort has completed.&amp;nbsp; Using big-O notation, we can say that this algorithm&amp;nbsp;executes in&amp;nbsp;O(n log n) time, which is about as efficient as you can expect from a sorting algorithm.&amp;nbsp; As long as each iteration of the sort divides the set of indices into two equal parts, we are dealing with a logarithm of base 2.&amp;nbsp; &amp;nbsp;So for 122,000 records (approximately 2 raised to the 17th power), the algorithm will call the Index.CompareRecords method approximately 122,000 x 17 times, which is a little over 2 million times.&amp;nbsp; And each call to Index.CompareRecords traverses a call stack several layers deep as it&amp;nbsp;wends its way through the object model.&amp;nbsp; Do this whole scenario twice and you can chew up 9 seconds.&lt;/P&gt;
&lt;P&gt;At least I think so.&amp;nbsp; To prove all this, you would have to instrument the System.Data code and check run-time performance with a testing tool.&amp;nbsp; So if there's a Computer Science student out there who wants an interesting research project, have some fun with &lt;A href="http://www.mono-project.com/Main_Page"&gt;Mono&lt;/A&gt; and tell us what you find.&amp;nbsp; Anyone?&lt;/P&gt;&lt;/FONT&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=88057"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=88057" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/chrisfalter/aggbug/88057.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Chris Falter</dc:creator>
            <guid>http://geekswithblogs.net/chrisfalter/archive/2006/08/15/88057.aspx</guid>
            <pubDate>Wed, 16 Aug 2006 06:24:00 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/chrisfalter/comments/88057.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/chrisfalter/archive/2006/08/15/88057.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/chrisfalter/comments/commentRss/88057.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/chrisfalter/services/trackbacks/88057.aspx</trackback:ping>
        </item>
        <item>
            <title>Why You Might Prefer a DataView to an Array of DataRecord</title>
            <link>http://geekswithblogs.net/chrisfalter/archive/2006/08/07/87328.aspx</link>
            <description>&lt;P&gt;Before we get too obsessed about the performance advantages of an array of DataRecord over a DataView, let's remember that a DataView behaves differently than an array of DataRecord.&amp;nbsp; No matter how you modify the data in an array of DataRecord, the array bounds will always be the same.&amp;nbsp; However, modifying a field in a DataRecord may cause it to disappear from a DataView, if the modification causes the record to be filtered by the DataView.Filter property.&amp;nbsp; Or if you modify a DataRecord in a DataTable, you might cause it to suddenly appear in a related&amp;nbsp;DataView.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;If you need this kind of dynamic, event-driven&amp;nbsp;update of set membership, you are going to have to use a DataView, regardless of the performance considerations.&amp;nbsp; If you don't need the dynamic set membership update, then performance considerations would&amp;nbsp;suggest you use&amp;nbsp;an array of DataRecord.&lt;/P&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=87328"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=87328" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/chrisfalter/aggbug/87328.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Chris Falter</dc:creator>
            <guid>http://geekswithblogs.net/chrisfalter/archive/2006/08/07/87328.aspx</guid>
            <pubDate>Tue, 08 Aug 2006 07:47:00 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/chrisfalter/comments/87328.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/chrisfalter/archive/2006/08/07/87328.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/chrisfalter/comments/commentRss/87328.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/chrisfalter/services/trackbacks/87328.aspx</trackback:ping>
        </item>
        <item>
            <title>Array of DataRecord vs. DataView: A Dramatic Difference in Performance</title>
            <link>http://geekswithblogs.net/chrisfalter/archive/2006/08/04/87143.aspx</link>
            <description>&lt;P&gt;I spent much of last weekend running tests against a table with 122,000 records.&amp;nbsp; The folks at Citibank and Geico would just yawn at that amount of data, but where I work that's fairly heavy lifting.&amp;nbsp; As I was tuning and validating the tests, I used a bit-field flag ("TestCompleted") to track whether a record had already been tested.&amp;nbsp; No need to do work twice, eh?&lt;/P&gt;
&lt;P&gt;Because this was a one-time set of tests, I used a TableAdapter (the simplest possible code) to grab all the records, then I needed to filter out all the records that had already been processed.&amp;nbsp; My initial solution was to use a DataView; just set the Filter property with a filter expression ("TestCompleted = false"), and voila--instant filtration!&amp;nbsp; Although it wasn't quite instant....my computer required 9 seconds to perform the operation.&lt;/P&gt;
&lt;P&gt;For reasons I won't go into here, I had to switch to using an array of DataRecord returned by the DataTable.Select method.&amp;nbsp; The filter expression ("TestCompleted = false") was simply passed as a parameter to the Select method, rather than to the DataView.Filter setter.&amp;nbsp; So I ran the test again, and....whoa!&lt;/P&gt;
&lt;P&gt;I had my array of DataRecord in just one second.&amp;nbsp; That's a &lt;EM&gt;&lt;STRONG&gt;whole order of magnitude&lt;/STRONG&gt;&lt;/EM&gt; faster than the DataView approach!&lt;/P&gt;
&lt;P&gt;Frankly, I don't know why the DataView.Filter approach is so much more computationally expensive than the DataTable.Select approach.&amp;nbsp; And perhaps for small amounts of data, the two approaches would be equally good--or the DataView might even be better and faster.&amp;nbsp; I didn't test the small recordset scenario, so I don't know that either.&amp;nbsp; (Note: I have subsequently posted &lt;A href="http://geekswithblogs.net/chrisfalter/archive/2006/08/15/88057.aspx"&gt;an analysis &lt;/A&gt;of the reason why the DataView is so much slower for those who are interested.)&lt;/P&gt;
&lt;P&gt;What I do know is this: if you're filtering a large amount of data in a DataTable, and you care about system performance, you will want to filter your data by using DataTable.Select (to get an array of DataRecord), rather than using DataView.Filter.&lt;/P&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=87143"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=87143" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/chrisfalter/aggbug/87143.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Chris Falter</dc:creator>
            <guid>http://geekswithblogs.net/chrisfalter/archive/2006/08/04/87143.aspx</guid>
            <pubDate>Sat, 05 Aug 2006 06:34:00 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/chrisfalter/comments/87143.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/chrisfalter/archive/2006/08/04/87143.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/chrisfalter/comments/commentRss/87143.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/chrisfalter/services/trackbacks/87143.aspx</trackback:ping>
        </item>
    </channel>
</rss>