Saturday, April 2, 2011

The Good, The Bad and The Ugly of Metadata Management

Introduction
The simplest definition of Metadata would be 'data that describes other data'. It adds context, meaning and understanding to the data being described. Database\Data warehouse projects often have some form of metadata management associated with them. Metadata management in simple terms would be the continuous process of maintaining metadata (adding, updating, other maintenance activities based on the form of metadata storage). An example of metadata management would be during the data modeling phase where the entity and attribute definitions are maintained by tools such as Erwin, ER studio, etc.
For the scope of this blog I will confine myself to the boundaries of technical metadata discussion (specifically to data dictionary metadata).
Metadata can be broadly classified into three types:
1. Business Metadata: This metadata defines and describes the actual data existing in the database or data warehouse in a business sense. Ex: The column Quantity in table Orders refers to the total number of orders placed by a customer in a day.
2. Technical Metadata: This metadata stores information about the technical aspects of the data for objects like tables, columns, data types, data profiling, etl objects and so on. This typically is called the data dictionary (or System Inventory).
An example of data dictionary metadata would be Microsoft SQL Server’s metadata storage; SQL Server stores data about user objects and system objects (pertaining to SQL Server) in a set of system databases – ‘master’, ‘model’ and ‘msdb’. The master database stores data about all the user objects (which include tables, indexes, constraints, stored procedures, functions, views, etc.) in a set of internal system tables. Ex: sysobjects, syscolumns, sysconstraints and other tables brilliantly exposed by INFORMATION_SCHEMA views. Note: These system tables also store data about themselves.
3. Process Execution Metadata: Data about the actual execution of the ETL processes – like performance statistics, rows transferred, transfer duration, errors\exceptions encountered, logging etc. In a way 3 is also technical metadata, but I like to branch it under a separate category due to the nature of the data.
The Why?
The ‘why’ of this blog is to (try to) understand the impact of purpose & use of the metadata stored in the metadata repository. Also will discuss the reasons for aligning your repository design with the purpose of metadata. Just to be clear I myself am a big supporter of introducing metadata in the overall architecture of a system and also to an extent on metadata driven architectures. The buck stops at the realization point when the effort being invested in “making it work” is more than the “actual work” itself.
Now that we have a fairly good enough understanding of what metadata is and its different forms of storage, lets move on to a case of building metadata solution for a database migration project.
The (Client’s) Treasure
Let us consider a case of designing a new enterprise data warehouse project and also a metadata solution which is an integral part of this effort. (I am relating this to a project that I worked on in the past where I had approximately one thousand DB2 tables which needed a transfer to SQL Server database at a major automobile dealership chain sharing some experience). Situation: Create a daily load from DB2 tables into the new SQL Server data warehouse. Assuming that our solution has the ETL part (SSIS) and also the reporting and analysis piece (SSAS and SSRS) to it, we come up with a metadata repository (a common sql server database) for the logging and auditing framework for the ETL components (process metadata), a key value pair storage structure for column definitions, ETL object definitions, report definitions, etc. (a common structure for business and technical metadata for specific work identified above).
The Good
From the descriptions of the types of metadata being stored the purpose can be inferred as operational statistics\reporting (of scheduled jobs, ETL processes), business definitions of columns to serve as a data dictionary for years to come.
As long as the purpose and the use (at the most granular level) is specifically understood, the pursuit towards that type of metadata storage can be justified.
Now lets assume the creation of a raw or staging area for our warehouse where the table structures are going to be almost the same as that of the source and given that we have the metadata of the source system (table name, column name, data type, length, etc.) we should be able to create a similar structure in our SQL Server warehouse environment by writing some looping programming constructs to create all staging tables dynamically.
Wow, isn't that awesome? Brag time: I was able to create a ‘simple’ script that generated a staging area with whopping 1000 tables plus their keys. Manually doing it is just not feasible. Now let us compare the effort involved in creating the script\process that did the work (less than 4 hrs.) instead of manually creating each table which if you estimate is a lot of $$$ and not being smart (“making it work” vs. “actual work”).
The (Not so) Bad 
The maintenance and constant upkeep of metadata is the ‘not so bad’. The reason being that although it does end up taking time and effort to keep it up to date, but doing so keeps the metadata under check. There will be the occasional exception that will throw the metadata values out of whack an may cause your automated process to fail. Try to fix the metadata, not the process in this case. Example: some of the datatypes being sent by the DB2 metadata dump are mistyped as ‘datetimer’ instead of 'datetime’ (extra ‘r’ at the end causing the automated script to fail). This is a very simple example. Think of other instances where you are creating primary keys and foreign keys from the metadata. Sure, does seem like a good idea and indeed is if the metadata is in a structured format. And yes, the process can also be fixed or restructured to address this; but, a well defined and well know process already exists for something like this and it is called ‘Data Modeling’. This gets into the ‘Ugly part discussed below’.
Remember the purpose of the metadata store – it was just to serve as a data dictionary in the simplest form. The ability to do something extra out of it was a by-product.
The (Definitely) Ugly
The ability to script and generate the staging area was possibly only due to the well structured metadata from the DB2 system, but if it were not, then the effort would be different – spending countless number of hours to get the DB2 metadata in a “perfect” structure which could possibly take more time than the actual work of just creating the staging area manually one table at a time. The perfect structure would be to mimic the storage structures which SQL Server stores its metadata in a very normalized format that validate all the data being stored. This takes you on a quest for finding a complex solution.
Your metadata repository structure does not have to be perfect, it just needs to serve its purpose. If you end up going down the path of making it absolutely right, then this is just over-engineering something simple.
The Summary
Remember that your metadata does not have to be a panacea (it is not, so try not to push too much toward making it one). Define the purpose of a certain piece of metadata, consider the administration\maintenance aspect that will be spent toward it and just drive toward achieving that purpose. There is a thin line between the bad and the ugly. As a continuous practice keep your metadata solution the ‘good’ or the ‘not so bad’ band and your metadata solution will have met its purpose.
The metadata you pursue will give you a lot of information and every time you work with the metadata repository created you will get newer ideas on using it for a number of things (possibly even fueling a rocket, watch out for such instances and prevent yourself from designing a rocket fueling system).
Do NOT let the the metadata implementation & management overshadow the actual system implementation and your immediate goals.
That is all I have for now. Thanks for reading.
Fun fact: The total number of time the word ‘metadata’ appears in this article = 50 :-)

