Monday, September 29, 2008

The following piece of code will allow you to have mutiple ASP.NET 2.0 Ajax CollapsiblePanelExtender controls on a single page and only one of them will be expanded at a time.  You can use this to keep the page length short.  You must set the BehaviorId of the CollapsiblePanelExtender, that is what the $find javascript function looks for.  Make sure to add all the BehaviorIds to the array in the pageLoad function.

<script type="text/javascript">

// WWB: Handles Mutual Exclusive Expansion.  Only One Extender Panel 
// Can Be Open At A Time

var extenders = [];
    
function pageLoad(sender, args)
{
    extenders[0] = $find("PanelExtender1");
    extenders[1] = $find("PanelExtender2");
    extenders[2] = $find("PanelExtender3");


    // WWB: Hook All The Extenders, If extenders[i] is null then
    // the extenders is not being displayed -- i.e. not visible
    for (var i=0; i< extenders.length; i++)
        if (extenders[i] != null)
            extenders[i].add_expandComplete( expandHandler );
}

function expandHandler(sender, args)
{
    for (var i=0; i< extenders.length; i++)
    {
        if ((extenders[i] != null) && (extenders[i] != sender))
            extenders[i]._doClose(); 
    } 
}
</script>
{6230289B-5BEE-409e-932A-2F01FA407A92}

 

 

Ajax | Wayne
Monday, September 29, 2008 8:47:30 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, September 25, 2008

This tip applies to both Microsoft SQL Server and to Oracle, and probably several other databases.

When you use the asterisk (aka star) in a select statement it requires all columns of data from the result set to be accessed.

Why not SELECT *?


If you are querying a small table with 3 or 4 columns, then the following two statements won’t be very different:

SELECT * FROM

Or

SELECT column1, column2, column3, column4 FROM

But when your query gets more complicated, and you then join in two more tables, which combined with the original table have a total of 40 columns, then all 40 columns are returned in your record set.

SELECT * FROM Table1, Table2, Table3 WHERE …   

will return all 40 columns

SELECT column1, column2, column3, column4
FROM Table1, Table2, Table3 WHERE …   

will only return 4 columns.

Recently I was optimizing a query using the SELECT * syntax which returned about 25 columns, one of which was a VARBINARY(MAX) column.  This query was taking about 7 seconds to run.  I then substituted the 6 column names that I needed for the select *, and with no other changes, that same query ran in about .1 seconds.

Additionally assume that you had the following query:

SELECT column1, column2, column3, column4 FROM Table1

And you had an index that contained column1, column2, column3, and column4.  This would be called a covered index, and when your query was run, it would never hit any of the data pages, and instead pull all of your results from the index.  This can much quicker than having to access the data pages.

So my recommendation is to never use the SELECT * syntax, specify what you want in your result sets.  Even if your table is small, specify what you want, because over time your table may grow to have more columns.

Why not COUNT(*)

Instead of COUNT(*), you should use COUNT(1).   Either way, you will get the same results. 

The COUNT(*) counts the number of rows in your result set by bringing all of the columns into memory, but using COUNT(1) doesn't require any of these columns to come into memory.  This also applies when your query includes a GROUP BY with COUNT(1).

My recommendation is to NEVER use COUNT(*), and instead use COUNT(1).  They will both give you the same number of rows in your result set, but there is far less work required to get the count when using COUNT(1), and COUNT(*) is just wasteful.




Thursday, September 25, 2008 7:34:19 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, September 17, 2008
The quick and easy way to determine how much memory your SQL Server is using is to look at the Task Manager on the server and find “sqlservr.exe” in the process list, and look at the “Mem Usage” column.

But what if you are not on the server, or if you want to grab this information programmatically from an application, it is not so obvious.  After 15 different Google queries, and many articles saying to just use DBCC MEMORYSTATUS, I finally tracked it down.

The problem with DBCC MEMORYSTATUS, is that it returns nearly 500 values about every aspect of memory possible on the SQL Server.

I finally discovered that if I take all of the output from DBCC MEMORYSTATUS, and insert it into a temporary table, I can then query for the one line of information that I need.  The total memory used, that matches what the task manager shows is called “Working Set”.   The following query returns the same memory usage numbers as the task manager shows.

CREATE TABLE #tmp

   ( row_id INT IDENTITY PRIMARY KEY, name VARCHAR(100), value BIGINT );

INSERT INTO #tmp EXEC ( 'DBCC MEMORYSTATUS' );

SELECT top 1 value / 1024 'KBUsed'

  FROM #tmp

 WHERE RTRIM(LTRIM(name)) = 'Working Set';

DROP TABLE #tmp;

From here I was able to call this from my C# code as follows:  (conn is of type SqlConnection and was already open and connected).

// get the total memory used by the SQL Server

