SQL Server Licensing is Simple

Over the years I’ve had no shortage of licensing questions for SQL Server. At times it’s felt a little crazy. Look at the licensing guide. Choose EE or SE and the number of cores. Then check if you’re using VMs. Oh, and consider the cloud, and which cloud you’re running a workload on.

It’s simple right?

It can seem confusing, and at times I’ve wished Microsoft would make it simpler. And perhaps even give us some add-ons, like adding some additional hardware capabilities (cough more RAM *cough) in SE.

Then I run into something like the introduction to Oracle licensing. This is one of the smaller guides on a site devoted to Oracle licensing. There are numerous articles on there, with lots of information, perhaps too much, to help anyone get a handle on this process. There are even companies (one, two) built around helping you manage Oracle licenses.

There’s a core factor table, where you need to figure out how to adjust your “license cost” based on the CPU. That’s after you pick the edition, and likely before you go into the other features you might need. I’m guessing this is why a lot of people might just pay for the Unlimited license and stop worrying. I think this is also why Oracle is still such a huge company and worth billions (or trillions?) of dollars.

I actually asked Claude to help me with Oracle licensing. I got these (partial) results, which talks about the different core licensing, editions, and then other costs. As I ask for more details in any area, this gets very complex and confusing. While some of the rules for SQL Server can be confusing, and certainly the HA and virtualization guidelines sometimes leave something to be desired, overall, I find things simple.

I like simple.

Over the years, many software companies have made licensing more complex and confusing to customers. Often this results in more profit for them without much benefit for the purchaser. Not all vendors do this, but Oracle certainly has created a complexity that spawned a whole business model for a few companies. SQL Server licensing is simpler, and I’ve learned to appreciate that.

Steve Jones

Listen to the podcast at Libsyn, Spotify, or iTunes.

Note, podcasts are only available for a limited time online.

Posted in Editorial | Tagged | 3 Comments

Database Collation Matters for Unicode: #SQLNewBlogger

While trying to work with Unicode data, I found some issues with collation. This post showcases what I’ve seen, with probably not enough answers. The collation/UTF stuff is still slightly confusing to me.

Another post for me that is simple and hopefully serves as an example for people trying to get blogging as #SQLNewBloggers.

Noticing Problems

I was doing some testing with Unicode data and noticed this sentence in the docs for UNISTR() (image below): “The database collation must be a UTF-8 collation if the input is of char or varchar data types.

2025-12_0088

I started experimenting with SQL 2022 with a default, US database. I ran this code:

SELECT N'Denver ' + NCHAR(0x1F601), DATABASEPROPERTYEX('sandbox', 'Collation')

That gave me unexpected results. The inputs aren’t char or varchar. They are NCHAR.

2025-12_0089

Strange. I’d have expected this to work. Let’s try the COLLATE clause. That should help.

It doesn’t.

2025-12_0091

One Solution

I decided to create a new database to test things. First, I ran this code to create a database using a UTF-8 collation:

CREATE DATABASE UnicodeTest COLLATE Latin1_General_100_CI_AS_SC_UTF8

Next, I tried my test. Same code as above, different database.

2025-12_0093

This works. I see my Unicode characters.

Why, I’m not sure. I would think that my requesting a collation for a query would work, but I see this in the docs, which notes this is for ORDER BY.

2025-12_0094

In the Write International T-SQL Statements doc, there is this:

2025-12_0095

I’m not sure what UCS-2 means when I’m querying in memory only, but apparently this matters.

An Explanation

The real answer is found in the NCHAR() docs. In here, the arguments section notes this:

2025-12_0096

The key is the Unicode value. NCHAR() handles up to 0xFFFF (4 Fs). My value is 0x1F40E (5 characters), so it’s out of range for the values that are handled with a non SC collation.

If I return to my Sandbox, non SC collation database, I can get Unicode characters, as long as they are below the FFFF threshhold.

2025-12_0097

A fun little experiment, where I learned something.

SQL New Blogger

This is a great example of my finding a problem, digging in, and solving it. Around some other work, this probably took me about 30 minutes to figure out with some reading and experimenting. Then about 15 minutes to write this post.

This is something you could easily do and showcase your knowledge as someone looking to learn and grow.

Posted in Blog | Tagged , , | Leave a comment

Don’t Let Corner Cases Drive Your Design

If you graph computer/query cost against the size of data, you can get four quadrants:

  1. small data, small compute (most CRUD app queries)
  2. small data, big compute (complex BI queries for this quarter, most reporting)
  3. big data, small compute (logs, audit data)
  4. big data, big compute (complex BI queries across all our data)

If you examine the costs here, 1 is the cheapest, with 2 and 3 having a similar cost. Number 4 is expensive, and it’s why we often have big boxes running our database server software. However, where is most of our work? The majority is in quadrant 1, with 2 getting the second most action. 3 might rarely exist, as does 4, but we often design for 4. We have to as we don’t want phone calls, ever. What we want is to provision a system large enough that we don’t hear many complaints about performance. On premises, many of us have over-provisioned systems to handle the peak load to avoid phone calls.

Can we handle the peaks or the really important things that someone thinks are important? Everyone thinks their workload is important, and it is. To them. However, there are plenty of cases where someone could think about designing for specific types of workloads, rather than just aiming for quadrant 4. I’ve got an image of different types of workloads that I grabbed from the Small Data 2025 conference. For example, if I am working with things like Time Series data or streaming analytics, I might not need huge compute. I might be storing a lot of data, and I need space, but the compute is low. The analysis of that data, however, might be compute intensive.

