Thursday, September 29, 2011

Gettin' Loopy Wtih Table Variables

It's midnight on a Wednesday and I can't seem to get to sleep. So what do I want to do? Code.

So let us engage in a little SQL exercise. Suppose that we need to copy data from one table to another. A task like this, on its own, can be tackled with a single INSERT...SELECT query. For example:
insert into Employee(firstName, lastName,...,postalCode)
select firstName, lastName,...,postalCode
from EmployeeImport
For the sake of discussion, we'll refer to EmployeesImport as the table we need to copy rows from and Employees as their destination. Imagine that, instead of just copying the rows from EmployeeImport into Employees, we also need to generate a special hash value generated from the content of each row that's inserted into the Employees table. Top that off with the fact that this special index value can only be generated via a stored procedure and, voilĂ , you've now got an interesting situation on your hands. We can't use the simple INSERT...SELECT query like we did previously because. as we all well know, you can't execute stored procedures inline with SELECT queries. That means that we are going to need to iterate through each row of the EmployeesImport table and insert them one at a time into the Employees table. Here's one way I've seen this task accomplished:
declare @firstName varchar(50),
	@lastName varchar(50),
	@birthDt datetime,
	@addressLine1 varchar(100),
	@city varchar(80),
	@province varchar(80),
	@country varchar(80),
	@postalCode varchar(10),
	@hashKey char(10)


declare @err bit
set @err=0

begin transaction importEmployees
	-- Setup the cursor
	declare cur_employee cursor for
		select * from EmployeesImport
	open cur_employee
	fetch next from cur_employee
		into @firstName,@lastName,@birthDt,@addressLine1,@city,@province,@country,@postalCode
	-- Main cursor loop
	while(@@FETCH_STATUS=0) begin
		-- Generate the hash
		exec GetEmployeeHash
			@hashKey output
		,	@lastName
		,	@firstName
		,	@postalCode
		,	@birthDt
		-- Insert record into Employees table
		insert into Employees(EmployeeID,FirstName,LastName,BirthDt,AddressLine1,City,Province,Country,PostalCode)
			select @hashKey,@firstName,@lastName,@birthDt,@addressLine1,@city,@province,@country,@postalCode
		if(@@ROWCOUNT=0) begin set @err=1 goto RollBackTransaction end
		-- Retrieve the next record using the cursor
		fetch next from cur_employee
			into @firstName,@lastName,@birthDt,@addressLine1,@city,@province,@country,@postalCode	
	end
	-- Cleanup
	close cur_employee
	deallocate cur_employee
	
if(@err=0) commit transaction importEmployees
RollBackTransaction:
if(@err>1) rollback transaction importEmployees
Now there are a number of issues that I have with this code. For one, lines 21-22 show that the cur_employee cursor is fetching rows directly from the EmployeesImport table and not from a temporary table. This means that it will create locks against the table that can cause blocking issues for other queries that might be working against the same table. This can lead to performance degradation in high-volume environments. Not only that, but developers using cursors must always be mindful to de-allocate and close  any they've declare to avoid memory leaks. Personally, I prefer to avoid cursors at all costs as I've found them to be slow, tedious, and high on overhead.

So how would I solve the problem? Like this:
declare @err bit
set @err=0

declare @EmployeesTemp as table (
	RowID int identity(1,1),
	FirstName varchar(50),
	LastName varchar(50),
	BirthDt datetime,
	AddressLine1 varchar(100),
	City varchar(80),
	province varchar(80),
	country varchar(80),
	postalCode varchar(10)
)

insert into @EmployeesTemp(FirstName,LastName,BirthDt,AddressLine1,City,Province,Country,PostalCode)
select * from EmployeesImport

declare @firstName varchar(50),
	@lastName varchar(50),
	@birthDt datetime,
	@addressLine1 varchar(100),
	@city varchar(80),
	@province varchar(80),
	@country varchar(80),
	@postalCode varchar(10),
	@hashKey char(10)
	
declare @total int
declare @rowID int
select @total=count(*) from @EmployeesTemp
set @rowID=1 

begin transaction importEmployees

	while (@rowID<=@total) begin
		select
			@firstName=FirstName
		,	@lastName=LastName
		,	@birthDt=birthDt
		,	@addressLine1=AddressLine1
		,	@city=City
		,	@province=Province
		,	@country=Country
		,	@postalCode=PostalCode
		from @EmployeesTemp
		where RowID=@rowID
		-- Generate the hash
		exec GetEmployeeHash
			@hashKey output
		,	@lastName
		,	@firstName
		,	@birthDt
		,	@postalCode
		-- Insert record into Employee table
		insert into Employees(EmployeeID,FirstName,LastName,BirthDt,AddressLine1,City,Province,Country,PostalCode)
			select @hashKey,@firstName,@lastName,@birthDt,@addressLine1,@city,@province,@country,@postalCode
		if(@@ROWCOUNT=0) begin set @err=1 goto RollBackTransaction end
		-- Increment the loop counter
		set @rowID=@rowID+1
	end

if(@err=0) commit transaction importEmployees
RollBackTransaction:
if(@err>1) rollback transaction importEmployees
My solution presents a number of improvements over the previous. Instead of repeatedly querying against the source table, the needed data is cached in a table variable. I love table variables because, unlike temp tables, they are scoped to the execution of the stored procedure and are disposed automatically once execution is complete. While I'm using the table variable, I also don't have to worry about locks against the source table. Temp tables also work for the same purpose (for more on the difference between temp tables and table variables, see this excellent Stack Overflow post)

Another cool feature of my solution is that I don't need to maintain cursors in order to move sequentially though my data set. Because I used an identity column in the temp table, I can just increment my counter so that I know the next rowID I need to query. Overall, I find it much simpler to use table variables effectively than to remember the complexities of managing cursors correctly.