SQLStatement = @"CREATE TABLE #tmp

   ( row_id INT IDENTITY PRIMARY KEY, name VARCHAR(100), value BIGINT );

INSERT INTO #tmp EXEC ( 'DBCC MEMORYSTATUS' );

SELECT top 1 value / 1024 'KBUsed'

  FROM #tmp

 WHERE RTRIM(LTRIM(name)) = 'Working Set';

DROP TABLE #tmp;";

 

SQLDataAdapter = new SqlDataAdapter(SQLStatement, conn);

dtResult = new DataTable();

SQLDataAdapter.Fill(dtResult);

 

foreach (DataRow drRow in dtResult.Rows)

{

    tbServerMemory.Text = drRow["KBUsed"].ToString();

}

 

SQLDataAdapter.Dispose();

 

This gives you a quick way to check the amount of memory being used by the SQL Server without being on the server or using the Task Manager.


C# | SQL Server | Steve | T-SQL
Wednesday, September 17, 2008 4:24:08 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 

Dina says I am happier when I code and not just during coding.

Some of my friends my age, and yes I am getting older, are moving to management jobs where they don’t code at all.  They might be development leads that train and deploy new technologies in bigger companies, or design systems and have others code.

Some of the same friends that interviewed at our smaller company and we didn’t hire because they just didn’t seem right (Where I work now you can’t just design or train since the company is so small).  These friends fit right in with the bigger companies; in fact they got jobs as developers however aren’t really doing any development at all.  I have a hard time calling these jobs management since they don’t have a lot of people under them; I really just want to call them a “Non-Productive” job – which is reflection of my perspective on how I like coding.  I wonder if the bigger companies will “wake up” and make them do something, or force them to do development which they were hired for, or just fire them.

I am not jealous, in fact I tell them about the stuff I am coding in my spare time and they don’t really care at all.  Which lead me to realize they really aren’t happier coding?

P.S.

Along with this profound thought, I was out for my afternoon walk in a park near where I work and there was a women spinning wool to yarn in the sun.  The first thought is what a waste of time.  If I had that time, I would be coding something.  Why doesn’t she code, what is the point of spinning yarn – someone in China and do it faster, better with a machine.  Doesn’t she realize that we are living in a quickly changing Internet world and she could make her mark on our era with just a single web site.  Then again the screen glare on the laptop prevents me from coding in the park on a sunny day. I might be sick. 

{6230289B-5BEE-409e-932A-2F01FA407A92}

Wednesday, September 17, 2008 8:18:08 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, September 16, 2008
I recently have had the opportunity to work on performance tuning on Microsoft SQL Server 2005.  My background has been more with performance tuning on Oracle.  The following is something that I have discovered to be very similar between Oracle and Microsoft SQL Server, but the names are different between the two systems.

So this brings me back to the question of how much procedure cache memory does one SQL Statement take up?   The answer is either very little memory, or all of the memory available to the cache, depending on how you do it.

Take the following query as an example.

SELECT column1 FROM table1 WHERE id = ???;

Where ??? represents the actual id number being passed into a query.  For instance:

SELECT column1 FROM table1 WHERE id = 7;
SELECT column1 FROM table1 WHERE id = 928;
SELECT column1 FROM table1 WHERE id = 12341;


Now compare the above queries to the following parameterized query:

SELECT column1 FROM table1 WHERE id = @ID_TO_FIND;

Where @ID_TO_FIND is a parameter that gets set at runtime.

To start with we need to understand how SQL Server handles the processing of queries.  There are 2 steps to running a query, the first is to compile the query (also known as creating the plan), and the second is to run the query.   The process of creating the plan (compiling) is very expensive, so SQL Server keeps a cache of these compiled queries around.  If SQL Server finds an already compiled query, it uses that, otherwise it is forced to recompile the query.

The difference between these two calling conventions is astounding.   In the first calling convention where you pass hard coded strings in each time, the SQL procedure cache will have n unique copies of the first query format cached, where n is the number of unique id parameters that are passed in.
In the second calling convention where the SQL statement is parameterized and is not changing each time, then we will have 1 copy of the SQL statement in the procedure cache, and this one cached copy is reused over and over again.

Given that the amount of memory for the procedure cache is limited (which it is), and that you could have hundreds or more queries running on your SQL server, and for each of those queries was not parameterized, you would multiply it by the number of unique parameters passed into it, you could easily in a day have hundreds of thousands of un-necessary plan compiling being done on your SQL Server.

Without using parameterized queries, you are just wasting the Procedure Cache.  If you are using parameterized queries, then your system will run faster, and scale better.

If you are using Oracle, you have the same concept, but it is called Bind Variables instead of Parameterized Queries.

Tuesday, September 16, 2008 7:44:44 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, September 15, 2008