This is a reason why we might separate analytic systems out as they often are in quadrants 2 and 4, and we might want serverless or scale up/down systems to handle the rare cases, and get a real cost for them. I found it particularly interesting that the Bronze tier might be where we have big data and big compute, but once we’ve moved to Silver or Gold, we might have lower compute and data requirements. This makes sense as Bronze is more staging, but it is a good reason why we might aim for a Gold layer in our organization and only keep that data for the long term; it’s more cost-effective.

Often, for simplicity, we build a bigger system for all types of queries. In other words, we are letting corner cases drive our design. That might be required, but it might not be. In this area of cost concerns, especially in the cloud, designing systems with appropriate resource usage is something that might override the analyst’s desire for queries across all data running as quickly as order lookups in an OLTP system. This might be even more true if we can predict some patterns in our workloads during system design. We can’t scale up or down instantly, but in a lot of places, I wish I had been able to scale financial or reporting systems up for a few days as we close out the period and scale them down for the rest of the month.

When building a system, think about the practical nature of your requirements and assign a cost to them. Let users know what workload you’re building a system to handle and set expectations on performance and cost. If you do that, you can let others decide when we handle corner cases and when we don’t. That’s often a much easier conversation when we have cost numbers to help customers understand the implications of their request.

Steve Jones

Listen to the podcast at Libsyn, Spotify, or iTunes.

Note, podcasts are only available for a limited time online.

Posted in Editorial | Tagged | Leave a comment

Reverse Engineering a Physical Model Diagram

I recently wrote about a logical diagram with Redgate Data Modeler. That was interesting, but creating all the objects is a pain. I decided to try creating a physical diagram from an existing database. This post looks at the experience.

This is part of a series of posts on Redgate Data Modeler.

Getting Started

As with the logical model, I right click and choose New document.

Then I get a list of options. I’ll choose the middle one, Physical Model. This is what I mostly need to work with an existing system. Since I don’t often move models from one platform to the other, a physical diagram can work well for me.

2025-11_0143

Once I click next, I get a list of platforms, and I need to enter a name. I’ve done that. Notice that when I select SQL Server, I can alter the drop down for different versions of SQL Server.

2025-11_0145

Below this, I see a source box, and a file picker.

2025-11_0146

I need a file.

I’ll go to SSMS and right click my database. I’ll find the Generate Scripts task, as shown below.

2025-11_0147

I go through the wizard and mostly pick defaults.

2025-11_0183

I do script to one file, not separate ones. I choose all objects.

2025-11_0184

Back to Data Modeler with the file. I select this and upload it and see…an error.

2025-11_0185

When I open the script, I see lots of non-database stuff.

2025-11_0186

I’ll delete this stuff and also a bit at the bottom. I rename this to Westwind.sql, which is what I am importing. Then I was able to import the file and when I clicked “Start modeling”, I ended up with this:

2025-11_0215

Redgate Data Modeler (RDM) has detected quite a few relationships. You can see them in the diagram for the explicit ones defined. If I click one, such as the Order to Order Details item, I can see on the right that this is for OrderID in both tables..

2025-11_0216

One thing that threw me slightly was two Employees tables. I was wondering what was going on here, but when I clicked the lower one and looked through properties, I can see that this is for a different schema. I wish this were more visible, but it did get detected.

2025-11_0217

Cleaning up the Design

One of the things I like is that I can set areas in the model. This lets me organize things and even convey information to developers and others that work with the database.

At the top left, I have a series of icons. The last one on the right is the New Area icon. I’ll click this.

2025-11_0218

I can now draw an “area” somewhere. Notice the right when I do this. I have properties for this area.

2025-11_0219

I’ll add a name and change the color, which gives me way to easily see this area in my diagram. I’ll also drag in the Auditing.Employees table, as this is what I want people to know.

2025-11_0220

I can select this and move it (look at the video) and then I see this as a part of my diagram, but clearly separate from other parts. Developers can learn the light red is the auditing schema, which is separate from the rest of the diagram.

2025-11_0221

I can add other areas, not just for schemas, but for separating out parts of my database. Often I have a series of entities that I care about, or want to cluster together, and having areas with colors lets me separate these out.

2025-11_0222

I might run out of colors in a large database, but I could use lots of pale blues or grays to separate out areas, each of which has a name. That can be helpful to reduce the complexity of the model.

Adding a New Table

I can also add a new table if I want. One of the icons at the top is for new tables.

2025-11_0224

When I click in the model, a new table appears. The right opens up the properties with a default name (table14). I can change this and add the columns I need.

2025-11_0225

Once I’ve finished, I can add a relationship. There is an icon for this.

2025-11_0227

I’ll click this and then click and drag from Products to Discount. This gives me a new column in Discount by default, called Products_ProductID. Not a bad name, but in general I want a cleaner name. I’ll edit the relationship to use ProductID in both tables and delete the other column from the model.

2025-11_0226

Modeling with an image is a good way to start to visualize how things are setup and where you might be normalizing, or denormalizing data. I also want to know just how many things are in here and what is related to what.

Moving Forward

There are more things that can be done with tools like that to help ensure our databases are well designed and perform well. I’ve submitted feedback to the team and asked for some enhancements.

One of the things I might want to do from here is update my dev db from the model. I’ll show that in a future post.

For now, I like the idea of getting a model started from my SQL script, though clearly I need a clean script. I’ll do more testing with other scripts for both forward and reverse engineering.

Give Redgate Data Modeler a try and see if it helps you and your team get a handle on your database.

Posted in Blog | Tagged , , , | 1 Comment