On the whole, 95% of the work that you'll ever need to do in SQL can and should be done using set-based queries. That's the whole point of using relational databases in the first place. But for the small minority of tasks that require row-by-row sequential processing, table variables are definitely the better alternative to cursors.

For a great article on cursor performance, check out the article "Performance Tuning SQL Server Cursors" by Brad McGee.

Wednesday, June 8, 2011

Introducing the "Spittin' Bits" Blog


So what is this blog all about? As they say where I come from, “lemme break it down fo ya”.

» The Name

The name of this blog, Spittin’ Bits, is what you get when you mix a slang word with software engineering terminology. On the one hand, there’s spittin’. In hip hop vernacular, spittin’ is what a rapper does when spontaneously rhyming on top of a melody or beat. If you have ever seen the movie “8 MILE” featuring rap artist Eminem, then you know how this works. A good rapper can spit’ a verse to a random beat in a matter of seconds. He will create artfully crafted phrases and clever puns out of thin air, drawing upon stories of past life experiences. Sometimes making you laugh and other times making you think, a good rap verse can educate the mind and move the soul with amazing efficiency.

On the other hand, bits
refers to the sequences of binary numbers, represented by 1’s and 0’s, that are used by computers to do whatever humans tell them to do. Every line of code in any piece of software I write boils down to bits. It is literally the only language that computers really “understand”. I often hear it said that there are only 10 types of people in the world: those who understand binary, and those who don’t. Anybody who wants to be a good programmer has to know how to spin those 1's and 0's!

So when I talk high-tech, I'm spittin' bits. When I'm writing code, I'm spittin' bits. I'm steppin' up to the metaphorical mic and makin' magic happen. That's how I get it done.

» The Purpose

Spittin’ Bits is about telling my story as a software engineer on my own terms and in my own words. While it’s true that I want this to develop into a solid programming blog, it’s not just about programming. Sure, this should be a place where you can find great commentary on patterns, practices, and good software design principles. And yes, I want to share the lessons learned over my career so that I can benefit someone else. My greatest desire is to show you how I have used all aspects of my life to transform from just another kid with a rough upbringing, to an accomplished software engineer. And I'm going to do it in a way that makes my story accessible to as many people as can be reached, whether geek or ghetto.

As an engineer, I will talk about writing efficient and robust code. As an ear-trained musician, I will show you how to recognize design patterns and teach you about how I use improvisation in my work. As a church boy, I’ll preach on developing good character and use examples from my upbringing to demonstrate the importance of ethical decision making. As a guy that grew up in a rough neighborhood, I’ll talk about how to be self-motivated, find positive influences, and about how to work with difficult people. And as a father and husband, I will share with you how I attempt to balance all the things that are important in my life beyond what I do between 9 and 5.


» The Audience

If you’re a tech head like me, then this blog is definitely for you. If you’re not, that’s OK. There will be plenty for you to enjoy as well. If you’re a teenager or a college student thinking about a career in software engineering, I am especially talking to you. In fact, anyone who doesn’t mind thought provoking conversation can find something on this blog that will resonate with them.

My name is Anthony Mays, and I hope you enjoy the Spittin’ Bits blog. And don’t worry, imma keep it real and represent ALL the way.

So wassup ya’ll, let’s get it!




Monday, May 30, 2011

From Ghetto To GitHub: A Software Engineer's Testimony

I would like to dedicate this first post of the "Spittin' Bits" blog to everybody that represents my hometown, the City of Compton. As an African American growing up in the 90’s in a place like Compton, where hope was at a deficit and gang violence a primary export, there weren't many success stories around for guys like me. It is my hope that I can give a voice to the bright and brilliant youth in every ghetto, hood, project, and barrio. The world will know that, in spite of all difficulties, we are here and are ready to usher in a new generation of success and accomplishment.

The story of my life preceding my success is not unique. Many of the youth that either grew up or are now growing up in impoverished neighborhoods like mine have been abused, bullied, abandoned, and sexually molested. They faced the threats posed by gangs and drugs on a daily basis just like I did. I had friends that succumbed to gang life. Even lost a couple who were killed blocks away from where I lived on Mayo St. Guys like me had the makings of a life that would lead, in many cases, to death or imprisonment. Worst of all, even working hard in school didn’t guarantee that I wouldn’t catch a stray bullet or end up in the wrong place at the wrong time. That was just the reality of growing up in Compton.

Fortunately for me, I ended up being adopted into the home of a loving couple who I came to know as my true mother and father. They fought hard everyday to ensure that I received the best education that Compton could offer. As a family we couldn’t afford much, and half way through my childhood, my father was laid-off from his job a year before his retirement was due. That didn’t stop them from ensuring that I had everything that I need to be successful later in my life. They instilled within me very high expectations which included attending and graduating from a four-year university and obtaining a respectable career. Without them, I would not have cultivated a love for technology and engineering.

Today, I am a Senior Software Engineer for Junction Solutions and a graduate of the University of California, Irvine. I've benefited from a career of over 6 years of industry experience, during which time I have been credited as co-inventor of a patent-pending method for processing bank transactions (US 2009/0037332 A1) while working as a programmer at City National Bank. I am also an INROADS alumnus and former Intern of the Year recipient in 2005.

I may have grown up in the hood, but that’s not what defines who I am. I believe that my work and my accomplishments will send a message to the world, however small, that investing in the young men and women of America’s most down and out communities does pay off. There are so many talented young men and women like me who can positively impact the world, but they can’t do it alone. That’s why I’m sharing my story with the hope that someone else may be inspired to invest in the education and development of minorities in business and technology.

Yeah, I used to live in the ghetto. Now I’m on GitHub. And as my dear, late grandmother once said, “may the work I’ve done speak for me”.