HOME | FERGUSON Digital Blog

Entries Tagged as 'MS SQL2008'


CFSCRIPT Query Speed Test

ColdFusion , MS SQL2008 · By Michael Ferguson No Comments »

I was curious about the speed comparisons between an MS SQL Stored Procedure called through ColdFusion, a typical ColdFusion query written in CFM, and a ColdFusion query written in CFSCRIPT. A query of five (5) columns and 58,960 records was chosen. Here is the code used:

<cfstoredproc procedure="GetTestC" datasource="TestData" result="GetResultC" />
<cfdump var="#GetResultC#"> SP<br />

<cfset TestSQL="SELECT * FROM TableName">

<cfquery name="GetTestA" datasource="TestData" result="GetResultA">
   #TestSQL#
</cfquery>
<cfdump var="#GetResultA#"> CFM<br />

<cfscript>
   GetResultB="";
   GetSQL=New Query();
   GetSQL.setDatasource("TestData");
   GetSQL.setName("GetTestB");
   GetSQL.setResult("GetResultB");
   GetSQL.setSQL("#TestSQL#");
   GetResultB=GetSQL.execute();
   WriteDump(GetResultB.getPrefix());
</cfscript> CF9 CFSCRIPT<br />

The results are for a ColdFusion 9 server running Microsoft Server 2008 R2 communicating through a crossover to another Microsoft Server 2008 R2 with Microsoft SQL 2008. The execution times were not consistent, but the variance between the three query configurations was reasonably similar. Running the tests several times then averaging the results seemed to provide a clearer difference. The surprise was how much faster a CFC query actually runs, most of the time it was almost the same as the CFSTOREDPROC.

Average speeds:

CFM 972

CFC 728

SP 629

I was expecting the stored procedure to be the clear winner, especially with 58,960 record results but was impressed by the CFSCRIPT query speeds. Your results may vary.

If you find this post useful please leave a comment and let me know how you used the information.

Easing ColdFusion processes in MS SQL with CASE

MS SQL2008 · By Michael Ferguson No Comments »

Here is an example of how to use CASE statements in MS SQL to evaluate the size of a number (in this case a file size recorded in a database). Since the file size is numeric in this example, we are going to CAST it into a VARCHAR while we append descriptors to the end, to show "bytes", "kb", and "mb" file size abbreviations. Additionally, we will be using LEFT to remove either 3 or 6 character places from the right side of our file size number.

SELECT   CASE
      WHEN   FileSize < 1000
      THEN   CAST(FileSize AS VARCHAR) + ' bytes'
      WHEN   FileSize >= 1000 AND FileSize < 999999
      THEN   CAST(Left(FileSize, Len(FileSize)-3) AS VARCHAR) + ' kb'
      WHEN   FileSize >= 1000000
      THEN   CAST(Left(FileSize, Len(FileSize)-6) AS VARCHAR) + ' mb'
   END AS FileSize
FROM   SampleTable

If this method is used in a stored procedure, for use with ColdFusion, then we've taken some of the work performed by our application server and given to the SQL server instead. You could just record the abbreviated file sizes and their notations in the database, but you may end up saving a little space in database size storing the numerical representation. Plus, the upload results tend to be calculations in whole numbers, not mixed text.

The CASE statement may not be the best choice or right for every method and occasion, but in configurations where the application server and the SQL server are equally configured (reasonably); making MS SQL do more can help speed up application server processes.

If you find this post useful please leave a comment and let me know how you used the information.

SQL First and Last Name Combined In One Record

MS SQL2008 · By Michael Ferguson 5 Comments »

I was working with a database that was recording personnel data with first names in one record and last names in another with middle initials in another. Nothing unusual about that, but I wanted to try something different. The last names had already been stripped of all punctuation, hyphens, and dashes; this provided an opportunity to store them in one record. The pulled record could then be given to ColdFusion as a three item list, or let SQL do the work for a change.

In this example I am storing the names in a database table, in one record in the format "John.Q.Public". The plan is to show how to use SQL to divide this record into three pieces; NameFirst, NameMI, and NameLast. The trick is using a character that will divide the three names into non-repeating ranges. Since all punctuation was already removed from this data I used ".", but you could just as easily use the pipe "|" character or whatever works for you.