Wednesday, February 2, 2011

Managing Database Code for Continuous Integration (Part 2 of 4)

Introduction
Part 2 (of 4 series) on Continuous Database Integration covers creating, managing and provisioning a database project for a continuous integration environment. I will be using Visual Studio 2010 to create a database project (.dbproj project) and for source control I will be using Subversion (open source). The usage of Visual Studio is mainly for the management of SQL scripts and (most importantly) for the deployment file that it generates, but you can do away with it and have a complete CDBI system setup in an open source environment. Most of the tools selected in this article to set up CI are free.
          If your environment extensively uses Team Foundation Server (instead of Subversion), and Application Lifecycle Management (ALM), you should look into setting up continuous integration with these tools before starting to look for free ones. If you are an open source shop (two thumbs up) or want to try out standing a CI environment on your own, read on.

This article is focused on the use of the SQL Server database project type in Visual Studio 2010. The SQL Server project type has ‘build’ and ‘deploy’ capabilities (along with a bunch of other features), which is the pivotal component of the CI setup. If you do not want to use VS 2010 Database Projects, and instead use a file system management based structure of hosting the database scripts; then, you need to manually create the re-runnable\deployable script (an OSQL or SQLCMD command script that executes all your deployable .sql scripts). Make sure you test this against a local instance of your database to emulate the build and deploy features. I created a custom C# console application that looks into specific folders (Tables, Stored Procedures etc.) and creates a command line batch script with error handling embedded in it (a custom deploy file generator was created as my project involved both oracle and sql server and I was working with Visual Studio 2005 .dbp project type), but with VS 2010 you get all these benefits plus the database testing, refactoring and it just plainly makes managing a database project much simpler (.dbproj project type).
Before we begin on the CI setup of the database project, download the following tools to set up the environment:
1.    Subversion – For source control of the database project. This is by far the best and most comfortable source control system I have worked with (Sorry TFS). After installing subversion and creating a repository, make a note of the repository location as you will need it to link your database project to that.
2.    Plugin for Subversion integration with Visual studio IDE (either one of the two)
       a. Visual SVN (Free to try, $49 per license)
       b. Ankh SVN (Free)

