I had a client that was concerned about SQL Compare behavior when a developer adds a column to the middle of a table. I wanted to reassure them, so I wrote this post to show how SQL Compare behaves by default.
I want to add a column to this table, called ProductQtyPerUnit. However, I decide to add this before that StatusID column so all my product data is together.
Note: This shouldn’t be done. Don’t worry about order of columns. Deal with that in your INSERT/SELECT statements instead.
If I do this in the SSMS designer, I’ll right click the table and select INSERT Column.
Then I can add the column, as appropriate to my table.
Before I save this, I’ll create a scripts folder and compare things. As you can see, things are in synch.
Now I’ll save the change.
SQL Compare Behavior
Now I’ll refresh my project. When I do that, I see a difference, as I should. Note that SQL Compare detects the change, and shows the new column in the middle of the table.
I’ll click Deploy and generate the deployment script. When I do that, I see the script below. Note that SQL Compare has just added a column, not rebuilt the table.
This is controlled by the Force Column Order option, which is off by default. This is the way we’d like to have the tool behave, as rebuilding tables is unnecessary.
I’ll close this dialog and then click Edit Project and select the options tab. I can search for Force and see the option is off.
to show how this works, I’ll check the checkbox and then recompare. Now when I generate the deployment script, I see this. The deployment wizard opens to this warning.
If I view this script, you can see below that this part of the script creates a new table and then renames it after data is moved and the old table dropped.
In general, you should leave this option off all the time. The physical order of columns doesn’t matter.
If you haven’t used SQL Compare from Redgate, it’s the industry standard for SQL Server schema comparison and an amazing tool. Download an eval today and give it a try.
TDM was based on some existing technology, and incorporated a product that we were already selling, but it was an evolution based on our knowledge and experience that helps organizations build better software. We’ve had these products for a number of years:
data masking – Data Masker for SQL Server and Oracle
data generation – SQL Data Generator for SQL Server
classification – SQL Data Catalog for SQL Server
However, we didn’t want to just rebrand these, but rather attack the problem space in a new way. We especially wanted to be sure that our products would work across different database platforms.
The result is Test Data Manager, which includes these capabilities:
classification
subsetting
masking
data generation
database virtualization/cloning
Of these areas, only the last one (virtualization/cloning) uses an existing product, Redgate Clone. The rest of these are CLI driven brand new products designed to be put together to meet your needs. I’m particularly excited by subsetting (I wrote about this recently), as I think this is a boon to agility.
If you want to shift-left, empower your developers, and build better quality database software faster, check out Test Data Manager and get a demo scheduled.
I had a customer question whether Flyway Desktop (FWD) would cause problems if developers were adding columns into the middle of tables. It’s a valid concern, and this post shows that FWD doesn’t cause you issues, even if your developers do silly things.
Unless they want to do silly things.
I’ve been working with Flyway Desktop for work more and more as we transition from older SSMS plugins to the standalone tool. This series looks at some tips I’ve gotten along the way.
The Scenario
Imagine that you have a table with a few columns, like this one.
CREATE TABLE Product
( ProductID INT NOT NULL CONSTRAINT ProductPK PRIMARY KEY
, ProductName VARCHAR(50)
, ProductDesc VARCHAR(1000)
, ProductSize CHAR(1)
, ProductWeight INT
, ProductColor VARCHAR(20)
, StatusID int
)
GO
This table has the same structure in dev and prod, and I need to add a new column. We need a quantity per package as we have new products where there are multiple items in a box, so there is a need to add ProductQtyPerUnit to the table.
I decide that this needs to be before StatusID since it’s related to the other product description items, and I want them to be together. This is a good concept when designing entities, but it’s not worth doing when we have millions of rows in this table in production.
In the SSMS designer, I do this. I right click my table, click Design, the right click before StatusID and select Insert Column:
I then design my new column. Things look good.
Most developers would just save this change. However, if I were to click the Generate Change Script button, I’d see this (I leave out the SET stuff at the top).
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Product
(
ProductID int NOT NULL,
ProductName varchar(50) NULL,
ProductDesc varchar(1000) NULL,
ProductSize char(1) NULL,
ProductWeight int NULL,
ProductColor varchar(20) NULL,
ProductQtyPerUnit smallint NULL,
StatusID int NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_Product SET (LOCK_ESCALATION = TABLE)
GO
IF EXISTS(SELECT * FROM dbo.Product)
EXEC('INSERT INTO dbo.Tmp_Product (ProductID, ProductName, ProductDesc, ProductSize, ProductWeight, ProductColor, StatusID)
SELECT ProductID, ProductName, ProductDesc, ProductSize, ProductWeight, ProductColor, StatusID FROM dbo.Product WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.Product
GO
EXECUTE sp_rename N'dbo.Tmp_Product', N'Product', 'OBJECT'
GO
ALTER TABLE dbo.Product ADD CONSTRAINT
ProductPK PRIMARY KEY CLUSTERED
(
ProductID
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
COMMIT
This script essentially creates a new table, copies over data, then drops the old table before a rename. On a large table, this could acquire a number of locks and potentially cause errors or disruptions for clients. If I want deployments at any time, without causing downtime, this isn’t the script I want to run.
Flyway and Column Changes
If I do this in dev, assuming I don’t have millions of rows of data, I might not notice this. What about detecting this change in Flyway? Let’s see.
I have a Flyway project open in Flyway desktop and I’ll refresh the changes. As you can see, we detect this new column. As you can see, we detect the change, showing the insertion of the column into the middle of the table.
I can save this and then generate a migration script for this change. When I do this, I see this script. Notice that this script is unlike the SSMS script and just adds a column to the table.
This is the same behavior in SQL Compare. By default, we don’t want to rebuild tables and move data. We want to just add the new change to the system.
This is controlled by the Force Column Order option, which is off by default. We can see this when I look at the comparison options for the project.
I can check this and then re-generate the migration script. When I do that, we see this script. This one
The entire script is here:
PRINT N'Dropping constraints from [dbo].[Product]'
GO
ALTER TABLE [dbo].[Product] DROP CONSTRAINT [ProductPK]
GO
PRINT N'Rebuilding [dbo].[Product]'
GO
CREATE TABLE [dbo].[RG_Recovery_1_Product]
(
[ProductID] [int] NOT NULL,
[ProductName] [varchar] (50) NULL,
[ProductDesc] [varchar] (1000) NULL,
[ProductSize] [char] (1) NULL,
[ProductWeight] [int] NULL,
[ProductColor] [varchar] (20) NULL,
[ProductQtyPerUnit] [smallint] NULL,
[StatusID] [int] NULL
)
GO
INSERT INTO [dbo].[RG_Recovery_1_Product]([ProductID], [ProductName], [ProductDesc], [ProductSize], [ProductWeight], [ProductColor], [StatusID]) SELECT [ProductID], [ProductName], [ProductDesc], [ProductSize], [ProductWeight], [ProductColor], [StatusID] FROM [dbo].[Product]
GO
DROP TABLE [dbo].[Product]
GO
EXEC sp_rename N'[dbo].[RG_Recovery_1_Product]', N'Product', N'OBJECT'
GO
PRINT N'Creating primary key [ProductPK] on [dbo].[Product]'
GO
ALTER TABLE [dbo].[Product] ADD CONSTRAINT [ProductPK] PRIMARY KEY CLUSTERED ([ProductID])
GO
By default, Flyway isn’t going to try and rebuild your tables if developers add columns into the middle of a table. This is the recommended and preferred way of dealing with these changes. If your developers complain, then discuss the fact that we don’t need to worry about the physical order of columns in a table. If you want columns returned in a different order, do that in a query (and don’t use SELECT *).
If you really need tables rebuilt, you can check the option, but you shouldn’t do that.
Try Flyway Enterprise out today. If you haven’t worked with Flyway Desktop, download it today. There is a free version that organizes migrations and paid versions with many more features.
If you use Flyway Community, download Flyway Desktop and get a GUI for your migration scripts.
malotype– n. a certain person who embodies all the things you like the least about yourself – a seeming caricature of your worst tendencies – which leave you feeling repulsed and fascinated in equal measure, having stumbled on a role model of exactly the kind of person you never want to be.
One of my hobbies is coaching volleyball for kids, teenagers really. This year I’ve taken on 13 year olds, and helping out with an 18 year old team as their coach is out for a few weeks. It’s been an interesting dichotomy, and I’ve now helped coach all ages from 13-18.
In the eight years I’ve been coaching, I’ve worked with, and watched a number of coaches. In that time, I’ve seen a few that are polar opposites of who I try to be. One in particular that was very good at understanding the game, knew all the rules, and recognized things to exploit in opponents.
However, this person was not good with players, in my opinion. Harsh, unapproachable, didn’t listen to concerns, didn’t provide support, belittled (my opinion) players, and demanded too much.
I can be loud, and I’ve been short with players at times. I try not to do that often, and I try hard to support them to help them grow, accepting their fallibilities while pushing them to grow and change. A number of players have said they would never want to be near that coach again and one quit a time.