Database Creation — CREATE DATABASE, File Groups and Configuration

Creating a SQL Server database correctly from the start prevents configuration issues that are hard to fix later. Key decisions: recovery model (Simple vs Full — affects backup strategy and log file growth), AUTO_SHRINK and AUTO_CLOSE settings (both should be OFF in production — they cause performance problems), collation (affects string sorting and comparison), and compatibility level (affects which T-SQL syntax and query optimiser behaviour is available). The BlogApp database creation script establishes these settings explicitly rather than relying on defaults.

BlogApp Database Creation

-- ── Create the BlogApp database with explicit configuration ────────────────
USE master;
GO

-- Create only if it doesn't exist
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'BlogApp')
BEGIN
    CREATE DATABASE BlogApp
    ON PRIMARY (
        NAME         = N'BlogApp_Data',
        FILENAME     = N'C:\SQLData\BlogApp.mdf',   -- explicit file path
        SIZE         = 128MB,                         -- initial size
        MAXSIZE      = UNLIMITED,
        FILEGROWTH   = 64MB                           -- grow in 64MB chunks
    )
    LOG ON (
        NAME         = N'BlogApp_Log',
        FILENAME     = N'C:\SQLData\BlogApp_log.ldf',
        SIZE         = 64MB,
        MAXSIZE      = 2048MB,
        FILEGROWTH   = 64MB
    );

    PRINT 'Database BlogApp created.';
END
ELSE
    PRINT 'Database BlogApp already exists.';
GO

-- ── Configure database settings ────────────────────────────────────────────
ALTER DATABASE BlogApp SET RECOVERY SIMPLE;       -- Simple for dev (Full for prod)
ALTER DATABASE BlogApp SET AUTO_CLOSE OFF;         -- Keep DB open (do not unload from memory)
ALTER DATABASE BlogApp SET AUTO_SHRINK OFF;        -- Never auto-shrink data files
ALTER DATABASE BlogApp SET AUTO_CREATE_STATISTICS ON;  -- Let SQL Server manage statistics
ALTER DATABASE BlogApp SET AUTO_UPDATE_STATISTICS ON;
ALTER DATABASE BlogApp SET COMPATIBILITY_LEVEL = 160;  -- SQL Server 2022 level
GO

-- ── Verify the database configuration ─────────────────────────────────────
SELECT
    name,
    recovery_model_desc,
    is_auto_close_on,
    is_auto_shrink_on,
    compatibility_level,
    collation_name,
    state_desc
FROM sys.databases
WHERE name = 'BlogApp';
GO

-- ── Create application login and user ─────────────────────────────────────
USE master;
GO

-- Create SQL Server login (if it doesn't exist)
IF NOT EXISTS (SELECT name FROM sys.server_principals WHERE name = N'blogapp_user')
BEGIN
    CREATE LOGIN blogapp_user WITH PASSWORD = N'BlogApp_Str0ng!Pass#2025';
    PRINT 'Login blogapp_user created.';
END
GO

-- Create database user for the login
USE BlogApp;
GO
IF NOT EXISTS (SELECT name FROM sys.database_principals WHERE name = N'blogapp_user')
BEGIN
    CREATE USER blogapp_user FOR LOGIN blogapp_user;
    -- Grant data read/write (application permissions)
    ALTER ROLE db_datareader ADD MEMBER blogapp_user;
    ALTER ROLE db_datawriter ADD MEMBER blogapp_user;
    -- Grant DDL for EF Core migrations (remove in production if migrations run separately)
    ALTER ROLE db_ddladmin   ADD MEMBER blogapp_user;
    PRINT 'Database user blogapp_user created.';
END
GO
Note: AUTO_SHRINK = OFF is critical. When AUTO_SHRINK is on, SQL Server periodically compacts the database file by removing unused space — then immediately re-grows it as data is added again. This shrink/grow cycle causes severe fragmentation and I/O overhead. The database file size should be planned based on expected data volume and grown manually (or via FILEGROWTH) as needed. Never let SQL Server automatically shrink data files.
Tip: The recovery model determines how much data can be recovered after a failure. SIMPLE recovery: transaction log is automatically reused (no log backups needed), but recovery is limited to the last full backup. FULL recovery: transaction log is preserved until backed up, enabling point-in-time recovery. Use SIMPLE for development (minimal log file growth) and FULL for production (maximum recovery options). With FULL recovery, implement regular transaction log backups or the log file grows unboundedly.
Warning: On LocalDB and Express, specify the database file path explicitly if you need to know where the files are — otherwise they are created in a default location that varies by installation. On a production server, always place data files (.mdf) and log files (.ldf) on separate physical drives for performance: data files on a fast NVMe SSD, log files on a separate SSD or RAID array. Mixing data and log files on the same physical drive causes write contention under load.

Common Mistakes

Mistake 1 — Setting AUTO_SHRINK = ON (causes fragmentation and performance degradation)

❌ Wrong — AUTO_SHRINK enabled on production database; SQL Server constantly shrinks and re-grows files; severe I/O overhead.

✅ Correct — always ALTER DATABASE X SET AUTO_SHRINK OFF; manage file sizes manually with DBCC SHRINKFILE only when explicitly needed.

Mistake 2 — Using FULL recovery model without transaction log backups (unbounded log growth)

❌ Wrong — FULL recovery model on production but no log backups configured; transaction log grows until disk is full.

✅ Correct — either use SIMPLE recovery (less protection) or FULL recovery with scheduled transaction log backups every 15-60 minutes.

🧠 Test Yourself

A production database uses FULL recovery model but transaction log backups have never been configured. After 3 months, the server disk is nearly full. What is the most likely cause?