Category Archives: Database

Sql Server 2008 Logo

Change Collation Sql Server 2008 Database

 

Sql 2008To change the collation of Sql Server 2008 Database, you’ll first need to drop the objects in the database that are dependent of the collation (like functions for instance). Otherwise you will get an error like this

The object ‘…’ is dependent on database collation.

Once you’ve dropped these objects, you can set the collation using this t-sql

 

 

1
2
3
4
5
6
ALTER DATABASE [dbname]
SET SINGLE_USER WITH ROLLBACK IMMEDIATE
ALTER DATABASE [dbname]
COLLATE SQL_Latin1_General_CP1_CI_AS
ALTER DATABASE [dbname]
SET MULTI_USER

After this, you’ll have to recreate your dropped objects.

Sql Server 2008 Logo

Moving FileStream data to a new location or renaming it (basically the same)

Sql 2008You’ll just have to detach the existing database, then rename the FileStream folder and then attach it again using following sql:






1
2
3
4
5
6
7
8
9
USE [master]
GO
CREATE DATABASE [televic-edu3-dev-one-channel] ON
( FILENAME = N'C:\Program Files\Microsoft SQL Server\...\DATA\name.mdf' ),
( FILENAME = N'C:\Program Files\Microsoft SQL Server\...\DATA\name.ldf' ),
FILEGROUP [FileStreamGroup] CONTAINS FILESTREAM DEFAULT
( NAME = N'name_FSData',
FILENAME = N'C:\Program Files\Microsoft SQL Server\...\DATA\name' )
FOR ATTACH

name_FSData will be the name of the renamed folder.

More information on other ways to do it here.

Database version control MSSQL C#[dot]NET Program

Some time ago I read an article on the importance of version control for databases by Jeff Atwood. I knew that in our team we had to start using something like this because updating different databases to a new release took a lot of time. We always used sql compare to look for the difference between the two databases and to update the database. Sometimes, with small changes, this wasn’t that bad, but with big differences and with data that also needed to be inserted, it was a nightmare. And if you had done one database, you needed to do it all over on another… very bad, very bad, but hey, we learn, we learn. Now I’ve created a C#.NET Console Application that handles most of the things described in the blog of Jeff Atwood. It’s certainly not done and lots of things can be improved, but due to a lack of time right now, this will currently have to do it. It does its job and that’s all we needed. This is the source code and this is the release build. In order to follow this serie of posts, you’d have to read the article by Jeff Atwood because I will not repeat everything he has said. In the source code zip there’s a folder lib with libraries I used and a folder files with the files I will explain further on.

What’s not implemented?

  • Setting up a database from scratch using the baseline scripts is not implemented.
  • Configuring more things like folder structure
  • Support for databases other than mssql
  • Views are not implemented as we do not use them yet in our application. Implementing them however is pretty easy and you should be able to do it yourself with the source code.

How does it work?

First you have to have a certain folderstructure because I haven’t had time to configure that. Here’s a screenshot of how it should look:

Screenshot Folder Structure

Screenshot Folder Structure

I quickly wrote the program so that we could use Database Version Control as quick as possible. Because of that default it works with this folder structure. Under Program is the Release build of the C# Console Application. Under the root of Scripts are the update scripts along with some files I’ll discuss later. Under the functions and storedprocedures are the create (no alter scripts because the sp’s and functions are removed when running the exe!) scripts for functions and stored procedures.

How does the root of Scripts look like:

Screenshot Files under Scripts folder

Screenshot Files under Scripts folder

  • DropStoredProceduresAndFunctions.sql: Script that will be used to delete all sp’s and functions out of the database. This will be necessary before creating all sp’s and functions.
  • excludeList.csv: This is a text file with comma seperated values. If one of the values appears in the name of a sp or function, then this sp or function will be ignored (will not be deleted and not be created).
  • sc.xx.xx.xxxx.sql: The update scripts. The name is important as the exe depends on that.
  • sc.template.sql: This is a template script that is best used to create an update script

Explanation of scripts

DropStoredProceduresAndFunctions.sql script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
-- variable to object name
DECLARE @name VARCHAR(1000)
-- variable to hold object type
DECLARE @xtype VARCHAR(20)
-- variable to hold sql string
DECLARE @sqlstring nvarchar(4000)
DECLARE SPViews_cursor cursor FOR
SELECT QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME)
AS name, ROUTINE_TYPE AS xtype
FROM
INFORMATION_SCHEMA.ROUTINES
UNION
SELECT QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) AS
name, 'VIEW' AS xtype
FROM
INFORMATION_SCHEMA.VIEWS
 