Visual SVN vs. Ankh
: I would recommend Visual SVN to a database centric shop that has heavy duty database development, SSIS, Reporting and\or SSAS solutions. I have had problems with Ankh SVN plugin to work correctly with these project types. It does not recognize these project types from the IDE and you end up managing them from the windows explorer instead of the commit\revert operations from the IDE. Visual SVN is much simpler to use, works perfectly with all types of project types that a database developer needs to work with. Yes, it does come with a price tag, but a license of $49 is dirt cheap. This was when I was working with Visual Studio 2005 integration. Things may have changed with Ankh since then, try it out and see what works best for your scenario.

3.    SQL Server SSMS Tools Pack: This is more of a helper plugin than a requirement. Helps you generate your seed data, save custom snippets as hotkeys, CRUD generator and more. Once you start using it you will want to get more. Download it here.

Database Project Setup
Once the prerequisite software is installed, open Visual Studio 2010 and create a new SQL Server 2008 project.

Database Project Type

For demo purposes I am creating (reverse engineering by importing an existing database during project setup wizard) a database project for AdventureWorks SQL Server 2008 database [If AdventureWorks sample database is not installed on your database server, it can be downloaded from CodePlex]. Complete the project setup by following the necessary steps as per your database configuration. Leaving them in their default settings is also fine for the moment.
Once the project setup wizard completes, the solution explorer should resemble the fig. below. Right click on the project name “AdventureWorks” and select Properties to bring up the project settings. Click on the ‘Build’ option to view the location of the deployment script. Select the ‘Deploy’ tab on the left to view the deployment settings.

AdventureWorks Deployment Options

Now that we have the project ready, Right click the project and select ‘Build’. The status bar should go from ‘Build Started’ to ‘Build Succeeded’ status. After the Build succeeds, deploy the project by Right clicking the project and selecting ‘Deploy’. This will create a deployment script named ‘AdventureWorks.sql’ (in the Visual Studio\Projects\YourProjectFolder \sql\debug). With the database project deployment, two options are available (for now leave it in its default state: 1).

1.    Create a deployment script (default)
2.    Create a deployment script and run it against a database.

Location of AdventureWorks.sql deployment script

The deployment script is the most important artifact for a successful CI system setup. This is a compilation of all the database objects belonging to your database project (including seed scripts, security etc.). After first time deployments, when a change is made to the database project, a script with the same name will be generated which will include the changes.
The next step is to add your project to Subversion source control. To version control your project, right click on the project and select ‘Add solution to subversion’. Select the repository path and add the project. And finally right click and Add files and then commit\check-in the solution. The project is now ready to be shared by anyone who has the correct setup as listed earlier.
 