For days I have been battling with MSDTC (Microsoft Distributed Transaction Server) and transaction that have the status of indoubt.  We are using the .NET System.Transactions.TransactionScope class to wrap many SQL Server calls together in a single transaction, which requires MSDTC to manage the transaction.  The application would run for 30 minutes then hang, timing out, and the table on SQL Server would end up being row locked -- hanging all selects, inserts, updates and deletes.  It took me a while to realize that the Kerbose error in the application log on SQL Server was the reason the MSDTC communication was failing -- by comparing the crash time with the error log.  Then doing some research I realized that all those virtual machines running our web servers that we copied around on our virtual servers had the same SID.  Even though we had renamed them and readded them to the domain, that didn't generate a new SID.  So I used Microsoft's NewSID utility to give them different SIDs and I am back in business.

NewId Application:

http://technet.microsoft.com/en-us/sysinternals/bb897418.aspx

Kerbose Error:

Event Type: Error
Event Source: Kerberos
Event Category: None
Event ID: 4
Date:  9/12/2008
Time:  12:10:29 PM
User:  N/A
Computer: LE79TEST
Description:
The kerberos client received a KRB_AP_ERR_MODIFIED error from the server
XXXXX.  The target name used was
XXXX. This indicates that the
password used to encrypt the kerberos service ticket is different than that
on the target server. Commonly, this is due to identically named  machine
accounts in the target realm (XXXX), and the client realm.
Please contact your system administrator.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Monday, September 15, 2008 8:19:23 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, September 12, 2008

ASP.NET 2.0

You do not have to call Page.RegisterRequiresRaiseEvent() in order for IPostBackEventHandler.RaisePostBackEvent() event to be called.  In fact calling Page.RegisterRequiresRaiseEvent() will interfer with all other controls on the page that need post back events.  The only way calling Page.RegisterRequiresRaiseEvent() actually works is if that is the only control on the page.  GridView doesn't have to call Page.RegisterRequiresRaiseEvent().

However, implementing just IPostBackEventHandler isn't good enough, you need to implement: IPostBackDataHandler also on your control.  If you don't then IPostBackEventHandler.RaisePostBackEvent() will never be called. 

{6230289B-5BEE-409e-932A-2F01FA407A92}

ASP.NET | C# | Wayne
Friday, September 12, 2008 1:04:41 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 

Please junior developers don't Databind() your GridView on Postback.  You only need to databind your GridView once, when the page is first loaded (and anytime the data changes).  However, if you are lazy then you will DataBind on every postback forcing the GridView to go to the data source every postback and making your page slow. 

Your junior code:

protected void Page_Load(object sender, EventArgs e)
{
    ERSGridView1.DataBind();
}

My code:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
        ERSGridView1.DataBind();
}

But, But...

Yes DataItem will not be accessible on Postback, so this code will not work:

protected void ERSGridView1_SelectedIndexChanged(object sender, EventArgs e)
{
   object myData = ERSGridView1.SelectedRow.DataItem;
}
You will have to do this:
protected void ERSGridView1_SelectedIndexChanged(object sender, EventArgs e)
{
   Int32 primaryKey = (Int32)ERSGridView1.DataKeys[ERSGridView1.SelectedIndex].Value;
   // Fetch Object From Data Source
}

I know, you have to fetch the object if the row is selected, however this is much better performance and more scaliable then fetching the all the objects on every post back.  Yes, the gridview will display all the rows if you don't DataBind, that is becuase it saves that information in ViewState and repopulates the row.

Two years ago this might not be as important.  However when you start Ajaxing your page (with Microsoft's ATLAS Extenders) there ends up being a lot more PostBacks that don't involve data changes.

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

 

ASP.NET | C# | Wayne
Friday, September 12, 2008 8:29:31 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [1]  | 
 Sunday, September 07, 2008

/useenv as s command line switch in Visual Studio 2005 is described as: "Use the following command line switches to display the integrated development environment and perform the described task." as opposed to: "Use the following command line switches to perform the described task. These command line switches do not display the IDE."  Reference: http://msdn.microsoft.com/en-us/library/xee0c8y7(VS.80).aspx  Which would make you think that /useenv is a switch for the IDE, however if you don't use it on the command line your settings for INCLUDE and LIB enviormental variables will not be used, making it very difficult to switch between platform SDK include files for your different OS versions.

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

Sunday, September 07, 2008 8:06:00 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, September 06, 2008

You can get CS1668 if you set your LIB path like this in your .bat file that builds your project using devenv.exe:

SET LIB="c:\Program Files\Microsoft SDKs\Windows\v6.0\Lib\"

instead of like this (the right way):

SET LIB=c:\Program Files\Microsoft SDKs\Windows\v6.0\Lib\

Note the quotes.  Time Wasted: 2 hours.

The usual suspect:

http://msdn.microsoft.com/en-us/library/tcbs315h(VS.80).aspx

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

C++ | Wayne
Saturday, September 06, 2008 9:29:53 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  |