OPEN SPViews_cursor
fetch NEXT FROM SPViews_cursor INTO @name, @xtype
while @@fetch_status = 0
BEGIN
-- test object type if it is a stored procedure
IF @xtype = 'PROCEDURE' ###
BEGIN
SET @sqlstring = 'drop procedure ' + @name
EXEC sp_executesql @sqlstring
SET @sqlstring = ' '
END
-- test object type if it is a function
IF @xtype = 'FUNCTION' ###
BEGIN
SET @sqlstring = 'drop FUNCTION ' + @name
EXEC sp_executesql @sqlstring
SET @sqlstring = ' '
END
-- test object type if it is a view
--if @xtype = 'VIEW'
-- begin
-- set @sqlstring = 'drop view ' + @name
-- exec sp_executesql @sqlstring
-- set @sqlstring = ' '
-- end
-- get next record
fetch NEXT FROM SPViews_cursor INTO @name, @xtype
END
close SPViews_cursor
deallocate SPViews_cursor

I’ve got this from here. The ### tokens will be replace by transact-sql by the program to exclude sp’s and funtions with certain keywords (excludeList.csv).

Example of an update script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
Comment
*/
SET NUMERIC_ROUNDABORT OFF
GO
SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS ON
GO
IF EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#tmpErrors')) DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error INT)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION
GO
 
-- sql code
 
GO
 
INSERT INTO [dbo].[SchemaChanges]
([MajorReleaseNumber]
,[MinorReleaseNumber]
,[PointReleaseNumber]
,[ScriptName]
,[DateApplied])
VALUES
('03'
,'01'
,'0011'
,'Comment'
,GETDATE())
 
GO
IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>0 BEGIN
PRINT 'The database update succeeded'
COMMIT TRANSACTION
END
ELSE PRINT 'The database update failed'
GO
DROP TABLE #tmpErrors
GO

These sort of scripts will be executed by a SqlCommand (DbCommand from Enterprise Library). We are still experimenting and have seen that the Transactions do not work. Somehow there’s a difference between these kind of scripts being executed in Management Studio and being executed by a SqlCommand. I think we’ll have to use TransactionScrope in the C# Console Application to make the transactions work. These Transactions are important because if only a part of the script would be executed, then the build would be broken. You would then have to restore a previous backup, fix the script and run the exe again against the database. Later on I’ll talk about some best practices to use database version control. The GO statements are also a program and the program filters them out before executing the script (again with some other keywords that cause problems). In a couple of months, when we have been able to work things out a little better, I’ll post a new version. For now, this is what you get ;-) .

In the script there’s place to put your sql code and then there’s an important part, updating the SchemaChanges table. Each update script inserts a new record in the table SchemaChanges so that the update gets registered in the database. With this table, the program can check what the last update was and look for new scripts in the Script folder. It’s very important that the values you insert into the SchemaChanges table correspond to the name you gave to the file, otherwise the whole thing will not work correctly.

sc.template.sql script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
Commentaar
*/
SET NUMERIC_ROUNDABORT OFF
GO
SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS ON
GO
IF EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#tmpErrors')) DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error INT)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION
GO
 
-- Plaats SQL Code hier
 
GO
 
INSERT INTO [dbo].[SchemaChanges]
([MajorReleaseNumber]
,[MinorReleaseNumber]
,[PointReleaseNumber]
,[ScriptName]
,[DateApplied])
VALUES
('00'
,'00'
,'0000'
,'Short Description'
,GETDATE(), 'Delete this parameter (is to make sure you change the version numbers')
 
GO
IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>0 BEGIN
PRINT 'The database update succeeded'
COMMIT TRANSACTION
END
ELSE PRINT 'The database update failed'
GO
DROP TABLE #tmpErrors
GO

This is the template, which will surely change in the next months. The INSERT query will not work like it is written because there’s a value too much. I’ve done this so that my teammembers wouldn’t forget to edit the release numbers.

Explanation of the program and source code

Let’s start of with explaining how the exe (DatabaseVersionControl.exe) works:

Parameters that are required (one):

-connectionString=”Data Source=OMITTED;Persist Security Info=True;Integrated Security=SSPI;Initial Catalog=OMITTED;MultipleActiveResultSets=True”

Parameters that are optional (two):