Preparing artifacts for CI
An isolated database instance of SQL Server needs to be provisioned for continuous build and deploy of database scripts (tear-down and reinstall). This database should not accessible to developers to use for development or testing purposes. The sole reason for the existence of this database is to test the continuous deployment of a database on either code commits or regular intervals of time. This also serves as a sanity check of your end product at any point in time.
Visual Studio 2010 database project provides the tear-down and install script (tear-down = recreate database) on the right click and select deploy action. But, in a continuous integration environment we would like to have this file created automatically on every build scenario. This can be implemented using the VSDBCMD command. You could use VSDBCMD for just creating the re-runnable deployable script (with the /dd- command line option) or use it for creating and running the deployable script (with /dd+ option at command line). If you plan to use it just for creating the re-runnable deployable script, then the script needs to be executed by either ‘sqlcmd’ or ‘OSQL’ in any environment separately.

    Ideally, I would prefer using VSDBCMD just to create the deployment script and then handover the deployment script to the DBA specifying the parameters (documenting them in an implementation plan of the database). The DBAs are familiar with sqlcmd\OSQL than VSDBCMD, plus using the VSDBCMD to execute the deployment script requires a bunch of assemblies (dll files) to be copied on the database server. I am not sure as to how the production DBA of today will accept this change. Thinking on the likes of a developer; sure, VSDBCMD is cool and you should definitely use in qa and production environments. But, in the real world scenario DBAs run the show. By just creating the deployable file in development and then running the same on QA and Production using sqlcmd you standardize your deployments and make your deployments simpler and worry free. (Did I mention that VSDBCMD also requires a registry change on the machine if Visual Studio is not installed on the machine, which is the database server?).
Not always a smooth ride; enter the obstacle: the hardcoded variables in the deployment file.

Hardcoded variables in Visual Studio deployment file
: Visual Studio deploy process creates three default parameters in the deployment file: DatabaseName, DefaultDataPath and DefaultLogPath. The ability to edit\override them is what makes the discussion of SqlCmd vs VSDBCMD interesting.
The main advantage with SqlCmd over VSDBCMD is the ability to pass variables as parameters to the deployment script from the command line. This is a big advantage as the VS DB project hardcodes the database name, data and log file path (mdf and ldf) in the deployment script (AdventureWorks.sql, see setvar commands below) and although there is a way to get around it, it is painful. 


:setvar DatabaseName "AdventureWorks"
:setvar DefaultDataPath "C:\Program Files\...\DATA\"
:setvar DefaultLogPath "C:\Program Files\...\DATA\"

Note: The above variables can be suppressed by editing the project deployment configurations. (This option can be used at runtime via command line params also).


At this point you have two options with sqlcmd: manually changing the DatabaseName and DefaultDataPath and DefaultLogPath variables in the deployment file, or use option two i.e. changing the variables on command line with ‘SqlCmd’ using the “-v” flag for variables.
Ex: sqlcmd –S -d master -v DatabaseName=“NewAdventureWorks” DefaultDataPath=“C:\Data\” DefaultLogPath=“C:\Data\”

If you decide to go with VSDBCMD for creating the deployment file and deploying to the database server, a workaround is required to make this work. Complete the following workaround steps (skip both steps if you are going to go with sqlcmd for qa & production deployments):
1.    Override the DatabaseName at runtime with the TargetDatabase command line option. Ex: /p:TargetDatabase="NewAdventureWorks". This will override the :setvar DatabaseName "AdventureWorks" to “NewAdventureWorks”.

2.    Overriding file path variables: Let’s get something straight first – ‘The variables DefaultDataPath and DefaultLogPath cannot be overwritten’. Microsoft has received requests for this and is planning to allow for overwriting in the next release of database projects. For now we will have to do with a workaround.

a. Right click on project ‘AdventureWorks’ and select ‘Deploy’. Edit the Sql command variables file by clicking the Edit button.



b. Add two additional variables ‘myDataPath’ and ‘myLogPath’ as shown below.


c.    In the database project, navigate to Schema Objects \Storage\Files and change the data file path variable in the AdventureWorks_Data.sqlfile.sql and the log file path variable in AdventureWorks_Log.sqlfile.sql to reference the newly created command variables.
-    Rename $(DefaultDataPath) to $(myDataPath)
-    Rename $(DefaultLogPath) to $(myLogPath)