We use CHARINDEX to determine the position of the "." marks and get the number that represents the place it occurs in the record. This is variable because everyone's names are not the same length. SQL does not have great list tools like ColdFusion, so we have to use positional manipulation. To get the last name, we will use CHARINDEX again, but by reversing the record we can get the position of the last name. We then use LEFT and RIGHT to set the name ranges based on the values returned by CHARINDEX. The middle initial is a little more tricky. Easiest way is to PATINDEX the two decimal points surrounding the middle inital and then use the SUBSTRING to pull out one letter.

DECLARE @SQL VARCHAR(255);
SET @SQL='John.Q.Public';

SELECT   @SQL AS NameConcat,
         Left(@SQL, CHARINDEX('.', @SQL) - 1) AS NameFirst,
         Right(@SQL, CHARINDEX('.', Reverse(@SQL)) - 1) AS NameLast,
         SUBSTRING(@SQL, PATINDEX('%._.%', @SQL) + 1, 1) AS NameMI

In this example I've given you real data to use by defining a test value. It divides out the first name and last name from a concatenated record separated by a decimal point "." and stored as a single record. LEFT and RIGHT have had one subtracted from their values to omit the decimal point and SUBSTRING has one added to its value to omit the leading decimal point.

If you find this post useful please leave a comment and let me know how you used the information.

Backup with Foreign Key Constraints

MS SQL2008 · By Michael Ferguson No Comments »

Work on development assets, then deploy to production. How can you work on development assets without realistic duplicates from production? I have actually heard bush-league ColdFusion programmers brag on faking the data on development. What? So, you are an expert in your customer's field too? Although I have had to learn a lot more about my customer's processes than I ever cared to over the years, I will never fool myself into believing I can create realistic pseudo-data by which to code to their needs. That's why I would always recommend forcing a daily copy of the database(s) from the production server to the development server and work from there.

The projects I have inherited at work were created by someone who thought far too highly of Foreign Keys (FK), they are everywhere. An FK constraint forces a link between data for two tables. Normally this would be a good thing, but the problem was that these databases were created without master-storage tables with numeric representation tying them to list tables.

Through Microsoft SQL 2008, an automation (job) can be easily created using SQL Server Integration Services (SSIS) to schedule a copy task for each database, except when they are bound together with FK constraints. Using the MATER table, you can scan the "sys.databases" table for all your databases (excluding the MATER, MODEL, MSDBDATA, and TEMPDB system databases). You could hard-code for specific database, but this solution will copy any new ones added later.

Create a CURSOR, which we'll use to parse through the total of all your database names and determine which tables are tied together using foreign key constraints and store the results (I'm storing them in the MASTER and not the TEMPDB because I need access to them later). After the results are stored, we can kill the FK's and copy the databases unconstrained.

USE [master];

IF OBJECT_ID('dbo.ForeignKeysList') IS NOT NULL DROP TABLE ForeignKeysList

CREATE TABLE ForeignKeysList (
   DBName varchar(25),
   FK_Table varchar(50),
   FK_Column varchar(50),
   PK_Table varchar(50),
   PK_Column varchar(50),
   Constraint_Name varchar(100))

DECLARE DBNames CURSOR
FOR
SELECT      [name]
   FROM      sys.databases
   WHERE      Len(owner_sid) > 1
   ORDER BY   [name]

OPEN DBNames

DECLARE @Name varchar(50)
DECLARE @SQL varchar(max)

FETCH NEXT FROM DBNames
INTO @Name