-include “value1,value2,…” : If one of these values are in the excludeList.csv, then they will be overruled so that they will not be excluded.

-scriptsDirectory=”…” : Path to the directory which contains the scripts. Under this folder the two folders storedprocedures and functions must be existing, otherwise the program will not work. Maybe that in the future this can be configured, but for now it’ll do. If this parameter is left out, then the exe searches for the scripts folder at ../Scripts. Change this if you want in the soruce code.

The source code itself is explained in the code. You’ll need some 4.1 enterprise libraries, but I guess you’ll see that if you try to compile the code. I have put them in a lib folder, but the project uses the dll’s from the registry.

We use cruisecontrol to set up a part of continuous integration. One project of cruisecontrol is listening to the scripts svn repository and executes the exe with the proper connectionstring is something has changed.

Best practices that we use in our team

  1. Everybody that wants to work at the database has a local database.
  2. Before starting to write an update script or change a sp or function, update your svn repository and execute the exe against your local database (and make sure you use the right one if you also have maintenance branches). I create a local bat file for each branch and for the trunk.
  3. If you want to change an sp or function, open the corresponding file, edit it, save it and run the exe. If everything works, commit the changed sp or function.
  4. If you want to create an update script, copy the template and give it the right name. If the last update script is sc.03.01.0017.sql, then the new one should be sc.03.01.0008.sql or sc.03.02.0000.sql or sc.04.00.0000.sql, depending on what kind of change you are going to make. !Do not commit at this point!
  5. Open the change script in an editor or in management studio and put in your scripts. Change the release numbers and put in some comment. Save the script and run the exe. If everything works, commit the change script.

Executing a change script, sp script or function script in management studio is a bad idea. It may work in management studio but not with the exe. In the future we’ll have to check some things that happen with the exe and not with executing them in management studio, but for now we use what we have. If you do want to test changes in management studio you should take a backup before you start doing that. If you think your script is done, then restore your db and run the exe. It’s not fun for other developers if things go wrong on the development database after you committed.

WITH common_table_expression (Transact-SQL)

Information at link.

I’ll write this down so I won’t forget it. This common table expression enables you to omit CURSORS and apparently it goes quicker.

This query

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
INSERT #TempTreeStructures (TreeStructureId) VALUES (@RootTreeStructureId)
 
SET @RootRightValue = @RootRightValue - 1
 
SELECT @RightValue = RightValue,
@TreeStructureId = TreeStructureId
FROM TreeStructures
WHERE TreeId = @TreeId AND
LeftValue = @RootLeftValue + 1
 
WHILE (@RightValue < @RootRightValue)
BEGIN
INSERT #TempTreeStructures (TreeStructureId) VALUES (@TreeStructureId)
SELECT @RightValue = RightValue,
@TreeStructureId = TreeStructureId
FROM TreeStructures
WHERE TreeId = @TreeId AND
LeftValue = @RightValue + 1
END
 