d.    Right click and Build the project. Navigate to .\AdventureWorks\sql\debug (location of your project) and open the AdventureWorks_Database.sqlcmdvars with Notepad. The new variables will be available to change in here.


As you can observe from steps 1 & 2 above, the workaround for using VSDBCMD can be a bit painful. One other important thing to keep in mind is that VSDBCMD does not execute pre-prepared deployment files. This is also an item that the MS team is considering to change in the next iteration. To create a deployment package VSDBCMD needs the necessary assemblies, build files, manifest, sqlcommandvars file etc. to prepare the end product (deployment file) and run it. On the other hand sqlcmd is easier to run pre-prepared deployment files (like AdventureWorks.sql).

Creating the build package (build files) & executing the deployment output
For now, I am going to demonstrate creating the deployable file with VSDBCMD (minus steps 1 & 2 above) and deploying them on different environments with sqlcmd instead of using VSDBCMD.

The workflow of the continuous builds and deployments that we are trying to emulate is:
a. Clear existing deployable file: In the \sql\debug folder, delete the file AdventureWorks.sql.

b. Build the project: For now just right click and select “Build”. I will be using MSBuild to perform this task in the next article. Behind the scenes, when you right click and build, Visual Studio uses MSBuild for the build process to create the build files in \sql\debug folder.

c. Generate deployable file AdventureWorks.sql: Using the VSDBCMD command line tool on the integration machine and the database manifest file (AdventureWorks.deploymanifest) to generate the deployment file “AdventureWorks.sql”

Before trying out this step, make sure VSDBCMD is installed on your integration machine.
-    If Visual Studio is not already installed, then follow the instructions here to download and install VSDBCMD.
-    If Visual Studio is already installed (VSDBCMD is located in “C:\Program Files\Microsoft Visual Studio 10.0\VSTSDB\Deploy”), make a reference to it by adding it to your PATH variable in environment variables (instead of copying the files).

Execute the following command in the \debug\sql folder from command prompt: 

VSDBCMD /dd:- /a:Deploy /manifest: AdventureWorks.deploymanifest


The /dd- ensures that a deployment script ‘AdventureWorks.sql’ is generated and is not executed against the database server.

d.    The output of step above (AdventureWorks.sql) is executed against the integration database instance. Execute AdventureWorks.sql using ‘sqlcmd’ to test out the deployment.

Sqlcmd –S -d -E –i -o -v DatabaseName=“DefaultDataPath=“DefaultLogPath=“

Ex: SqlCmd –S myServer -d master -E –i C:\AdventureWorks.sql -o C:\LogOutput.txt -v DatabaseName=“NewAdventureWorks” DefaultDataPath=“C:\Data\” DefaultLogPath=“C:\Data\”

Note: Variables set with –v parameters overwrite hardcoded variables set in the deployment script.

Summary
This completes our preparation of build items needed for setting up the database project for Continuous Integration. Not to worry, the steps above are for understanding the working knowledge of how the CI product (Hudson) is going to orchestrate the above steps on the server for us in the next part of this series. As far as the options go with selecting VSDBCMD for build or using it for both build and deploy, it depends on your environment. If you are flexible enough knowing the changes you have to accommodate to get VSDBCMD working in your environment, then go for it, otherwise just use it for build purposes on the build server to create the deployable product and use that going into the next environment phases (QA and Production).

The next part of the series deals with orchestrating the steps a through d above in a repetitive manner based on either code commit\check-in or regular intervals of time. This will be set up using free tools - Hudson and NAnt. The next article will explain in detail setting up Hudson as a CI server for Database projects and configuring NAnt tasks for the actual implementation. I will also take some time to discuss a proactive vs. a reactive CI setup and how that affects development. That’s all I have for now. Thanks for reading.