WHILE (@@FETCH_STATUS <> -1)
BEGIN
EXEC ('USE [' + @Name + ']')

   SET @SQL='';
   SET @SQL=@SQL+'SELECT ''' + @Name + ''' AS DBName,FK_Table = FK.TABLE_NAME,';
   SET @SQL=@SQL+'FK_Column = CU.COLUMN_NAME,';
   SET @SQL=@SQL+'PK_Table = PK.TABLE_NAME,';
   SET @SQL=@SQL+'PK_Column = PT.COLUMN_NAME,';
   SET @SQL=@SQL+'Constraint_Name = C.CONSTRAINT_NAME ';
   SET @SQL=@SQL+'FROM [' + @Name +
'].INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS C INNER JOIN ';
   SET @SQL=@SQL+'[' + @Name +
'].INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN ';
   SET @SQL=@SQL+'[' + @Name +
'].INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN ';
   SET @SQL=@SQL+'[' + @Name +
'].INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ';
   SET @SQL=@SQL+'(SELECT   i1.TABLE_NAME, i2.COLUMN_NAME ';
   SET @SQL=@SQL+'FROM [' + @Name +
'].INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS i1 INNER JOIN ';
   SET @SQL=@SQL+'[' + @Name +
'].INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME ';
   SET @SQL=@SQL+'WHERE (i1.CONSTRAINT_TYPE = ''PRIMARY KEY'')) AS PT ON ';
   SET @SQL=@SQL+'PT.TABLE_NAME = PK.TABLE_NAME ';
   SET @SQL=@SQL+'ORDER BY   1,2,3,4,5';

   INSERT INTO ForeignKeysList
   EXEC (@SQL);

FETCH NEXT FROM DBNames
INTO @Name
END

CLOSE DBNames
DEALLOCATE DBNames

DECLARE ForeignKey CURSOR
FOR
   SELECT   *
   FROM   ForeignKeysList

OPEN ForeignKey

DECLARE @DBName varchar(25)
DECLARE @FK_Table varchar(50)
DECLARE @FK_Column varchar(50)
DECLARE @PK_Table varchar(50)
DECLARE @PK_Column varchar(50)
DECLARE @Constraint_Name varchar(100)

FETCH NEXT FROM ForeignKey
INTO @DBName, @FK_Table, @FK_Column, @PK_Table, @PK_Column, @Constraint_Name

WHILE (@@FETCH_STATUS <> -1)
BEGIN
   SET @SQL='';
   SET @SQL=@SQL+'ALTER TABLE [' + @DBName + '].dbo.' + @FK_Table + ' ';
   SET @SQL=@SQL+'DROP CONSTRAINT ' + @Constraint_Name;

   EXEC (@SQL);

FETCH NEXT FROM ForeignKey
INTO @DBName, @FK_Table, @FK_Column, @PK_Table, @PK_Column, @Constraint_Name END

CLOSE ForeignKey
DEALLOCATE ForeignKey

Last in the job, after the databases are copied it's time to add the FK entries back from our MASTER database. Creating a CURSOR again, we loop through the results and ALTER each table based on the results and re-establish the foreign key.

USE [master];

DECLARE @SQL varchar(max)

DECLARE ForeignKey CURSOR
FOR
   SELECT   *
   FROM   ForeignKeysList

OPEN ForeignKey

DECLARE @DBName varchar(25)
DECLARE @FK_Table varchar(50)
DECLARE @FK_Column varchar(50)
DECLARE @PK_Table varchar(50)
DECLARE @PK_Column varchar(50)
DECLARE @Constraint_Name varchar(100)

FETCH NEXT FROM ForeignKey
INTO @DBName, @FK_Table, @FK_Column, @PK_Table, @PK_Column, @Constraint_Name

WHILE (@@FETCH_STATUS <> -1)
BEGIN

   SET @SQL='';
   SET @SQL=@SQL+'ALTER TABLE [' + @DBName + '].dbo.' + @FK_Table + ' ADD CONSTRAINT ';
   SET @SQL=@SQL+@Constraint_Name + ' FOREIGN KEY (' + @FK_Column +
') ';
   SET @SQL=@SQL+'REFERENCES dbo.' + @PK_Table + ' (' + @PK_Column
+ ')'
   
   EXEC (@SQL);

FETCH NEXT FROM ForeignKey
INTO @DBName, @FK_Table, @FK_Column, @PK_Table, @PK_Column, @Constraint_Name END

CLOSE ForeignKey
DEALLOCATE ForeignKey

IF OBJECT_ID('dbo.ForeignKeysList') IS NOT NULL DROP TABLE ForeignKeysList

Don't forget, these kinds of automation could always go wrong if scheduled to happen while you are not present to save the day. Plan accordingly, execute wisely, and back-up often!

If you find this post useful please leave a comment and let me know how you used the information.

© Copyright 1997-2024, All Rights Reserved Coldfusion and MS SQL2008
Powered by Mango Blog.   Design by FERGUSON Digital