INSERT #TempTreeStructures (TreeStructureId) VALUES (@TreeStructureId)
SELECT ts.TreeStructureId,
ts.LeftValue,
ts.RightValue,
tn.Name,
tn.TYPE,
tn.DATA ,
tn.Description,
tn.DateChanged ,
tn.UserId
FROM TreeStructures ts
JOIN TreeNodes tn ON ts.TreeStructureId = tn.TreeStructureId
WHERE ts.TreeStructureId = (SELECT TOP 1 TreeStructureId FROM #TempTreeStructures)
AND tn.TreeNodeId = (SELECT TOP 1 tn2.TreeNodeId FROM TreeNodes tn2 WHERE tn2.TreeStructureId = ts.TreeStructureId ORDER BY tn2.DateChanged DESC)
UNION ALL
SELECT ts.TreeStructureId,
ts.LeftValue,
ts.RightValue,
tn.Name,
tn.TYPE,
tn.DATA ,
NULL AS [Description],
NULL AS DateChanged,
tn.UserId
FROM TreeStructures ts
JOIN TreeNodes tn ON ts.TreeStructureId = tn.TreeStructureId
WHERE ts.TreeStructureId IN (SELECT TreeStructureId FROM #TempTreeStructures) AND
ts.TreeStructureId <> (SELECT TOP 1 TreeStructureId FROM #TempTreeStructures) AND
tn.TreeNodeId = (SELECT TOP 1 tn2.TreeNodeId FROM TreeNodes tn2 WHERE tn2.TreeStructureId = ts.TreeStructureId ORDER BY tn2.DateChanged DESC)

could be replaced by this one

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
;WITH TreeData (TreeStructureId, LeftValue, RightValue, TreeId)
AS (
SELECT TOP 1
TreeStructures.TreeStructureId
, TreeStructures.LeftValue
, TreeStructures.RightValue
, TreeStructures.TreeId
FROM TreeStructures
WHERE TreeStructures.TreeId = @TreeId
AND TreeStructures.LeftValue = @RootLeft + 1
UNION ALL
SELECT
TreeStructures.TreeStructureId
, TreeStructures.LeftValue
, TreeStructures.RightValue
, TreeStructures.TreeId
FROM TreeStructures
INNER JOIN TreeData ON TreeStructures.LeftValue = TreeData.RightValue + 1
WHERE TreeStructures.TreeId = TreeData.TreeId
)
SELECT TreeStructures.TreeStructureId,
TreeStructures.LeftValue,
TreeStructures.RightValue,
TreeNodes.Name,
TreeNodes.TYPE,
TreeNodes.DATA ,
TreeNodes.Description,
TreeNodes.DateChanged ,
TreeNodes.UserId
FROM TreeStructures
JOIN TreeNodes ON TreeNodes.TreeStructureId = TreeStructures.TreeStructureId
WHERE TreeNodes.TreeNodeId = (
SELECT TOP 1 tn2.TreeNodeId
FROM TreeNodes tn2
WHERE TreeStructureId = TreeStructures.TreeStructureId
ORDER BY DateChanged DESC
)
AND TreeStructures.TreeStructureId = @RootTreeStructureId
UNION ALL
SELECT TreeData.TreeStructureId,
TreeData.LeftValue,
TreeData.RightValue,
TreeNodes.Name,
TreeNodes.TYPE,
TreeNodes.DATA,
TreeNodes.Description,
TreeNodes.DateChanged ,
TreeNodes.UserId
FROM TreeData
JOIN TreeNodes ON TreeNodes.TreeStructureId = TreeData.TreeStructureId
WHERE TreeNodes.TreeNodeId = (
SELECT TOP 1 tn2.TreeNodeId
FROM TreeNodes tn2
WHERE TreeStructureId = TreeData.TreeStructureId
ORDER BY DateChanged DESC
)
ORDER BY LeftValue
;

I’ll have to read some more on it to fully understand its capabilities.

thx, Lieven Cardoen

Peformance issues IIS7, WebORB, Network, …

Two weeks ago I had a lot of problems in a project of mine. Often some clients couldn’t connect to weborb.aspx (actually 0.01% of the times). After a lot of searching we weren’t really able to find the problem. It seemed to me that maybe it was a network issue. The customer had just changed a lot of servers and improved their network. What previously worked didn’t seem to work anymore now.

We changed some things after which everything started to work smoothly again:

- When an error is thrown from the server or there’s a network problem we invoke the server call again with Credentials. We use authentication, so if at a certain moment in time IIS decides to recycle, the next calls to the server will fail. So we implemented a fallback system. If a fault occurs we authenticate again and try the call a second time. If the second time would also fail, then we give the user an Alert with some information what to do.

- When profiling SQLServer2008 we saw that there were millions of logs being written to the database by WebORB. We had configured WebORB logging with Log4Net and set the Filter in Log4Net on INFO. Basically everything that was logged was written to the database. This meant a lot of overhead. After having put the Filter on Warning connections to database reduced by a factor 100.

Configuring WebORB Logging with Log4Net (in global.asax):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
     void Application_Start(object sender, EventArgs e) 
    {
        log4net.Config.XmlConfigurator.Configure();
        log4net.ILog log = log4net.LogManager.GetLogger("Global.asax");
        log.Info("Application_Start(" + sender.ToString() + ", " + e.ToString() + ")");
 
        //Configuring WebORB Logging with Log4Net
	try
	{
		Weborb.Util.Logging.Log.addLogger("log4NetLogger", new Edu3.Util.Logger());	
                Weborb.Util.Logging.Log.removeLogger("default");
	}
	catch (Exception exception)
	{
		log.Error("Application_Start", exception);
	}
    }

- We profiled IIS7 with some tools that were proposed on StackOverflow. These tools were very interesting, but still I thought to get much more information. Strange that there’s not a professional profiling tool for IIS7. We used Administration Pack for IIS 7.0, the stackoverflow question is at link. The strange thing was that in 0.01% of the requests a 404 was returned. Even after having enabled Failed Request Tracing in IIS7, I couldn’t find the reason for the 404.

- Recycling happens automatically @ 23 hours. (this was allready done earlier when I had problems in November).

After these tweaks everything is working fine again. Those 404′s remain a mystery…

Ciao, Lieven Cardoen

A sort of Subset Union

1
2
3
4
5
6
7
8
9
SELECT A.UserId
FROM
(
      SELECT UserId FROM Users WHERE Email LIKE '%.com'
) A,
(
      SELECT UserId FROM Users WHERE Email LIKE '%er%'
) B
WHERE A.UserId = B.UserId

Result A:

10059
10060
10061
10062
10063
10082
10058
10088
10089

Result B:

10059
10063
10087
10089

Result query:

10059
10063
10089

If there are other ways to acomplish this, please let me know.

Lieven Cardoen aka Johlero

Rounding Up 2008

I started this year by taking over the lead of a big project for the Belgian government. The project is an e-learning environment created mainly with Flex, WebORB, .NET, MSMQ and MSSQLServer 2005. Daily hundreds of candidates go to Brussels were they are being tested by our software. Typically some 300 candidates start off at the same time to take a test.

So what have I learned this year (some of the things ;-) ):

Database

  1. Indexes are very important because they can speed up things a lot. However they can also be misused!!! So read about them.
  2. Stored Procedures made it easy to quickly write logic (transaction scripts). However it’s hard to maintain these Stored Procedures and Cache dependencies don’t work with complex Stored Procedures.
  3. MetaData was a very usefull mechanism to add new logic in Flex without having to change table designs.
  4. We also used MetaData for tags which wasn’t the best choice.

.NET

  1. I didn’t have a lot of experience in the beginning of this year so things kind of moved in the direction of Transaction Scripts. They aren’t a bad choice but as the project gets complexer, transaction scripts are difficult to maintain.
  2. SubSonic (o/r mapping tool) did it job very good but I’m not very pleased with the lack of documentation, tutorials and clear explanations. I will certainly look into nHibernate and Entity Framework and see how they work with some of the patterns described in ‘Patterns of Enterprise Application Architecture’ by Fowler. In the future the project will certainly need to be scalable so things will have to change.
  3. Visual Studio is a great IDE.

IIS and ASP.NET

  1. By default IIS recycles application pools every 29 hours (will come back to that later because this caused a lot of problems).
  2. HttpHandlers are great.
  3. Cache is a very important feature if you want to speed up your application.

Flex

  1. Very good choice for our client side development. Application development however is far more complex than writing web pages in .NET. If you need your code to be maintainable you need to know about design patterns, frameworks, refactoring, architecture, … Those things are mainly things you learn after having used them a couple of years.
  2. We now work with modules but in the future we will have to check out those shared libraries as well. Our application is now 2mb big so some kind of intelligent caching will be needed.
  3. Prana is great to configure your application externally. Check it out!
  4. The Flexbuilder Eclipse Plugin is a waste of memory and I hope Adobe tries to improve this in the future. Building our project takes far too long.
  5. Resource bundles could be made easier.
  6. Designing a Flex application is a hard thing because you really need a designer who knows some basic things about Flex.
  7. Implementing Pessimistic Concurrency with Messaging was a very hard one this year!
  8. Looking forward to create a desktop application version of our project.

WebORB

  1. Great product. FluorineFX is the open source alternative, but WebORB has a lot more features. Without a support plan however some things are really hard to debug.
  2. Authentication and Authorization is worth to take a look at, but it’s important to fully understand it.
  3. WebORB messaging integration with MSMQ is great to let other applications know what’s happening.

Other tools that have been very usefull are CvsDude, Trac, Mylyn, SubVersion, Charles, SQL Compare, SQL Data Compare, ant, cruisecontrol, Linq, SilverLight (very promising), Spring,…

Ciao!

Change Location MSSQL2005 Db files Security problem

Last week I changed the location of all my database files to an external harddisk. You can easily do this by detaching databases.

However, after having moved and attached the files again, SQL server wouldn’t load the files…

After some searching I found that you need to add a group to the security tab of the db files.

On my computer this group is called SQLServer2005MSSQLUser$TLV-EDU-LIC$SQL2005. You can easily go and check the security on the original folder to find out the correct name.

After I added this group and gave it full control, my db’s were up and running again.