<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Database Best Practices - TheCodeBuzz</title>
	<atom:link href="https://thecodebuzz.com/category/database-best-practices/feed/" rel="self" type="application/rss+xml" />
	<link>https://thecodebuzz.com</link>
	<description>Best Practices for Software Development</description>
	<lastBuildDate>Tue, 13 Oct 2026 21:38:12 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://thecodebuzz.com/wp-content/uploads/2022/11/cropped-android-chrome-512x512-1-1-51x51.jpg</url>
	<title>Database Best Practices - TheCodeBuzz</title>
	<link>https://thecodebuzz.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>SQL Server Best Practices and Guidelines-2026</title>
		<link>https://thecodebuzz.com/sql-server-best-practices-guidelines/</link>
					<comments>https://thecodebuzz.com/sql-server-best-practices-guidelines/#respond</comments>
		
		<dc:creator><![CDATA[Izzy]]></dc:creator>
		<pubDate>Tue, 13 Oct 2026 21:38:05 +0000</pubDate>
				<category><![CDATA[Database Best Practices]]></category>
		<category><![CDATA[DBA]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server 2025]]></category>
		<category><![CDATA[T-SQL]]></category>
		<guid isPermaLink="false">https://thecodebuzz.com/?p=30819</guid>

					<description><![CDATA[<p>SQL Server best practices for 2022 and 2025: memory, MAXDOP, tempdb, security, backups and upgrades, with runnable T-SQL and C# examples.</p>
<p>The post <a href="https://thecodebuzz.com/sql-server-best-practices-guidelines/">SQL Server Best Practices and Guidelines-2026</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>This guide is a bookmarkable reference for developers and DBAs who run SQL Server in production. It is current for SQL Server 2022 and 2025, with runnable T-SQL, C# and Python examples. Many older checklists still repeat the &#8220;leave 4-6 GB or 10-15% for the OS&#8221; memory rule and give contradictory MAXDOP advice. They also skip the 2025 features, the current driver defaults and the upgrade pitfalls. These SQL Server best practices fix that.</p>
<p>It is different from the existing post, <em>SQL Server Best Practices for Developers and DBAs (2026 Guide)</em>. This one is organised by production concern: configuration, indexing and queries, transactions, drivers, security, backups, monitoring and upgrades. Each rule explains the why, states the trade-off and gives a command to verify the result. The guide ends with an anti-patterns table and a production readiness checklist.</p>
<p>Before you start, you need sysadmin access on a test instance and SSMS or sqlcmd. The .NET examples use <a href="https://thecodebuzz.com/connect-sql-server-database-insert-update-delete-sqlclient-csharp/">Microsoft.Data.SqlClient</a> and the Python examples use pyodbc. Support dates, build numbers and default behaviours are correct as of October 2026. Always test every change on a non-production copy first.</p>
<blockquote><p><strong>Version note:</strong> This guide targets SQL Server 2022 (latest CU27, 16.0.4295.3) and SQL Server 2025 (latest CU9, 17.0.5005.3), with Microsoft.Data.SqlClient v7.0.1.</p>
<p>&nbsp;</p></blockquote>
<p><strong>In this guide</strong></p>
<ul>
<li><a href="#sql-server-best-practices-at-a-glance">SQL Server Best Practices at a Glance</a></li>
<li><a href="#sql-server-configuration-best-practices-memory-maxdop-cost-t">SQL Server Configuration Best Practices: Memory, MAXDOP, Cost Threshold and tempdb</a></li>
<li><a href="#data-modeling-and-indexing-best-practices">Data Modeling and Indexing Best Practices</a></li>
<li><a href="#query-optimization-and-sql-server-performance-tuning-best-pr">Query Optimization and SQL Server Performance Tuning Best Practices</a></li>
<li><a href="#transactions-isolation-levels-and-optimized-locking">Transactions, Isolation Levels and Optimized Locking</a></li>
<li><a href="#connection-management-and-microsoft-data-sqlclient-best-prac">Connection Management and Microsoft.Data.SqlClient Best Practices</a></li>
<li><a href="#sql-server-security-best-practices-least-privilege-injection">SQL Server Security Best Practices: Least Privilege, Injection and Encryption</a></li>
<li><a href="#sql-server-backup-best-practices-high-availability-and-resto">SQL Server Backup Best Practices, High Availability and Restore Testing</a></li>
<li><a href="#monitoring-sql-server-wait-stats-extended-events-and-perform">Monitoring SQL Server: Wait Stats, Extended Events and Performance Counters</a></li>
<li><a href="#patching-and-upgrading-to-sql-server-2025-what-to-check-firs">Patching and Upgrading to SQL Server 2025: What to Check First</a></li>
<li><a href="#common-anti-patterns-and-sql-server-dba-production-readiness">Common Anti-Patterns and SQL Server DBA Production Readiness Checklist</a></li>
<li><a href="#key-takeaways">Key takeaways</a></li>
<li><a href="#faq">FAQ</a></li>
</ul>
<p>&nbsp;</p>
<h2 id="sql-server-best-practices-at-a-glance">SQL Server Best Practices at a Glance</h2>
<p>&nbsp;</p>
<p>This guide covers production best practices for SQL Server 2022 and SQL Server 2025, from instance configuration and indexing to security, backups, monitoring and upgrades.</p>
<p>&nbsp;</p>
<p>The table below is a quick reference for developers, architects and DBAs. Each rule points to the section that explains the reason, so you can jump to the detail when you need it.</p>
<p>&nbsp;</p>
<h3>Quick Reference Table</h3>
<p>&nbsp;</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Area</th>
<th>Do this</th>
<th>Avoid this</th>
</tr>
</thead>
<tbody>
<tr>
<td>Instance memory</td>
<td>Cap <code>max server memory</code> at about 75% of available memory (see Configuration).</td>
<td>Leaving the default of about 2 TB.</td>
</tr>
<tr>
<td>MAXDOP and cost threshold</td>
<td>Start from the NUMA-based MAXDOP rule and tune cost threshold by measurement (see Configuration).</td>
<td>MAXDOP 1 server-wide, or cost threshold left at 5.</td>
</tr>
<tr>
<td>tempdb</td>
<td>Use equally sized, pre-sized data files with fixed growth (see Configuration).</td>
<td>One small file that relies on autogrow.</td>
</tr>
<tr>
<td>Storage layout</td>
<td>Separate data, log and tempdb volumes; enable instant file initialization (see Configuration).</td>
<td>Putting everything on one shared volume.</td>
</tr>
<tr>
<td>Data types and keys</td>
<td>Use the narrowest correct type and a narrow, unique, ever-increasing clustered key (see Data Modeling).</td>
<td>Random GUID clustered keys and <code>nvarchar(max)</code> for short values.</td>
</tr>
<tr>
<td>Indexing</td>
<td>Index for WHERE, JOIN and ORDER BY, and use INCLUDE columns (see Data Modeling).</td>
<td>Duplicate and unused indexes.</td>
</tr>
<tr>
<td>Query patterns</td>
<td>Write SARGable predicates and set-based code (see Query Optimization).</td>
<td><code>SELECT *</code> and functions on indexed columns.</td>
</tr>
<tr>
<td>Isolation level</td>
<td>Use RCSI for read-heavy OLTP after testing (see Transactions).</td>
<td>Long transactions and untested isolation changes.</td>
</tr>
<tr>
<td>Connection strings</td>
<td>Keep <code>Encrypt=Mandatory</code> or use Strict (see Connection Management).</td>
<td><code>TrustServerCertificate=true</code> in production.</td>
</tr>
<tr>
<td>Authentication and permissions</td>
<td>Use Windows or Entra auth and a custom role (see Security).</td>
<td>Using <code>sa</code> or <code>db_owner</code> for apps.</td>
</tr>
<tr>
<td>Dynamic SQL</td>
<td>Use <code>sp_executesql</code> with typed parameters (see Security).</td>
<td>Concatenating user input into SQL strings.</td>
</tr>
<tr>
<td>Backups</td>
<td>Use <code>CHECKSUM</code>, compression and off-server copies (see Backups).</td>
<td>FULL recovery with no log backups.</td>
</tr>
<tr>
<td>Restore testing</td>
<td>Restore on a schedule and run <code>DBCC CHECKDB</code> (see Backups).</td>
<td>Trusting <code>RESTORE VERIFYONLY</code> alone.</td>
</tr>
<tr>
<td>Patching</td>
<td>Patch on a cadence and test on a copy first (see Patching and Upgrading).</td>
<td>Switching between CU and GDR tracks casually.</td>
</tr>
<tr>
<td>Monitoring</td>
<td>Start with wait stats, then Query Store and Extended Events (see Monitoring).</td>
<td>Alerting only on whether a job ran.</td>
</tr>
</tbody>
</table>
</figure>
<h3></h3>
<h3>How to Read This Guide</h3>
<p>&nbsp;</p>
<p>Treat every rule as a default, not a law. Where a rule does not apply, the section states the trade-off and the case where you should do something different.</p>
<p>&nbsp;</p>
<p>Test each change on a non-production copy and measure before and after.</p>
<p>&nbsp;</p>
<h2 id="sql-server-configuration-best-practices-memory-maxdop-cost-t">SQL Server Configuration Best Practices: Memory, MAXDOP, Cost Threshold and tempdb</h2>
<p>&nbsp;</p>
<p>These instance-level settings decide how SQL Server uses memory, CPU and temporary storage. Most of them ship with defaults that suit a demo machine, not a production server, so review them on every new install, on 2022 and on 2025.</p>
<p>&nbsp;</p>
<h3>SQL Server Max Server Memory Setting</h3>
<p>&nbsp;</p>
<p>Cap max server memory on every version. The default is about 2 TB, which means SQL Server will take whatever it can and leave the OS and other processes to fight for the rest.</p>
<p>Current Microsoft docs suggest a starting point of about 75% of the available memory not used by other processes, including other instances on the same host. Leave min server memory at 0. Setup on Windows has suggested a value since SQL Server 2019, so check what it picked.</p>
<p>&nbsp;</p>
<p>The older advice was to leave 4-6 GB, or 10-15%, for the OS. A percentage of what is actually available is a better baseline because it already subtracts a second instance, an SSIS service, antivirus or a monitoring agent. A fixed reserve ignores all of them.</p>
<p>&nbsp;</p>
<p>If Lock Pages in Memory (LPIM) is granted to the service account, set a specific value. LPIM stops Windows from trimming SQL Server&#8217;s memory, so a wrong cap can starve the OS.</p>
<p>&nbsp;</p>
<h3>MAXDOP: Why OLTP Does Not Automatically Mean MAXDOP</h3>
<p>&nbsp;</p>
<p>MAXDOP (maximum degree of parallelism) is the number of CPUs one query can use. Some teams say &#8220;OLTP means MAXDOP 1&#8221;, while Microsoft publishes a NUMA-based rule. They conflict because the first is a workaround for parallelism waits and the second is a general default.</p>
<p>&nbsp;</p>
<p>Start from the Microsoft guidance. A NUMA node (Non-Uniform Memory Access node) is a group of processors that share local memory. Keeping a query inside one node avoids slower cross-node memory access. The table below shows the starting values.</p>
<p>&nbsp;</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Server layout</th>
<th>Recommended MAXDOP</th>
</tr>
</thead>
<tbody>
<tr>
<td>One NUMA node, 8 or fewer logical processors</td>
<td>Up to the number of logical processors</td>
</tr>
<tr>
<td>One NUMA node, more than 8 logical processors</td>
<td>8</td>
</tr>
<tr>
<td>Several NUMA nodes, 16 or fewer logical processors per node</td>
<td>Up to the number of logical processors in one node</td>
</tr>
<tr>
<td>Several NUMA nodes, more than 16 logical processors per node</td>
<td>Half the logical processors in one node, with a maximum of 16</td>
</tr>
</tbody>
</table>
</figure>
<p>&nbsp;</p>
<p>For example, a server with two NUMA nodes of 24 logical processors each would start at 12. A server with two nodes of 40 logical processors each would start at 16, because half of 40 is 20 and the cap is 16.</p>
<p>&nbsp;</p>
<ul>
<li><strong>Mixed workloads:</strong> Use <code>ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP</code> so each database gets its own limit.</li>
<li><strong>One workload that needs a different limit:</strong> Create a Resource Governor workload group with its own <code>MAX_DOP</code>.</li>
<li><strong>MAXDOP 1 server-wide:</strong> Avoid it. Parallel index builds and reporting queries lose parallelism, and maintenance windows get longer.</li>
</ul>
<h3></h3>
<h3>Cost Threshold for Parallelism and Optimize for Ad Hoc Workloads</h3>
<p>&nbsp;</p>
<p>The default cost threshold for parallelism is 5, which is too low for modern hardware. Small queries go parallel and waste threads on coordination.</p>
<p>&nbsp;</p>
<p>Raise it based on observed plan costs. A value in the 25 to 50 range is a reasonable test value, not a rule. After the change, compare CXPACKET and CXCONSUMER waits before and after, and check that your important queries did not slow down.</p>
<p>&nbsp;</p>
<p>Enable <code>optimize for ad hoc workloads</code> when the plan cache fills with single-use plans, e.g. an ORM that sends unparameterized text. On first run SQL Server stores only a small plan stub, and the full plan is cached on the second run. The trade-off is one extra compile for queries that do repeat.</p>
<p>&nbsp;</p>
<h3>tempdb Configuration</h3>
<p>&nbsp;</p>
<p>Use several data files of equal size, pre-sized, with a fixed growth increment, on fast storage. Autogrow should be an emergency only, not the sizing method.</p>
<p>Many sessions create temporary objects at once, and they all compete for the allocation pages (PFS, GAM, SGAM) in a single file. That shows up as PAGELATCH waits. More files spread the allocations. SQL Server fills files in proportion to free space, so unequal sizes send most of the work to one file.</p>
<p>Use this rule for the file count, which follows Microsoft guidance:</p>
<ol>
<li>If the server has 8 or fewer logical processors, create one data file per logical processor (e.g. 4 logical processors, 4 files).</li>
<li>If the server has more than 8 logical processors, start with 8 data files.</li>
<li>If PAGELATCH contention on tempdb allocation pages continues with 8 files, add files in multiples of 4, and stop when the contention goes away.</li>
</ol>
<p>More files than needed do not help and add some overhead, so do not match the core count on a large server.</p>
<h3>SQL Server 2025 Additions</h3>
<ul>
<li><strong>tempdb space governance:</strong> Resource Governor can limit tempdb space per workload group. A workload that exceeds its limit is stopped with an error.</li>
<li><strong>Accelerated Database Recovery in tempdb:</strong> Now supported.</li>
<li><strong>Resource Governor in Standard edition:</strong> It has the same functionality as Enterprise. Standard 2025 is limited to the lesser of 4 sockets or 32 cores, and 256 GB of buffer pool per instance.</li>
<li></li>
</ul>
<h3>Storage and OS Settings</h3>
<p>&nbsp;</p>
<p>Separate data, log and tempdb volumes where your storage design allows it. Put the log on fast storage or RAID 10, because log writes are sequential and every commit waits for them (WRITELOG).</p>
<p>Enable instant file initialization (IFI) by granting the &#8220;Perform volume maintenance tasks&#8221; privilege to the SQL Server service account. With IFI, data file growth and restores skip zeroing the new space, so they finish much faster.</p>
<p>Log files are different, and the behavior depends on the version. In SQL Server 2019 and earlier, log files are always zero-initialized. In SQL Server 2022 and later, transaction log growth events of up to 64 MB can also use IFI. Larger log growths, and the initial creation of a log file, are still zeroed.</p>
<p>For the versions this guide targets, set the log autogrowth increment to 64 MB or less so that emergency growths are fast. Still pre-size the log to its working size, because a log that grows often creates many virtual log files and slows recovery.</p>
<p>&nbsp;</p>
<h3>Sample Configuration Script</h3>
<p>The example below assumes one instance on a 32 GB server, so 75% is 24576 MB. It also assumes a single NUMA node with 16 logical processors. By the Microsoft rule, a single node with more than 8 logical processors gets MAXDOP 8, and the same layout gives 8 tempdb data files. Adjust all values for your own hardware.</p>
<p>&nbsp;</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;

EXEC sp_configure 'max server memory (MB)', 24576;
EXEC sp_configure 'cost threshold for parallelism', 50;
EXEC sp_configure 'optimize for ad hoc workloads', 1;
RECONFIGURE;

-- Run in the user database that needs its own limit.
-- 8 = single NUMA node with 16 logical processors (more than 8, so cap at 8).
ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 8;

-- Verify the instance settings
SELECT name, value, value_in_use
FROM sys.configurations
WHERE name IN ('max server memory (MB)',
               'min server memory (MB)',
               'cost threshold for parallelism',
               'optimize for ad hoc workloads');

-- Check the NUMA layout and logical processor count used for MAXDOP and tempdb sizing
SELECT cpu_count FROM sys.dm_os_sys_info;

SELECT node_id, online_scheduler_count
FROM sys.dm_os_nodes
WHERE node_state_desc = N'ONLINE';

-- Check tempdb file layout (expect 8 data files on this 16-processor server)
SELECT name, physical_name,
       size * 8 / 1024 AS size_mb,
       growth, is_percent_growth
FROM sys.master_files
WHERE database_id = 2;</code></pre>
<p>Run the NUMA queries first and change MAXDOP if your layout differs. The last query should show equal <code>size_mb</code> values, a fixed growth in MB and <code>is_percent_growth</code> set to 0 for every data file.</p>
<h2 id="data-modeling-and-indexing-best-practices">Data Modeling and Indexing Best Practices</h2>
<p>Good SQL Server performance starts with the table design, not the server settings. Model the data cleanly, choose small data types, and add only the indexes your queries use. These rules apply to both SQL Server 2022 and 2025.</p>
<h3>Model to Third Normal Form First</h3>
<p>Start with third normal form (3NF), where each non-key column depends only on the key. Denormalize only when a measured query problem justifies it.</p>
<p>Normalized tables avoid update anomalies, because a customer address lives in one row and not in every order. Rows stay smaller, so more rows fit on a page. Updates touch fewer rows, which means fewer locks.</p>
<h3>Use the Narrowest Correct Data Type and Add Constraints</h3>
<p>Pick the smallest type that safely holds the data. The clustered index key is carried into every nonclustered index as the row locator, so a wide clustered key makes every nonclustered index larger. Wide columns in any index key also add to index size, buffer pool memory and I/O.</p>
<ul>
<li><strong>int vs bigint:</strong> Use <code>int</code> unless you expect more than about 2.1 billion rows.</li>
<li><strong>date vs datetime2:</strong> Use <code>date</code> when no time is needed, and <code>datetime2(0)</code> for second precision.</li>
<li><strong>Strings:</strong> Avoid <code>nvarchar(max)</code> for short values. Use a sized type such as <code>nvarchar(100)</code>.</li>
</ul>
<p>Declare primary key, foreign key, unique and check constraints. The optimizer uses them to build better plans, and they reject bad data at the source, before it reaches the application.</p>
<h3>Choose a Narrow, Ever-Increasing Clustered Key</h3>
<p>Give every table a clustered index on a narrow, unique, ever-increasing key, such as an <code>int IDENTITY</code> column. New rows are appended at the end of the table, and the small key is copied into each nonclustered index.</p>
<p>A random GUID from <code>NEWID()</code> inserts rows at random positions, which causes page splits and fragmentation. A GUID is also 16 bytes, which makes it a wide clustered key. If you need GUIDs, use <code>NEWSEQUENTIALID()</code> as a column default, or keep an identity column as the clustered key and the GUID as a separate unique column.</p>
<h3>Design Nonclustered Indexes for Your Queries</h3>
<p>Index the columns used in <code>WHERE</code>, <code>JOIN</code> and <code>ORDER BY</code>. Put equality columns first and the range column after them. Use <code>INCLUDE</code> for columns that are only selected, so the index covers the query without key lookups.</p>
<p>Example: a retail site lists one customer&#8217;s recent orders, filtering on <code>CustomerId</code> (equality) and <code>OrderDate</code> (range).</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">CREATE TABLE dbo.Orders
(
    OrderId     int IDENTITY(1,1) NOT NULL,
    CustomerId  int NOT NULL,
    OrderDate   datetime2(0) NOT NULL,
    Status      tinyint NOT NULL,
    TotalAmount decimal(10,2) NOT NULL,
    CONSTRAINT PK_Orders PRIMARY KEY CLUSTERED (OrderId),
    CONSTRAINT FK_Orders_Customers FOREIGN KEY (CustomerId)
        REFERENCES dbo.Customers (CustomerId),
    CONSTRAINT CK_Orders_TotalAmount CHECK (TotalAmount &gt;= 0)
);

CREATE NONCLUSTERED INDEX IX_Orders_Customer_Date
ON dbo.Orders (CustomerId, OrderDate)
INCLUDE (Status, TotalAmount);</code></pre>
<p>This creates a narrow clustered key, a foreign key, a check constraint and a covering index for the customer-orders query.</p>
<h3>Remove Duplicate and Unused Indexes</h3>
<p>Every index slows inserts, updates and deletes and uses storage. Check <code>sys.dm_db_index_usage_stats</code> to find indexes that are written to but never read.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">SELECT OBJECT_SCHEMA_NAME(i.object_id) AS SchemaName,
       OBJECT_NAME(i.object_id)        AS TableName,
       i.name                          AS IndexName,
       ISNULL(s.user_seeks, 0)   AS UserSeeks,
       ISNULL(s.user_scans, 0)   AS UserScans,
       ISNULL(s.user_lookups, 0) AS UserLookups,
       ISNULL(s.user_updates, 0) AS UserUpdates
FROM sys.indexes AS i
LEFT JOIN sys.dm_db_index_usage_stats AS s
       ON s.object_id = i.object_id
      AND s.index_id = i.index_id
      AND s.database_id = DB_ID()
WHERE i.type_desc = 'NONCLUSTERED'
  AND i.is_primary_key = 0
  AND i.is_unique_constraint = 0
  AND OBJECTPROPERTY(i.object_id, 'IsUserTable') = 1
  AND ISNULL(s.user_seeks, 0) + ISNULL(s.user_scans, 0) + ISNULL(s.user_lookups, 0) = 0
ORDER BY UserUpdates DESC;</code></pre>
<p>This lists nonclustered indexes with no reads, sorted by write cost. The usage counters reset when the instance restarts, so observe a full business cycle (e.g. a month-end close) before dropping anything.</p>
<h3>Maintain Statistics First, Fragmentation Second</h3>
<p>Update statistics regularly, because the optimizer chooses plans from them. Stale statistics cause bad row estimates and bad plans.</p>
<p>For fragmentation, act on a threshold and not on a blanket schedule. Measure it with <code>sys.dm_db_index_physical_stats</code>, then pick an action from the table below. These numbers are starting points only, so adjust them after you see how your own workload and storage respond.</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Index fragmentation</th>
<th>Starting-point action</th>
<th>Why</th>
</tr>
</thead>
<tbody>
<tr>
<td>Below 5%</td>
<td>Do nothing</td>
<td>The maintenance cost is higher than any benefit.</td>
</tr>
<tr>
<td>5% to 30%</td>
<td><code>ALTER INDEX ... REORGANIZE</code></td>
<td>Reorganize is an online operation that compacts pages in place, using little extra space.</td>
</tr>
<tr>
<td>Above 30%</td>
<td><code>ALTER INDEX ... REBUILD</code></td>
<td>Rebuild creates the index again, which removes fragmentation and updates the index statistics with a full scan.</td>
</tr>
</tbody>
</table>
</figure>
<p>Ignore small indexes, for example those under about 1,000 pages, because their fragmentation figures are not meaningful and rarely affect performance. Fragmentation matters less on SSD storage, but statistics matter just as much.</p>
<h3>SQL Server 2025 Vector Data</h3>
<p>The <code>vector</code> data type is generally available in SQL Server 2025. DiskANN vector indexes are still preview only, need the <code>PREVIEW_FEATURES</code> database scoped configuration, and are not recommended for production yet.</p>
<h2 id="query-optimization-and-sql-server-performance-tuning-best-pr">Query Optimization and SQL Server Performance Tuning Best Practices</h2>
<p>Most SQL Server performance tuning comes down to a few habits: write predicates the optimizer can seek on, return only the data you need, reuse plans, and watch for plan regressions with Query Store.</p>
<h3>Write SARGable Predicates</h3>
<p>A SARGable predicate (Search ARGument able) lets the engine use an index seek. Wrapping an indexed column in a function forces a scan, because the function must run on every row.</p>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">-- Bad: function on the column, index on OrderDate cannot be used for a seek
SELECT OrderId, TotalAmount
FROM dbo.Orders
WHERE YEAR(OrderDate) = 2026;

-- Good: range on the bare column, index seek is possible
SELECT OrderId, TotalAmount
FROM dbo.Orders
WHERE OrderDate &gt;= '20260101'
  AND OrderDate &lt;  '20270101';</code></pre>
<p>The rewritten query returns the same rows and reads only the matching index range.</p>
<h3>Return Less Data, Use Fewer Round Trips</h3>
<ul>
<li><strong>Select only needed columns:</strong> Avoid <code>SELECT *</code>. It reads and sends extra data, and it stops narrow covering indexes from being used.</li>
<li><strong>SET NOCOUNT ON:</strong> Add it at the top of procedures to stop the &#8220;rows affected&#8221; message after every statement.</li>
<li><strong>Set-based code:</strong> Use one <code>UPDATE ... JOIN</code> instead of a cursor. A cursor processes one row at a time, which costs more CPU and more statements.</li>
</ul>
<p>Example: a retail nightly job that updates stock for 200,000 products should run one set-based statement, not a loop that fires 200,000 updates.</p>
<h3>Handle Parameter Sniffing</h3>
<p>Parameterized queries and stored procedures let SQL Server reuse plans. Parameter sniffing means the plan is built for the first parameter value it sees, which can be a poor fit for later values.</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Option</th>
<th>Use when</th>
<th>Trade-off</th>
</tr>
</thead>
<tbody>
<tr>
<td>Parameter-sensitive plan (PSP) optimization (SQL Server 2022 and later, compatibility level 160 or higher)</td>
<td>A parameterized query runs against skewed data, so one value returns a few rows and another returns millions</td>
<td>Applies only to some predicate shapes, and the engine decides when to use it. It is not a fix for every sniffing problem, so check the plans in Query Store</td>
</tr>
<tr>
<td><code>OPTION (RECOMPILE)</code></td>
<td>Rare, expensive queries with very uneven data</td>
<td>Compile cost on every run</td>
</tr>
<tr>
<td><code>OPTIMIZE FOR</code></td>
<td>One typical value is known</td>
<td>Other values may run slowly</td>
</tr>
<tr>
<td>Query Store plan forcing</td>
<td>A known good plan exists</td>
<td>Forced plan can go stale as data changes</td>
</tr>
</tbody>
</table>
</figure>
<p>On 2022 and later, PSP optimization is the first thing to try when you are on compatibility level 160. It lets one parameterized statement keep more than one plan for different parameter ranges. If it does not cover your query, move down the table.</p>
<h3>Use Query Store</h3>
<p>Query Store records queries, plans and runtime statistics inside the database. From SQL Server 2022, it is ON by default for new databases. The &#8220;enable it&#8221; step therefore mostly applies to databases that were upgraded or restored from an older instance, because they keep their earlier setting.</p>
<p>Check which databases still have it off, and turn it on for the ones you care about. Use <code>QUERY_CAPTURE_MODE = AUTO</code> so trivial queries do not fill the store.</p>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">SELECT name, is_query_store_on
FROM sys.databases
WHERE database_id &gt; 4;</code></pre>
<p>This lists user databases and shows whether Query Store is on for each one.</p>
<p>On readable secondary replicas, the defaults differ by version. In SQL Server 2025, Query Store on readable secondaries is on by default. In SQL Server 2022 it was off and needed trace flag 12606.</p>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">ALTER DATABASE SalesDb SET QUERY_STORE = ON
(
    OPERATION_MODE = READ_WRITE,
    QUERY_CAPTURE_MODE = AUTO,
    MAX_STORAGE_SIZE_MB = 1024,
    INTERVAL_LENGTH_MINUTES = 60,
    SIZE_BASED_CLEANUP_MODE = AUTO
);</code></pre>
<p>The sizes above are example values. Adjust them to your workload.</p>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">SELECT TOP (10)
    q.query_id,
    LEFT(qt.query_sql_text, 200) AS query_text,
    SUM(rs.count_executions * rs.avg_duration) / 1000.0 AS total_duration_ms
FROM sys.query_store_query AS q
JOIN sys.query_store_query_text AS qt ON qt.query_text_id = q.query_text_id
JOIN sys.query_store_plan AS p ON p.query_id = q.query_id
JOIN sys.query_store_runtime_stats AS rs ON rs.plan_id = p.plan_id
GROUP BY q.query_id, qt.query_sql_text
ORDER BY total_duration_ms DESC;</code></pre>
<p>This lists the ten queries that consumed the most total time. Durations are stored in microseconds, so the query divides by 1000.</p>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">EXEC sys.sp_query_store_force_plan @query_id = 42, @plan_id = 17;

-- Remove the forced plan when it is no longer needed
EXEC sys.sp_query_store_unforce_plan @query_id = 42, @plan_id = 17;</code></pre>
<p>Replace the IDs with values from the previous query and the Query Store reports.</p>
<h3>Test Feedback Features and Compatibility Levels</h3>
<p>The optimizer can adjust some settings for a query after it has run, using what it saw on earlier executions. Two feedback features matter most, and each needs a minimum compatibility level.</p>
<ul>
<li><strong>Memory grant feedback:</strong> Resizes the memory granted to a query when earlier runs got too much or too little, which reduces tempdb spills and wasted memory. Batch mode needs compatibility level 140 or higher. Row mode needs 150 or higher. In SQL Server 2022, the percentile and persisted versions of this feedback need Query Store to be on and in read-write mode.</li>
<li><strong>DOP feedback:</strong> Lowers the degree of parallelism (DOP, the number of threads a query uses) for parallel queries that do not benefit from it. It is available in SQL Server 2022 and later, needs compatibility level 160 or higher, and needs Query Store in read-write mode. In 2022, check that the <code>DOP_FEEDBACK</code> database scoped configuration is on for the database.</li>
</ul>
<p>Raise the compatibility level on a copy of the database first, compare plans, and force the old plan where a regression appears. Check the Microsoft documentation for the exact compatibility level that matches your SQL Server version before you change it.</p>
<h3>Read Execution Plans</h3>
<ol>
<li><strong>Estimated vs actual rows:</strong> Large gaps usually mean stale statistics or a poor cardinality estimate.</li>
<li><strong>Spills to tempdb:</strong> A sort or hash warning means the memory grant was too small.</li>
<li><strong>Key lookups:</strong> Many lookups suggest the index needs an <code>INCLUDE</code> column.</li>
<li><strong>Implicit conversions:</strong> A parameter type that differs from the column type (e.g. <code>nvarchar</code> against <code>varchar</code>) can block an index seek.</li>
</ol>
<h2 id="transactions-isolation-levels-and-optimized-locking">Transactions, Isolation Levels and Optimized Locking</h2>
<p>Keep transactions short, touch tables in the same order everywhere, and use row versioning (Read Committed Snapshot Isolation, or RCSI) for read-heavy OLTP so readers don&#8217;t block writers. These habits are part of SQL Server performance tuning best practices because blocking often looks like a slow query.</p>
<h3>Isolation Levels Compared</h3>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Level</th>
<th>What it prevents</th>
<th>Version store cost</th>
<th>Use when</th>
</tr>
</thead>
<tbody>
<tr>
<td>READ COMMITTED (locking)</td>
<td>Dirty reads</td>
<td>None</td>
<td>Default; low-concurrency workloads</td>
</tr>
<tr>
<td>READ COMMITTED SNAPSHOT (RCSI)</td>
<td>Dirty reads; readers don&#8217;t wait for writers</td>
<td>Row versions in tempdb, or in the PVS with ADR</td>
<td>Read-heavy OLTP</td>
</tr>
<tr>
<td>SNAPSHOT</td>
<td>Dirty reads, non-repeatable reads, phantoms within a transaction</td>
<td>Same store; versions live as long as the oldest open transaction</td>
<td>Consistent multi-statement reads</td>
</tr>
<tr>
<td>SERIALIZABLE</td>
<td>All of the above, using range locks</td>
<td>None, but heavy locking</td>
<td>Strict invariants, used rarely</td>
</tr>
</tbody>
</table>
</figure>
<h3>RCSI Trade-offs</h3>
<p>RCSI makes a SELECT read the last committed version of a row instead of waiting for a lock. The cost is extra version storage, normally in tempdb. With Accelerated Database Recovery (ADR), the version store lives in the user database (the persistent version store, PVS).</p>
<p>Behaviour also changes. Code that relied on a blocking read to wait for a writer, such as a &#8220;read then update&#8221; pattern, now sees the old value. Test this in a copy of the database first.</p>
<h3>Optimized Locking in SQL Server 2025</h3>
<p>SQL Server 2025 adds optimized locking, which uses transaction ID (TID) locking and lock after qualification (LAQ). A TID lock replaces many row locks, and LAQ takes locks only on the rows that match the predicate. This reduces blocking and lock memory use, avoids lock escalation, and needs no application code change. It is a good reason to test 2025 with write-heavy workloads.</p>
<p>Optimized locking is not on by default for every database. It requires Accelerated Database Recovery (ADR) to be enabled on the database, so turn on ADR first and check the result in <code>sys.databases</code>. Confirm the exact database-level setting for optimized locking in the Microsoft documentation for your build.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">-- Prerequisite for optimized locking: ADR on the database.
-- Test first and run in a quiet window.
ALTER DATABASE BankDb SET ACCELERATED_DATABASE_RECOVERY = ON;
GO

SELECT name, is_accelerated_database_recovery_on
FROM sys.databases
WHERE name = N'BankDb';</code></pre>
<p>This enables ADR and confirms it with a check of <code>is_accelerated_database_recovery_on</code>.</p>
<p>RCSI and optimized locking address different parts of the blocking problem, so measure them with and without RCSI on your own workload instead of assuming the combination is better. The animated diagram below compares classic locking with optimized locking plus RCSI for two sessions on the same table.</p>
<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" src="https://thecodebuzz.com/wp-content/uploads/2026/10/sql-server-best-practices-guidelines-diagram-5.gif" alt="Classic locking escalates to a table lock and blocks a SELECT; optimized locking with RCSI uses one TID lock and does not block." width="1200" height="675" /><figcaption>Classic locking escalates and blocks readers; optimized locking with RCSI uses a TID lock and readers see row versions.</figcaption></figure>
<h3>Deadlocks and Retries</h3>
<p>When SQL Server picks your session as a deadlock victim, it returns error 1205. Retry in application code with a bounded count (e.g. three attempts) and a short backoff. To see the cause, read the deadlock graph from the <code>system_health</code> Extended Events session.</p>
<h3>Finance Transfer Example</h3>
<p>Move money in one short transaction. Validate the inputs first, then update the two accounts with two separate statements, lowest ID first. Because every transfer takes the locks in the same order, two opposite transfers (A to B and B to A) can&#8217;t deadlock on these two rows.</p>
<p>The balance check sits inside the debit <code>UPDATE</code>&#8216;s <code>WHERE</code> clause. The row is locked when the check runs, so it sees the current balance. A separate <code>SELECT</code> before the update could read an older row version under RCSI.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">-- Enable RCSI (rolls back open transactions, so run in a quiet window)
ALTER DATABASE BankDb SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
GO

CREATE OR ALTER PROCEDURE dbo.TransferFunds
    @FromId int, @ToId int, @Amount decimal(19,4)
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    -- Validate inputs before opening a transaction
    IF @Amount IS NULL OR @Amount &lt;= 0
        THROW 50001, 'Amount must be greater than zero.', 1;
    IF @FromId IS NULL OR @ToId IS NULL OR @FromId = @ToId
        THROW 50002, 'Source and target accounts must be different.', 1;

    -- Work out the lock order: lowest AccountId first
    DECLARE @LowId  int = CASE WHEN @FromId &lt; @ToId THEN @FromId ELSE @ToId END;
    DECLARE @HighId int = CASE WHEN @FromId &lt; @ToId THEN @ToId ELSE @FromId END;

    -- Signed change for each account: negative for the debit, positive for the credit
    DECLARE @LowDelta  decimal(19,4) = CASE WHEN @LowId  = @FromId THEN -@Amount ELSE @Amount END;
    DECLARE @HighDelta decimal(19,4) = CASE WHEN @HighId = @FromId THEN -@Amount ELSE @Amount END;

    BEGIN TRY
        BEGIN TRANSACTION;

        UPDATE dbo.Accounts
           SET Balance = Balance + @LowDelta
         WHERE AccountId = @LowId
           AND (@LowDelta &gt; 0 OR Balance &gt;= @Amount);
        IF @@ROWCOUNT = 0
            THROW 50003, 'Account not found or insufficient funds.', 1;

        UPDATE dbo.Accounts
           SET Balance = Balance + @HighDelta
         WHERE AccountId = @HighId
           AND (@HighDelta &gt; 0 OR Balance &gt;= @Amount);
        IF @@ROWCOUNT = 0
            THROW 50003, 'Account not found or insufficient funds.', 1;

        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT &gt; 0 ROLLBACK TRANSACTION;
        THROW;
    END CATCH
END;</code></pre>
<p>The procedure rejects zero, negative and NULL amounts, and it rejects a transfer from an account to itself. If either update finds no row to change, the transaction rolls back, so a failed debit never leaves a half-finished credit behind. <code>XACT_ABORT ON</code> also rolls back the whole transaction on any runtime error.</p>
<p>The fixed order only protects code that follows it. Any other procedure that updates the same accounts in a different order, or a trigger that touches other rows, can still deadlock with this one. Keep the retry logic for error 1205 in place.</p>
<h2 id="connection-management-and-microsoft-data-sqlclient-best-prac">Connection Management and Microsoft.Data.SqlClient Best Practices</h2>
<p>Use Microsoft.Data.SqlClient (v7.0.1 is shown in the current API docs) and keep the defaults <code>Encrypt=Mandatory</code> and <code>TrustServerCertificate=false</code>. When an app starts failing with certificate errors after a driver upgrade, the driver is not broken. The client simply does not trust the server certificate. Fix the certificate chain or the host name instead of switching on <code>TrustServerCertificate</code>. This is one of the most useful SQL Server best practices for developers.</p>
<p>The animated diagram below shows how the client decides whether a connection succeeds and which fix to choose.</p>
<figure class="wp-block-image size-full"><img decoding="async" src="https://thecodebuzz.com/wp-content/uploads/2026/10/sql-server-best-practices-guidelines-diagram-6.gif" alt="Decision flow from opening a connection through Encrypt settings and certificate checks to a connected result or a certificate error with two fixes." width="1200" height="675" /><figcaption>Certificate errors come from failed server identity checks; fix the certificate and host name rather than enabling TrustServerCertificate.</figcaption></figure>
<h3>Encrypt Options Compared</h3>
<p><code>Encrypt=Strict</code> uses TDS 8.0 and cannot be bypassed with <code>TrustServerCertificate</code>. Use it when your server supports TDS 8.0. Avoid <code>TrustServerCertificate=true</code> in production, because it skips the server identity check.</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Encrypt value</th>
<th>Behaviour</th>
<th>Certificate validation</th>
<th>Use when</th>
</tr>
</thead>
<tbody>
<tr>
<td>Optional</td>
<td>Encrypts only if the server requires it</td>
<td>Only when encryption is used</td>
<td>Legacy apps during migration, not new work</td>
</tr>
<tr>
<td>Mandatory (default)</td>
<td>Always encrypts</td>
<td>Yes, unless <code>TrustServerCertificate=true</code></td>
<td>Most production apps</td>
</tr>
<tr>
<td>Strict</td>
<td>TDS 8.0, TLS first</td>
<td>Always, cannot be bypassed</td>
<td>Server supports TDS 8.0</td>
</tr>
</tbody>
</table>
</figure>
<h3>Connection Pooling Rules</h3>
<ul>
<li><strong>Open late, close early:</strong> Use <code>using</code> or <code>await using</code> so the connection returns to the pool even when an exception occurs.</li>
<li><strong>One connection per thread:</strong> A <code>SqlConnection</code> is not thread-safe, so never share it.</li>
<li><strong>Keep connection strings identical:</strong> Each distinct string creates its own pool. Per-request values (e.g. a user name in the string) fragment the pool.</li>
<li><strong>Watch Max Pool Size:</strong> The default is 100. Pool exhaustion shows up as &#8220;timeout period elapsed prior to obtaining a connection from the pool&#8221;. The usual cause is a leaked connection, so look for missing disposal before raising the limit.</li>
</ul>
<h3>Availability Groups and Read-Only Routing</h3>
<p>Connect to the availability group listener name, never a node name. Add <code>MultiSubnetFailover=True</code> when the listener spans subnets, so the client tries all IP addresses in parallel. Add <code>ApplicationIntent=ReadOnly</code> for reporting workloads that should use read-only routing.</p>
<h3>C# Example: Strict Encryption and a Typed Parameter</h3>
<p>Example: a retail app looks up orders for one customer. The parameter has an explicit type and size, which avoids implicit conversions and plan cache bloat.</p>
<p class="code-label"><strong>C# (.NET)</strong></p>
<pre><code class="language-csharp">using System.Data;
using Microsoft.Data.SqlClient;

var builder = new SqlConnectionStringBuilder
{
    DataSource = "orders-listener.contoso.com",
    InitialCatalog = "Sales",
    IntegratedSecurity = true,
    Encrypt = SqlConnectionEncryptOption.Strict,
    MultiSubnetFailover = true,
    ApplicationIntent = ApplicationIntent.ReadWrite,
    MaxPoolSize = 100
};

await using var connection = new SqlConnection(builder.ConnectionString);
await connection.OpenAsync();

await using var command = new SqlCommand(
    "SELECT OrderId, OrderDate FROM dbo.Orders WHERE CustomerRef = @CustomerRef;",
    connection);
command.Parameters.Add("@CustomerRef", SqlDbType.VarChar, 20).Value = "C-10045";

await using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
    Console.WriteLine($"{reader.GetInt32(0)} {reader.GetDateTime(1):d}");
}</code></pre>
<p>This opens a strict, encrypted connection and returns it to the pool when the block ends.</p>
<p>For transient errors, the driver offers configurable retry logic (<code>SqlRetryLogicOptions</code> with <code>SqlConfigurableRetryFactory</code>). Assign a provider to the connection or command, and keep the retry count and delay bounded.</p>
<h3>Python Equivalent with pyodbc</h3>
<p>Use the ODBC Driver for SQL Server, set <code>Encrypt=yes</code> and <code>TrustServerCertificate=no</code>, and pass values through <code>?</code> placeholders. Match the driver name to the one installed on your machine.</p>
<p class="code-label"><strong>Python</strong></p>
<pre><code class="language-python">import os
import pyodbc

conn_str = (
    "DRIVER={ODBC Driver 18 for SQL Server};"
    "SERVER=orders-listener.contoso.com;"
    "DATABASE=Sales;"
    f"UID={os.environ['SQL_USER']};PWD={os.environ['SQL_PASSWORD']};"
    "Encrypt=yes;TrustServerCertificate=no;"
    "MultiSubnetFailover=Yes;"
)

with pyodbc.connect(conn_str) as conn:
    cursor = conn.cursor()
    cursor.execute(
        "SELECT OrderId, OrderDate FROM dbo.Orders WHERE CustomerRef = ?",
        "C-10045",
    )
    for row in cursor.fetchall():
        print(row.OrderId, row.OrderDate)</code></pre>
<p>This keeps the password out of the source code and sends the value as a parameter, not as part of the SQL text.</p>
<h2 id="sql-server-security-best-practices-least-privilege-injection">SQL Server Security Best Practices: Least Privilege, Injection and Encryption</h2>
<p>Use Windows or Microsoft Entra authentication, give each application its own login with only the permissions it needs, and never connect an application as <code>sa</code> or as a member of <code>db_owner</code>. These SQL Server security best practices limit the damage if one credential or one query is compromised.</p>
<h3>Apply the Least Privilege Pattern</h3>
<p>Create a database role for the application, grant it <code>EXECUTE</code> on a schema, and give it no direct table access. Stored procedures and tables owned by the same principal use ownership chaining, so the procedure can read the tables even though the caller cannot.</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Permission model</th>
<th>Risk</th>
<th>Use</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>db_owner</code></td>
<td>Full control of the database, including dropping objects and changing permissions</td>
<td>DBAs and deployment accounts only</td>
</tr>
<tr>
<td><code>db_datareader</code> / <code>db_datawriter</code></td>
<td>Read or write every table, including future ones. An injection flaw exposes all data</td>
<td>Simple tools and trusted internal jobs</td>
</tr>
<tr>
<td>Custom role with <code>EXECUTE</code> on a schema</td>
<td>Limited to the procedures in that schema</td>
<td>Default for application connections</td>
</tr>
</tbody>
</table>
</figure>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">CREATE LOGIN [CORP\svc-orders-app] FROM WINDOWS;
GO
USE OrdersDb;
GO
CREATE SCHEMA app AUTHORIZATION dbo;
GO
CREATE USER [CORP\svc-orders-app] FOR LOGIN [CORP\svc-orders-app];
CREATE ROLE app_orders_role;
GRANT EXECUTE ON SCHEMA::app TO app_orders_role;
ALTER ROLE app_orders_role ADD MEMBER [CORP\svc-orders-app];</code></pre>
<p>This creates the login, the user, and a role that can only run procedures in the <code>app</code> schema.</p>
<h3>Prevent SQL Injection in Dynamic SQL</h3>
<p>Build dynamic SQL with parameters through <code>sp_executesql</code> and never concatenate user input into the query text. Microsoft guidance also says to review every piece of code that calls <code>EXEC</code>, <code>EXECUTE</code> or <code>sp_executesql</code>. Dynamic SQL also breaks ownership chaining, so the caller needs permissions on the underlying tables.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">DECLARE @sql nvarchar(max) =
    N'SELECT OrderId, OrderDate, Total
      FROM dbo.Orders
      WHERE CustomerId = @CustomerId AND OrderDate &gt;= @From;';

EXEC sys.sp_executesql
     @sql,
     N'@CustomerId int, @From date',
     @CustomerId = 42,
     @From = '2026-01-01';

-- Object names cannot be parameters, so quote them
DECLARE @table sysname = N'Orders';
SET @sql = N'SELECT COUNT(*) FROM dbo.' + QUOTENAME(@table) + N';';
EXEC sys.sp_executesql @sql;</code></pre>
<p>Typed parameters also give you plan reuse. <code>QUOTENAME</code> is for object names only, and you should still check them against an allow-list.</p>
<h3>Encrypt Data in Transit, at Rest and in Columns</h3>
<ul>
<li><strong>In transit:</strong> Use TLS with a valid server certificate. See the connection management section for <code>Encrypt</code> settings.</li>
<li><strong>At rest:</strong> Enable Transparent Data Encryption (TDE) to protect data files and backups from a stolen disk or file copy. TDE does not protect against a user who has permission to query the data.</li>
<li><strong>Sensitive columns:</strong> Use Always Encrypted when even DBAs should not read the values. The keys stay with the client.</li>
<li><strong>Backups:</strong> Encrypt them, and store the certificate or key separately. Without it, the backup cannot be restored.</li>
</ul>
<h3>Audit Activity and Reduce the Attack Surface</h3>
<p>Use SQL Server Audit to write to a file or the Windows event log. Capture logins, permission changes and access to sensitive tables. Disable or rename <code>sa</code> if you don&#8217;t need it, and keep <code>xp_cmdshell</code> and other unused features turned off. This is a core item on any SQL Server DBA checklist.</p>
<h3>Example: Patient Data in a Healthcare System</h3>
<p>Give the reporting team a read-only role with column-level permissions, so identifying columns stay out of reach.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">CREATE ROLE reporting_role;
GRANT SELECT ON dbo.Patient (PatientId, AdmissionDate, WardCode) TO reporting_role;
DENY  SELECT ON dbo.Patient (FullName, NationalId) TO reporting_role;</code></pre>
<p>Dynamic data masking can hide values in query results, but it is a convenience and not a security boundary. A user who can filter or infer values can still work around it, so rely on permissions and encryption.</p>
<h2 id="sql-server-backup-best-practices-high-availability-and-resto">SQL Server Backup Best Practices, High Availability and Restore Testing</h2>
<p>A backup is only proven when you have restored it. Match the recovery model to your recovery point objective (RPO, the amount of data loss you can accept), take full, differential and log backups, keep copies off the server, and test restores on a schedule. These are the core SQL Server backup best practices.</p>
<h3>Choose a Backup Strategy That Matches Your RPO and RTO</h3>
<p>The recovery model decides which backups are possible. RTO means recovery time objective, the time you can afford to be down.</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Strategy</th>
<th>RPO</th>
<th>RTO</th>
<th>Log growth risk</th>
</tr>
</thead>
<tbody>
<tr>
<td>Full only (SIMPLE recovery)</td>
<td>Back to the last full backup</td>
<td>Short, one restore</td>
<td>Low, the log is reused automatically</td>
</tr>
<tr>
<td>Full + differential (SIMPLE)</td>
<td>Back to the last differential</td>
<td>Short, two restores</td>
<td>Low</td>
</tr>
<tr>
<td>Full + differential + log (FULL recovery)</td>
<td>Minutes, set by log backup interval</td>
<td>Longer, a full chain plus point-in-time options</td>
<td>High if log backups stop</td>
</tr>
</tbody>
</table>
</figure>
<p>In FULL recovery, SQL Server keeps log records until a log backup has captured them. With no log backups, the log cannot be reused, so it grows until the disk is full. Switch to SIMPLE if you do not need point-in-time recovery.</p>
<p>Example: a retail orders database takes a full backup nightly, a differential every four hours and a log backup every 10 minutes. That gives an example RPO of about 10 minutes. It is an illustration, not a recommendation, so set your own interval from business needs.</p>
<h3>Use CHECKSUM, Compression and Encryption on Every Backup</h3>
<p>CHECKSUM detects page corruption while the backup runs. Compression reduces size and I/O. Encryption protects the file once it leaves the server.</p>
<p><code>RESTORE VERIFYONLY</code> is the minimum check. It confirms the backup is readable, but it does not prove the data is consistent. Only a real restore followed by <code>DBCC CHECKDB</code> on the restored copy does that.</p>
<h3>ZSTD Compression and Secondary Backups in SQL Server 2025</h3>
<p>ZSTD backup compression is GA in SQL Server 2025 but is not the default. Enable it per backup with <code>COMPRESSION (ALGORITHM = ZSTD, LEVEL = LOW | MEDIUM | HIGH)</code>, or instance-wide by setting <code>backup compression algorithm</code> to 3 with <code>sp_configure</code>. Test CPU cost and backup time first, because HIGH can take much longer.</p>
<p>Full, differential and log backups can now run on availability group secondary replicas (GA), which takes load off the primary. Backups to immutable storage are also GA, which helps against ransomware.</p>
<p>The animated diagram below shows the full path from backup to a verified restore.</p>
<figure class="wp-block-image size-full"><img decoding="async" src="https://thecodebuzz.com/wp-content/uploads/2026/10/sql-server-best-practices-guidelines-diagram-8.gif" alt="Pipeline: primary or AG secondary emits backups through a compress, encrypt, CHECKSUM gate to local and offsite copies, then restore test and CHECKDB." width="1200" height="675" /><figcaption>A backup is proven only when a scheduled restore plus DBCC CHECKDB succeeds, and the restore time gives your measured RTO.</figcaption></figure>
<h3>High Availability Is Not a Backup</h3>
<p>An availability group replicates a bad <code>DELETE</code> or corruption to the secondary just as quickly. Use HA for uptime and backups for recovery.</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Option</th>
<th>Scope</th>
<th>Failover</th>
<th>Readable secondary</th>
<th>Typical use</th>
</tr>
</thead>
<tbody>
<tr>
<td>Always On availability group</td>
<td>Database(s)</td>
<td>Automatic or manual</td>
<td>Yes</td>
<td>HA, read offload, backups on secondary</td>
</tr>
<tr>
<td>Failover cluster instance</td>
<td>Whole instance</td>
<td>Automatic, shared storage</td>
<td>No</td>
<td>Instance-level HA, jobs and logins included</td>
</tr>
<tr>
<td>Log shipping</td>
<td>Database</td>
<td>Manual</td>
<td>Optional, in standby mode</td>
<td>Simple DR to another site</td>
</tr>
</tbody>
</table>
</figure>
<h3>Protect Copies, Credentials and Keys</h3>
<p>Keep one copy on a local share for fast restores and one offsite or on immutable storage. Document the backup credential, certificate and private key, and store them separately from the backups. If you lose the certificate, encrypted backups cannot be read.</p>
<h3>Backup and Restore Test Script</h3>
<p>The script below backs up, restores to a test name with <code>MOVE</code>, and checks consistency. The test server needs the same certificate. Run <code>RESTORE FILELISTONLY</code> first to get the logical file names.</p>
<p class="code-label"><strong>SQL (T-SQL)</strong></p>
<pre><code class="language-sql">-- Optional: make ZSTD the instance default (SQL Server 2025)
EXEC sp_configure 'backup compression algorithm', 3;
RECONFIGURE;

BACKUP DATABASE SalesDB
TO DISK = N'D:\Backup\SalesDB_full.bak'
WITH CHECKSUM,
     COMPRESSION (ALGORITHM = ZSTD, LEVEL = MEDIUM),
     ENCRYPTION (ALGORITHM = AES_256, SERVER CERTIFICATE = BackupCert),
     STATS = 10;

BACKUP LOG SalesDB
TO DISK = N'D:\Backup\SalesDB_log.trn'
WITH CHECKSUM,
     COMPRESSION (ALGORITHM = ZSTD, LEVEL = LOW),
     ENCRYPTION (ALGORITHM = AES_256, SERVER CERTIFICATE = BackupCert);

-- On the restore test server
RESTORE FILELISTONLY FROM DISK = N'D:\Backup\SalesDB_full.bak';

RESTORE DATABASE SalesDB_RestoreTest
FROM DISK = N'D:\Backup\SalesDB_full.bak'
WITH MOVE N'SalesDB'     TO N'E:\RestoreTest\SalesDB_RestoreTest.mdf',
     MOVE N'SalesDB_log' TO N'F:\RestoreTest\SalesDB_RestoreTest.ldf',
     CHECKSUM, RECOVERY, STATS = 10;

DBCC CHECKDB (SalesDB_RestoreTest) WITH NO_INFOMSGS, ALL_ERRORMSGS;</code></pre>
<p>This restores the full backup under a new name and reports any corruption. Record how long the restore took, because that is your measured RTO.</p>
<p>For a point-in-time restore, restore the full backup (and the latest differential) with <code>NORECOVERY</code>. Then restore each log backup, and add <code>STOPAT = '2026-10-13T09:55:00'</code> to the last one with <code>RECOVERY</code>. This needs FULL recovery and an unbroken log chain.</p>
<h2 id="monitoring-sql-server-wait-stats-extended-events-and-perform">Monitoring SQL Server: Wait Stats, Extended Events and Performance Counters</h2>
<p>Start with wait statistics to see what the instance is waiting on. Then use Query Store and Extended Events to find the queries and events behind those waits. This order is the core of SQL Server performance tuning best practices, because it stops you from guessing.</p>
<h3>Common Wait Types and What They Point To</h3>
<p>A wait type is the reason a request had to pause. Treat it as a pointer, not a diagnosis. Confirm it with a query, a plan or a counter before you change anything.</p>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Wait</th>
<th>Usually points to</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>PAGEIOLATCH_*</code></td>
<td>Slow data storage or memory pressure</td>
</tr>
<tr>
<td><code>LCK_M_*</code></td>
<td>Blocking between sessions</td>
</tr>
<tr>
<td><code>WRITELOG</code></td>
<td>Slow transaction log storage</td>
</tr>
<tr>
<td><code>CXPACKET</code> / <code>CXCONSUMER</code></td>
<td>Parallelism (check MAXDOP and cost threshold)</td>
</tr>
<tr>
<td><code>RESOURCE_SEMAPHORE</code></td>
<td>Queries waiting for memory grants</td>
</tr>
</tbody>
</table>
</figure>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">SELECT TOP (10)
       wait_type,
       waiting_tasks_count,
       wait_time_ms,
       signal_wait_time_ms,
       CAST(100.0 * wait_time_ms / SUM(wait_time_ms) OVER () AS decimal(5,2)) AS pct_of_waits
FROM sys.dm_os_wait_stats
WHERE wait_time_ms &gt; 0
  AND wait_type NOT IN (N'SLEEP_TASK', N'LAZYWRITER_SLEEP', N'XE_TIMER_EVENT',
      N'XE_DISPATCHER_WAIT', N'REQUEST_FOR_DEADLOCK_SEARCH', N'CHECKPOINT_QUEUE',
      N'DIRTY_PAGE_POLL', N'LOGMGR_QUEUE', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
      N'SP_SERVER_DIAGNOSTICS_SLEEP', N'BROKER_TO_FLUSH', N'BROKER_TASK_STOP',
      N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', N'QDS_ASYNC_QUEUE', N'WAITFOR')
ORDER BY wait_time_ms DESC;</code></pre>
<p>This returns the top waits since the last restart, minus a partial list of idle waits. Take two snapshots and compare them to see current behaviour.</p>
<h3>Use Extended Events, Not Profiler</h3>
<p>Extended Events is the lightweight tracing system, and SQL Trace and Profiler are deprecated. Keep the built-in <code>system_health</code> session running for deadlock graphs. Add a small session for slow statements.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">CREATE EVENT SESSION [LongRunningStatements] ON SERVER
ADD EVENT sqlserver.sql_statement_completed
(
    ACTION (sqlserver.database_name, sqlserver.client_app_name, sqlserver.sql_text)
    WHERE duration &gt; 1000000   -- microseconds, so 1 second
)
ADD TARGET package0.event_file
(
    SET filename = N'LongRunningStatements.xel', max_file_size = 50, max_rollover_files = 4
)
WITH (MAX_DISPATCH_LATENCY = 30 SECONDS, STARTUP_STATE = ON);

ALTER EVENT SESSION [LongRunningStatements] ON SERVER STATE = START;</code></pre>
<p>The file target rolls over at a fixed size, so the session cannot fill the disk.</p>
<h3>Counters and Alerts Worth Setting Up</h3>
<ul>
<li><strong>Page life expectancy:</strong> Watch the trend against your own baseline. A fixed number such as 300 does not fit every server.</li>
<li><strong>Batch requests per second:</strong> Use it to read load changes next to waits.</li>
<li><strong>Log file percent used:</strong> Alert before the log fills the volume.</li>
<li><strong>Free space:</strong> Check data, log and tempdb volumes separately.</li>
<li><strong>AG synchronization lag:</strong> Alert when secondaries fall behind.</li>
<li><strong>Errors and jobs:</strong> Alert on severity 17 to 25 errors and on job failures.</li>
</ul>
<p>For backups, alert on the age of the last successful backup, not on whether the job ran. A job can finish without producing a usable backup. This also belongs on any SQL Server DBA checklist.</p>
<h2 id="patching-and-upgrading-to-sql-server-2025-what-to-check-firs">Patching and Upgrading to SQL Server 2025: What to Check First</h2>
<p>Patch on a regular cadence, test the upgrade on a copy that has the same linked servers, certificates and jobs, and plan the outage window before you start. Most upgrade surprises come from things outside the database files.</p>
<h3>Version, Support and Current Builds</h3>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Version</th>
<th>Mainstream support</th>
<th>Extended support</th>
<th>Latest build (October 2026)</th>
</tr>
</thead>
<tbody>
<tr>
<td>SQL Server 2019</td>
<td>Ended 28 February 2025</td>
<td>Until 8 January 2030</td>
<td>CU32 15.0.4430.1; CU32+GDR 15.0.4490.9</td>
</tr>
<tr>
<td>SQL Server 2022</td>
<td>Ends 11 January 2028</td>
<td>Check the Microsoft lifecycle page for the end date</td>
<td>CU27 16.0.4295.3</td>
</tr>
<tr>
<td>SQL Server 2025 (GA 18 November 2025, RTM 17.0.1000.7)</td>
<td>Ends 6 January 2031</td>
<td>Check the Microsoft lifecycle page for the end date</td>
<td>CU9 17.0.5005.3 (15 September 2026); GDR 17.0.1135.8; CU8+GDR 17.0.4085.5</td>
</tr>
</tbody>
</table>
</figure>
<p>A CU (cumulative update) carries fixes and features. A GDR (General Distribution Release) carries security-only fixes for servers that don&#8217;t apply CUs. Each instance sits on one of two tracks, and the rule is one-way.</p>
<ol>
<li>GDR track: the instance has only had GDR updates and receives security fixes only (e.g., 17.0.1135.8 for SQL Server 2025).</li>
<li>CU track: the instance has had at least one CU. From here, security-only fixes arrive as a CU+GDR package built on the CU you already have (e.g., CU8+GDR 17.0.4085.5).</li>
<li>Moving from GDR to CU is allowed. Install a CU and the instance joins the CU track.</li>
<li>Moving from CU back to GDR is not allowed. Once a CU is installed, only CU and CU+GDR packages apply.</li>
</ol>
<p>Decide the track before the first patch. If you may want bug fixes or features later, plan to move to the CU track once and stay there. If you only want security fixes, stay on GDR until you are ready to commit to CUs.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">SELECT SERVERPROPERTY('ProductVersion') AS ProductVersion,
       SERVERPROPERTY('ProductLevel')   AS ProductLevel,
       SERVERPROPERTY('Edition')        AS Edition;</code></pre>
<p>Compare the returned build number with the table above to see which track and update level the instance is on.</p>
<h3>Is the Upgrade Worth It?</h3>
<p>Yes for write-heavy or backup-heavy systems, after testing. The practical 2025 gains are:</p>
<ul>
<li>Optimized locking, which uses transaction ID (TID) locking and lock after qualification (LAQ) to reduce blocking and lock memory, and to avoid lock escalation, with no application code changes.</li>
<li>Query Store on readable secondaries, on by default (in 2022 it was off by default and needed trace flag 12606).</li>
<li>ZSTD backup compression and backups on AG secondaries.</li>
<li>Resource Governor and higher limits in Standard edition.</li>
<li>tempdb space governance.</li>
</ul>
<p>The trade-off is testing effort. DiskANN vector indexes are preview only, so keep them out of production.</p>
<h3>What Breaks: Linked Servers and TLS</h3>
<p>A DBA report found that linked servers using SQLNCLI or MSOLEDBSQL can fail after an in-place upgrade to 2025, because of stricter TLS certificate validation. Setup can also restart the service up to three times, so the outage is longer than one restart. Fix the certificates or the provider settings before cutover, then test every linked server afterwards.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">DECLARE @name sysname;
DECLARE ls CURSOR FAST_FORWARD FOR
    SELECT name FROM sys.servers WHERE is_linked = 1;
OPEN ls;
FETCH NEXT FROM ls INTO @name;
WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY
        EXEC sp_testlinkedserver @name;
        PRINT @name + ': OK';
    END TRY
    BEGIN CATCH
        PRINT @name + ': FAILED - ' + ERROR_MESSAGE();
    END CATCH;
    FETCH NEXT FROM ls INTO @name;
END;
CLOSE ls;
DEALLOCATE ls;</code></pre>
<p>The animated diagram below shows the safe order of steps, including the retry loop for failed linked server tests.</p>
<h3>In-Place vs Side-by-Side Migration</h3>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Approach</th>
<th>Rollback</th>
<th>Downtime</th>
<th>Effort</th>
</tr>
</thead>
<tbody>
<tr>
<td>In-place</td>
<td>Hard; restore the old setup from backups</td>
<td>Longer (service restarts during Setup)</td>
<td>Low</td>
</tr>
<tr>
<td>Side-by-side (backup/restore or log shipping cutover)</td>
<td>Easy; old server stays intact</td>
<td>Short, limited to the cutover</td>
<td>Higher</td>
</tr>
</tbody>
</table>
</figure>
<p>Use side-by-side for critical systems. Use in-place only for small or non-critical instances where a longer window is acceptable.</p>
<h3>After the Upgrade: Compatibility Level</h3>
<p>Keep the old compatibility level until the application is tested. Let Query Store capture baseline plans, then raise the level and force back any plan that regressed.</p>
<p>The level used below, 170 for SQL Server 2025, is not in the verified research for this article. Confirm it in the Microsoft documentation article &#8220;ALTER DATABASE compatibility level (Transact-SQL)&#8221; before you run the statement, and use the highest level that article lists for your version.</p>
<p class="code-label"><strong>T-SQL</strong></p>
<pre><code class="language-sql">-- Check the current level
SELECT name, compatibility_level FROM sys.databases WHERE name = N'SalesDb';

-- Raise it after testing. Replace 170 if the Microsoft docs list a different
-- level for your SQL Server 2025 build.
ALTER DATABASE SalesDb SET COMPATIBILITY_LEVEL = 170;</code></pre>
<h2 id="common-anti-patterns-and-sql-server-dba-production-readiness">Common Anti-Patterns and SQL Server DBA Production Readiness Checklist</h2>
<p>Most production incidents trace back to a small set of repeated mistakes. Use the table below to spot them, then run the checklist before a server goes live.</p>
<h3>Common SQL Server Anti-Patterns</h3>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Anti-pattern</th>
<th>Symptom</th>
<th>Fix</th>
</tr>
</thead>
<tbody>
<tr>
<td>Default <code>max server memory</code></td>
<td>OS paging, memory pressure on the instance</td>
<td>Cap it, starting near 75% of available memory</td>
</tr>
<tr>
<td>MAXDOP 1 everywhere, or default 0 on a large NUMA box</td>
<td>Slow reports and index builds, or heavy parallel waits</td>
<td>Start from the NUMA-based guidance, scope per database</td>
</tr>
<tr>
<td>Cost threshold left at 5</td>
<td>Tiny queries going parallel</td>
<td>Raise it from observed plan costs, then check CXPACKET/CXCONSUMER</td>
</tr>
<tr>
<td>Single tempdb file, small autogrow steps</td>
<td>PAGELATCH contention, pauses during growth</td>
<td>Equally sized, pre-sized files with fixed growth</td>
</tr>
<tr>
<td>Clustered key on <code>NEWID()</code> GUID</td>
<td>Page splits, fragmentation</td>
<td>Use an ever-increasing key or <code>NEWSEQUENTIALID</code></td>
</tr>
<tr>
<td>Functions on indexed columns in <code>WHERE</code></td>
<td>Index scans instead of seeks</td>
<td>Rewrite as SARGable range predicates</td>
</tr>
<tr>
<td><code>SELECT *</code></td>
<td>Extra I/O, covering indexes unused</td>
<td>List only the needed columns</td>
</tr>
<tr>
<td>String-built dynamic SQL</td>
<td>Injection risk, plan cache bloat</td>
<td>Use <code>sp_executesql</code> with typed parameters</td>
</tr>
<tr>
<td>Apps connecting as <code>sa</code> or <code>db_owner</code></td>
<td>Large blast radius after a compromise</td>
<td>Custom role with <code>EXECUTE</code> on a schema</td>
</tr>
<tr>
<td><code>TrustServerCertificate=true</code> in production</td>
<td>No server identity check</td>
<td>Fix the certificate chain and host name</td>
</tr>
<tr>
<td>FULL recovery with no log backups</td>
<td>Log file grows until the disk fills</td>
<td>Schedule log backups, or use SIMPLE if the RPO allows</td>
</tr>
<tr>
<td>Backups never restored</td>
<td>Surprise failure at recovery time</td>
<td>Scheduled test restore plus <code>DBCC CHECKDB</code></td>
</tr>
<tr>
<td>Linked servers not tested after upgrade</td>
<td>Failures after cutover</td>
<td>Run <code>sp_testlinkedserver</code> on a copy first</td>
</tr>
</tbody>
</table>
</figure>
<h3>SQL Server Production Readiness Checklist</h3>
<p>This SQL Server DBA checklist combines the configuration, security and backup rules from the sections above. Work through it in order.</p>
<ol>
<li>Confirm the version and patch level, and choose the CU or GDR track on purpose.</li>
<li>Set the SQL Server max server memory setting to a specific value, with <code>min server memory</code> at 0.</li>
<li>Set MAXDOP and cost threshold for parallelism from the NUMA rule and measured plan costs.</li>
<li>Lay out tempdb with equally sized, pre-sized files on fast storage.</li>
<li>Separate data, log and tempdb volumes where the storage design allows.</li>
<li>Enable instant file initialization for data files.</li>
<li>Enable Query Store on user databases with a sensible size and capture mode.</li>
<li>Choose the isolation level deliberately, and test RCSI before turning it on.</li>
<li>Set connection strings with <code>Encrypt</code>, the listener name and <code>MultiSubnetFailover=True</code> where it applies.</li>
<li>Create least-privilege roles for each application, and disable or rename <code>sa</code>.</li>
<li>Enforce TLS in transit and enable TDE at rest.</li>
<li>Turn on SQL Server Audit for logins, permission changes and sensitive tables.</li>
<li>Schedule full, differential and log backups with <code>CHECKSUM</code>, compression and encryption.</li>
<li>Keep an offsite or immutable copy, and document backup keys and certificates.</li>
<li>Restore on a schedule and run <code>DBCC CHECKDB</code> on the restored copy.</li>
<li>Alert on wait trends, failed jobs, severity 17-25 errors and the age of the last good backup.</li>
<li>Write the upgrade plan, including linked server tests and the outage window.</li>
</ol>
<p>These items also form a short SQL Server security best practices review (items 10 to 12) and a SQL Server backup best practices review (items 13 to 15).</p>
<h2 id="key-takeaways">Key takeaways</h2>
<ul>
<li><strong>Cap max server memory:</strong> Start from about 75% of the memory that is available to SQL Server (after other processes and other instances), keep min server memory at 0, and always use a specific value if Lock Pages in Memory is granted.</li>
<li><strong>Tune MAXDOP and cost threshold by measurement:</strong> Begin with the Microsoft NUMA-based MAXDOP guidance, use database-scoped MAXDOP or Resource Governor for exceptions, and raise cost threshold for parallelism above the default of 5 after checking CXPACKET/CXCONSUMER waits.</li>
<li><strong>Use Strict or Mandatory encryption with a valid certificate:</strong> Fix the certificate chain or host name when connections fail after a driver upgrade. Avoid <code>TrustServerCertificate=true</code> in production.</li>
<li><strong>Give applications least privilege:</strong> Use a dedicated login and a role with EXECUTE on a schema, never <code>sa</code> or <code>db_owner</code>, and pass every value through typed parameters.</li>
<li><strong>Enable Query Store:</strong> Turn it on for every database you care about, so you can find regressions, force a known good plan, and keep baseline plans before a compatibility level change.</li>
<li><strong>Test restores, not just backups:</strong> Take backups with CHECKSUM, keep an offsite or immutable copy, and restore to a test name regularly, then run DBCC CHECKDB on the restored copy.</li>
<li><strong>Test the SQL Server 2025 upgrade on a copy first:</strong> Include linked servers, certificates and jobs, and run <code>sp_testlinkedserver</code> afterwards because stricter TLS validation can break them. Evaluate optimized locking with RCSI for write-heavy workloads, and keep DiskANN vector indexes out of production while they are preview only.</li>
</ul>
<p>That&#8217;s all! Happy coding!</p>
<p>Did this guide help you to set up and tune SQL Server for production? Please share your questions or experience in the comments below.</p>
<p>Bookmark this page for your next production review and share it with your team. Subscribe to TheCodeBuzz to get new database best-practice guides in your inbox.</p>
<h2 id="faq">FAQ</h2>
<h3>What should I set max server memory to in SQL Server?</h3>
<p>Start with about 75% of the memory that is available to the instance, meaning the total minus what the OS, other instances and other processes use, and leave min server memory at 0. The default is about 2 TB, which is effectively unlimited, so you should cap it on every version. If Lock Pages in Memory is granted to the service account, you must set a specific value, not the default. Set it with <code>sp_configure 'max server memory (MB)'</code> followed by <code>RECONFIGURE</code>, and check the result in <code>sys.configurations</code>.</p>
<h3>What is the best MAXDOP and cost threshold for parallelism setting?</h3>
<p>There is no single best value. Start from Microsoft&#8217;s NUMA-based MAXDOP guidance, set it per database with <code>ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP</code> for mixed workloads, and use Resource Governor workload groups where one workload needs a different limit. Avoid MAXDOP 1 server-wide, because it breaks parallel index builds and slows reporting queries. The cost threshold for parallelism defaults to 5, which is too low for modern hardware, so raise it based on observed plan costs and check the effect on CXPACKET and CXCONSUMER waits.</p>
<h3>How many tempdb files should I have, and how should I size them?</h3>
<p>Start with a small number of equally sized data files, up to the number of cores as Microsoft guidance suggests, and add more only if monitoring shows allocation contention. Pre-size the files and use a fixed growth increment, so autogrow stays an emergency measure and not a routine event. Equal sizes matter because SQL Server spreads allocations across files, and uneven files lead to uneven use. On SQL Server 2025 you can also use Resource Governor tempdb space governance, which stops a workload with an error when it exceeds its limit.</p>
<h3>Why does my app fail to connect after upgrading Microsoft.Data.SqlClient, with certificate errors?</h3>
<p>The driver now defaults to <code>Encrypt=Mandatory</code> and <code>TrustServerCertificate=false</code>, so it rejects a server certificate that the client does not trust. This is not a driver bug. Fix the certificate chain or make sure the host name in the connection string matches the certificate, instead of switching on <code>TrustServerCertificate=true</code>, which skips server identity checks. Use <code>Encrypt=Strict</code> where the server supports TDS 8.0, because Strict cannot be bypassed with <code>TrustServerCertificate</code>.</p>
<h3>Should I enable Query Store, optimized locking or Read Committed Snapshot Isolation?</h3>
<p>Yes to Query Store on every user database you care about, because it helps you find regressions and force a known good plan. Enable Read Committed Snapshot Isolation (RCSI) after testing, since it adds version storage and changes behavior for code that relied on blocking reads. Optimized locking comes with SQL Server 2025 and needs no application code changes. It works best together with RCSI, so it is a good reason to test 2025 for heavy write workloads.</p>
<h2 id="sources">Sources and further reading</h2>
<ul>
<li><a href="https://learn.microsoft.com/en-us/sql/sql-server/what-s-new-in-sql-server-2025?view=sql-server-ver17" target="_blank" rel="noopener">What&#8217;s New in SQL Server 2025 &#8211; SQL Server</a> (Microsoft Learn)</li>
<li><a href="https://learn.microsoft.com/en-us/troubleshoot/sql/releases/download-and-install-latest-updates" target="_blank" rel="noopener">Latest Updates and Version History for SQL Server</a> (Microsoft Learn)</li>
<li><a href="https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/server-memory-server-configuration-options?view=sql-server-ver17" target="_blank" rel="noopener">Server Memory Configuration Options &#8211; SQL Server</a> (Microsoft Learn)</li>
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/memory-management-architecture-guide?view=sql-server-ver17" target="_blank" rel="noopener">Memory Management Architecture Guide &#8211; SQL Server</a> (Microsoft Learn)</li>
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor?view=sql-server-ver17" target="_blank" rel="noopener">Resource Governor &#8211; SQL Server</a> (Microsoft Learn)</li>
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/security/sql-server-security-best-practices?view=sql-server-ver17" target="_blank" rel="noopener">SQL Server Security Best Practices &#8211; SQL Server</a> (Microsoft Learn)</li>
<li><a href="https://learn.microsoft.com/en-us/sql/connect/ado-net/encryption-and-certificate-validation?view=sql-server-ver17" target="_blank" rel="noopener">Encryption and Certificate Validation in Microsoft.Data.SqlClient</a> (Microsoft Learn)</li>
<li><a href="https://techcommunity.microsoft.com/blog/azuresqlblog/whats-new-in-the-backuprestore-area-in-sql-server-2025/4474613" target="_blank" rel="noopener">Whats new in the Backup/Restore area in SQL Server 2025</a> (Microsoft Tech Community)</li>
<li><a href="https://www.mssqltips.com/sqlservertip/8290/sql-server-2025-new-features/" target="_blank" rel="noopener">SQL Server 2025 New Features and Enhancements</a> (MSSQLTips)</li>
<li><a href="https://www.sqlservercentral.com/articles/sql-server-2025-backup-compression-algorithm" target="_blank" rel="noopener">SQL Server 2025 Backup Compression Algorithm</a> (SQLServerCentral)</li>
</ul>
<p><em>Diagrams are original illustrations created by and for TheCodeBuzz.</em></p><p>The post <a href="https://thecodebuzz.com/sql-server-best-practices-guidelines/">SQL Server Best Practices and Guidelines-2026</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://thecodebuzz.com/sql-server-best-practices-guidelines/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PostgreSQL &#8211; Best Practices for Production</title>
		<link>https://thecodebuzz.com/postgresql-best-practices-production/</link>
					<comments>https://thecodebuzz.com/postgresql-best-practices-production/#respond</comments>
		
		<dc:creator><![CDATA[Izzy]]></dc:creator>
		<pubDate>Thu, 08 Oct 2026 05:31:19 +0000</pubDate>
				<category><![CDATA[Database Best Practices]]></category>
		<category><![CDATA[High Availability]]></category>
		<category><![CDATA[Indexing]]></category>
		<category><![CDATA[pg_upgrade]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">https://thecodebuzz.com/?p=30710</guid>

					<description><![CDATA[<p>Production PostgreSQL best practices: patching, upgrades from 14, indexing, UUIDv7 keys, checksums, OAuth and a readiness checklist you can apply today.</p>
<p>The post <a href="https://thecodebuzz.com/postgresql-best-practices-production/">PostgreSQL – Best Practices for Production</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>In our last article, we learned <a href="https://thecodebuzz.com/mongodb-security-guidelines-and-best-practices/">MongoDB specific guidelines</a>. Today in this article , we will learn about PostgreSQL.</p>
<p>&nbsp;</p>
<p>Most PostgreSQL outages and security incidents come from clusters that were never patched or never upgraded, not from exotic bugs. This guide is for engineers, architects and DBAs who run PostgreSQL in production. It is a compact reference you can bookmark and check a cluster against.</p>
<p>&nbsp;</p>
<p>Here is where things stand in October 2026. PostgreSQL 18 is the current stable major, and 18.6, dated 2026-08-13, is its latest minor. PostgreSQL 14 receives its last fixes on 2026-11-12, so anyone still on it has a deadline measured in weeks. I cover patching and upgrades first, because that is where most production risk sits.</p>
<p>After that come the PostgreSQL 18 features that change how you design schemas and indexes, with the reasoning behind each rule so you can judge where it applies to your workload. These PostgreSQL best practices start with a summary table and end with a checklist and FAQ.</p>
<p>&nbsp;</p>
<blockquote>
<p><strong>Version note:</strong> this guide targets PostgreSQL 18 (18.6), and also covers 17.11, 16.15, 15.19 and 14.24 for patching and upgrade planning, with PostgreSQL 19 Beta 4 mentioned only for testing.</p>
<p>&nbsp;</p>
</blockquote>
<h2 id="postgresql-best-practices-at-a-glance">PostgreSQL best practices at a glance</h2>
<figure class="wp-block-table">
<table>
<thead>
<tr>
<th>Area</th>
<th>Do this</th>
<th>Avoid this</th>
</tr>
</thead>
<tbody>
<tr>
<td>Patching</td>
<td>Run the latest minor of your major: 18.6, 17.11, 16.15, 15.19 or 14.24. Minors contain only bug and security fixes, so they are low-risk, but still test them in staging first. They need a restart.</td>
<td>Pinning old minors. 18.1 fixed CVE-2025-12817 and 18.4 fixed CVE-2026-6575.</td>
</tr>
<tr>
<td>Versions</td>
<td>Run a supported major. PostgreSQL 14 receives its last fixes on November 12, 2026, so plan that upgrade now. Test your workload against PostgreSQL 19 Beta 4 in a non-production environment.</td>
<td>Running any beta in production, or staying on 14 after its end of support.</td>
</tr>
<tr>
<td>Backups and PITR</td>
<td>Take regular base backups and archive WAL continuously (<code>archive_mode</code> plus an archive command or library that reports failures). Rehearse restores to a chosen point in time, and monitor archive lag.</td>
<td>Relying on <code>pg_dump</code> alone for large production systems, or keeping backups you have never restored.</td>
</tr>
<tr>
<td>Replication and failover</td>
<td>Run at least one streaming standby in another failure domain. Use tested, automated failover tooling with fencing of the old primary. Choose <code>synchronous_commit</code> and synchronous standbys deliberately, based on how much data loss you can accept.</td>
<td>Untested manual failover, and abandoned replication slots that make the primary retain WAL until the disk fills.</td>
</tr>
<tr>
<td>Autovacuum and bloat</td>
<td>Keep autovacuum on. Tune per-table thresholds on hot, high-churn tables. Watch dead tuples, table and index size, and the oldest open transaction.</td>
<td>Disabling autovacuum, or leaving sessions idle in a transaction, which stops cleanup of dead rows.</td>
</tr>
<tr>
<td>Connection pooling</td>
<td>Put a pooler such as PgBouncer in front of the database and keep server-side connections to a small, measured number.</td>
<td>Thousands of direct application connections. Also avoid transaction-mode pooling with session state (session-level <code>SET</code>, advisory locks) without checking compatibility.</td>
</tr>
<tr>
<td>Memory and <code>max_connections</code></td>
<td>Start <code>shared_buffers</code> at roughly a quarter of RAM and adjust from measurements. Size <code>work_mem</code> against the worst-case number of concurrent sorts and hashes. Keep <code>max_connections</code> modest and rely on the pooler.</td>
<td>Raising <code>max_connections</code> to hide pool exhaustion, or a large global <code>work_mem</code> multiplied across many sessions.</td>
</tr>
<tr>
<td>TLS and SCRAM</td>
<td>Set <code>password_encryption = scram-sha-256</code>. Enable <code>ssl</code> and use <code>hostssl</code> lines in <code>pg_hba.conf</code> with <code>scram-sha-256</code>.</td>
<td><code>trust</code> rules, unencrypted remote connections and legacy <code>md5</code> hashes.</td>
</tr>
<tr>
<td>Authentication</td>
<td>Where you have an identity provider, configure OAuth in <code>pg_hba.conf</code> and load validators with <code>oauth_validator_libraries</code>.</td>
<td>Shared static passwords.</td>
</tr>
<tr>
<td>Monitoring</td>
<td>Load <code>pg_stat_statements</code> through <code>shared_preload_libraries</code>. Set <code>log_min_duration_statement</code> to a threshold that fits your workload and enable <code>log_lock_waits</code>. Alert on replication lag, archive failures, disk space and connection saturation.</td>
<td>Logging every statement permanently, or finding slow queries only after users report them.</td>
</tr>
<tr>
<td>Primary keys</td>
<td>Use <code>uuidv7()</code> for timestamp-ordered keys.</td>
<td>Random UUIDs as keys on large B-tree indexes, because of poor locality.</td>
</tr>
<tr>
<td>Composite indexes</td>
<td>Order columns for your main queries. PostgreSQL 18 skip scan lets a query omit an equality condition on leading columns. It helps most when the omitted leading column has few distinct values. Confirm with <code>EXPLAIN</code>.</td>
<td>Dropping or reordering existing indexes because skip scan exists, or adding redundant indexes without checking plans.</td>
</tr>
<tr>
<td>Integrity</td>
<td>Use <code>WITHOUT OVERLAPS</code> and <code>PERIOD</code> temporal constraints.</td>
<td>Application-side overlap checks.</td>
</tr>
<tr>
<td>Storage</td>
<td>Keep data checksums, which <code>initdb</code> enables by default in 18. When upgrading a cluster that has none, <code>pg_upgrade</code> needs matching settings, so initialize the new cluster with <code>--no-data-checksums</code>.</td>
<td>Turning checksums off without a reason.</td>
</tr>
<tr>
<td>I/O</td>
<td>Use 18 async I/O (<code>io_method</code>) for reads. Inspect <code>pg_aios</code>. Benchmark on your own storage before changing the default.</td>
<td>Changing <code>io_method</code> on assumptions.</td>
</tr>
</tbody>
</table>
</figure>
<p>Minor releases contain only bug and security fixes, which is why they are low-risk to apply. Low-risk is not no-risk: read the release notes, test against your workload and schedule the restart. The CVE examples above show why you should not defer them for long.</p>
<p>&nbsp;</p>
<p>Key order matters because a B-tree keeps neighbouring values on neighbouring pages. Time-ordered keys append to the right edge of the index, while random keys touch pages all over it, which hurts cache hit rates on large tables.</p>
<p>&nbsp;</p>
<p>Skip scan changes the column-order trade-off but does not remove it. PostgreSQL has to probe the index once for each distinct value of the omitted leading column. With a handful of values that is cheap.</p>
<p>&nbsp;</p>
<p>With millions of values it is not, and an index that leads with the column you actually filter on is still the better choice. Check the plan before you change any existing index.</p>
<h3> </h3>
<h3>Example: uuidv7 key, temporal constraint and a skip scan candidate</h3>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">CREATE EXTENSION IF NOT EXISTS btree_gist;

CREATE TABLE room_booking (
    booking_id uuid NOT NULL DEFAULT uuidv7() PRIMARY KEY,
    tenant_id  integer NOT NULL,
    room_id    integer NOT NULL,
    status     text NOT NULL,   -- few distinct values, for example 'confirmed' or 'cancelled'
    during     tstzrange NOT NULL,
    CONSTRAINT no_double_booking
        UNIQUE (room_id, during WITHOUT OVERLAPS)
);

-- Leading column has few distinct values; queries may filter on tenant_id alone.
CREATE INDEX room_booking_status_tenant_idx
    ON room_booking (status, tenant_id);</code></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The scalar <code>room_id</code> in the temporal key needs <code>btree_gist</code>. The range column <code>during</code> is what the constraint checks for overlap. The index behind that constraint also starts with <code>room_id</code>, so lookups by room already have an index and you do not need to add another.</p>
<p>&nbsp;</p>
<p>The <code>(status, tenant_id)</code> index is the skip scan candidate. The query below has an equality condition on <code>tenant_id</code> but none on the leading column <code>status</code>. Before PostgreSQL 18, this index could not serve it efficiently. Run it against representative data after an <code>ANALYZE</code>. On a tiny table the planner may prefer a sequential scan, so the <code>SET LOCAL</code> line is for testing only and shows whether the index is usable at all.</p>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">ANALYZE room_booking;

BEGIN;
SET LOCAL enable_seqscan = off;   -- test only: see whether the index can serve the query

EXPLAIN (ANALYZE, BUFFERS)
SELECT booking_id
FROM room_booking
WHERE tenant_id = 42;

ROLLBACK;</code></pre>
<p>In the plan, look for a scan on <code>room_booking_status_tenant_idx</code> with <code>tenant_id = 42</code> as the index condition, even though the query never mentions <code>status</code>.</p>
<p>PostgreSQL 18 also reports the number of index searches in <code>EXPLAIN ANALYZE</code>. A skip scan shows roughly one search per distinct <code>status</code> value.</p>
<p>Then rerun the query without the <code>SET LOCAL</code> line and compare timing and buffer counts with the plan the planner picks on its own. If the planner chooses a sequential scan or another index and is faster, keep that plan. If <code>status</code> has many distinct values in your data, a separate index on <code>(tenant_id)</code> is the better design.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2 id="plan-upgrades-and-the-production-readiness-checklist">Plan upgrades and the production readiness checklist</h2>
<h3>Support lifecycle</h3>
<p>PostgreSQL ships a major version about once a year and supports each for five years. PostgreSQL 18 was first released on 2025-09-25, and its final release is due 2030-11-14. PostgreSQL 14 stops receiving fixes on 2026-11-12, so schedule that move now. Since version 10, minors increment the second number (18.5 to 18.6).</p>
<p>&nbsp;</p>
<p>Minor releases carry only bug and security fixes, so they are low-risk to apply, but not zero-risk. Test them in staging and keep a rollback plan. Apply them promptly. Release 18.1 fixed CVE-2025-12817, where <code>CREATE STATISTICS</code> skipped a schema <code>CREATE</code> privilege check.</p>
<p>&nbsp;</p>
<p>Release 18.4 fixed CVE-2026-6575 in <code>pg_restore_attribute_stats</code> along with more than 60 bugs. As of early October 2026 the newest minors are 18.6, 17.11, 16.15, 15.19 and 14.24, all dated 2026-08-13.</p>
<p>&nbsp;</p>
<p>PostgreSQL 19 is in beta (Beta 4 was announced on 2026-09-24). Do not run it in production, but do test your own workloads against it so you find regressions early.</p>
<p>&nbsp;</p>
<h3>Upgrading with pg_upgrade</h3>
<p>PostgreSQL 18 keeps planner statistics across the upgrade, runs checks in parallel with <code>--jobs</code>, and adds <code>--swap</code>, which swaps directories instead of copying, cloning or linking. The animated diagram below walks through this path.</p>
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" src="https://thecodebuzz.com/wp-content/uploads/2026/10/postgresql-best-practices-production-diagram-2.gif" alt="Decision path for upgrading PostgreSQL 14: check checksums, run initdb, pg_upgrade --check, --swap, analyze, then a supported major." width="1200" height="675" />
<figcaption>Match the new cluster&#8217;s checksum setting to the old one, dry-run with &#8211;check, then upgrade with &#8211;swap after a verified backup.</figcaption>
</figure>
<p>Four rules govern the new cluster and the run itself:</p>
<p>&nbsp;</p>
<ul>
<li><strong>Compatible encoding and locale.</strong> Initialise the new cluster with an encoding and locale that match the old one. <code>pg_upgrade</code> refuses to proceed if they differ. Read the old values first and pass them to <code>initdb</code> explicitly rather than relying on the environment.</li>
<li><strong>Matching checksum settings.</strong> <code>initdb</code> in PostgreSQL 18 enables data checksums by default, and <code>pg_upgrade</code> requires both clusters to agree. If the old cluster has none, create the new one with <code>--no-data-checksums</code>. You can enable checksums later, offline, with <code>pg_checksums --enable</code> while the cluster is cleanly shut down. It rewrites every data file, so plan the window.</li>
<li><strong>Run as the <code>postgres</code> user.</strong> Run <code>initdb</code> and <code>pg_upgrade</code> as the operating-system user that owns the data directories, normally <code>postgres</code>. Running as root, or as a different user, causes permission failures or leaves files with the wrong owner.</li>
<li><strong><code>--swap</code> leaves the old cluster unusable.</strong> It reuses the old cluster&#8217;s files instead of copying them, so you cannot start the old cluster afterwards. Your rollback is the backup you took before the upgrade, so confirm it restores before you begin.</li>
</ul>
<p>&nbsp;</p>
<p class="code-label"><strong>SQL</strong></p>
<p>&nbsp;</p>
<pre><code class="language-sql">-- Run on the OLD cluster: encoding and locale to reuse for initdb
SELECT datname,
       pg_encoding_to_char(encoding) AS encoding,
       datcollate,
       datctype
FROM pg_database
WHERE datname NOT IN ('template0', 'template1');</code></pre>
<p class="code-label"><strong>Bash/shell</strong></p>
<pre><code class="language-bash"># Run everything as the postgres user
sudo -iu postgres

# Does the old cluster use checksums?
pg_controldata -D /var/lib/postgresql/14/main | grep -i checksum

# New cluster: match encoding and locale from the query above.
# Add --no-data-checksums ONLY if the old cluster has no checksums.
/usr/lib/postgresql/18/bin/initdb \
  --encoding=UTF8 --locale=en_US.UTF-8 \
  --no-data-checksums \
  -D /var/lib/postgresql/18/main

# Dry run: checks only, changes nothing
/usr/lib/postgresql/18/bin/pg_upgrade --check --jobs=4 \
  -b /usr/lib/postgresql/14/bin -B /usr/lib/postgresql/18/bin \
  -d /var/lib/postgresql/14/main -D /var/lib/postgresql/18/main

# Real run, after a verified backup. The old cluster is unusable afterwards.
/usr/lib/postgresql/18/bin/pg_upgrade --jobs=4 --swap \
  -b /usr/lib/postgresql/14/bin -B /usr/lib/postgresql/18/bin \
  -d /var/lib/postgresql/14/main -D /var/lib/postgresql/18/main

# Optional, later, with the cluster cleanly shut down:
# pg_checksums --enable -D /var/lib/postgresql/18/main</code></pre>
<h3> </h3>
<h3> </h3>
<h3>After the upgrade</h3>
<p>&nbsp;</p>
<p>Do not reopen the application to traffic until you have checked three things.</p>
<ol>
<li>Start the new cluster and confirm the version with <code>SELECT version();</code>.</li>
<li>Check statistics. PostgreSQL 18 carries planner statistics across, which shortens the slow period after an upgrade, but verify rather than assume. Find tables that have rows but no statistics, then run <code>ANALYZE</code>.</li>
<li>Run your application&#8217;s test suite and a representative query set against the new cluster. Compare the plans and timings of your slowest queries with a pre-upgrade baseline.</li>
</ol>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">-- Tables that have rows but no planner statistics
SELECT c.oid::regclass AS table_name, c.reltuples::bigint AS est_rows
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r', 'm')
  AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
  AND c.reltuples &gt; 0
  AND NOT EXISTS (
    SELECT 1 FROM pg_stats s
    WHERE s.schemaname = n.nspname AND s.tablename = c.relname
  );</code></pre>
<p class="code-label"><strong>Bash/shell</strong></p>
<pre><code class="language-bash"># Refresh statistics in every database
vacuumdb --all --analyze-only --jobs=4</code></pre>
<h3> </h3>
<h3>Low-downtime alternative: logical replication</h3>
<p>If you cannot afford the downtime of <code>pg_upgrade</code>, build a new cluster on the target major version and keep it in sync with logical replication. Then switch applications over in a short window. PostgreSQL 17 improved logical replication for high-availability setups and major-version upgrades, so this path is better supported on recent versions. It also gives you a rollback: the old cluster stays intact until you decide to retire it.</p>
<p>The cost is more moving parts. Logical replication does not copy schema changes, so you must create the schema on the target and freeze DDL during the migration.</p>
<p>Sequence values need to be synchronised before cutover.</p>
<p>Tables need suitable replica identities, usually a primary key. Rehearse the whole procedure on a copy of production first.</p>
<h3> </h3>
<h3>Production readiness checklist</h3>
<p>&nbsp;</p>
<p>Each item names something you can check. If you cannot show the evidence, treat the item as not done.</p>
<ol>
<li><strong>Latest minor applied.</strong> <code>SHOW server_version;</code> matches the newest minor of your major (18.6, 17.11, 16.15, 15.19 or 14.24 as of this writing).</li>
<li><strong>Supported major with a dated plan.</strong> You are not on a version past its end-of-fix date. If you run PostgreSQL 14, the upgrade must finish before 2026-11-12.</li>
<li><strong>WAL archiving works.</strong> <code>archive_mode = on</code> with a working archive command or library. <code>pg_stat_archiver</code> shows a recent <code>last_archived_time</code> and a <code>failed_count</code> that is not growing. Alert when archiving fails, because unarchived WAL piles up on the primary&#8217;s disk.</li>
<li><strong>A restore has been tested.</strong> You have restored a base backup plus archived WAL to a separate host, reached a chosen point in time, and run application queries against it. Record the date and how long it took, and repeat on a schedule.</li>
<li><strong><code>pg_stat_statements</code> is enabled.</strong> It is in <code>shared_preload_libraries</code> (this needs a restart), and <code>CREATE EXTENSION pg_stat_statements;</code> has been run in the database you query. A dashboard or a regular review uses it to find the slowest and most frequent statements.</li>
<li><strong>Autovacuum is monitored.</strong> You alert on dead tuples and time since the last autovacuum for large tables, on long-running transactions and stale replication slots that hold back cleanup, and on transaction ID age (<code>age(datfrozenxid)</code>) approaching the freeze limits.</li>
<li><strong>TLS is required.</strong> <code>ssl = on</code> with a valid certificate, and <code>pg_hba.conf</code> uses <code>hostssl</code> entries rather than plain <code>host</code> for network clients. Clients connect with <code>sslmode=verify-full</code> where possible.</li>
<li><strong>Passwords use <code>scram-sha-256</code>.</strong> <code>password_encryption = scram-sha-256</code>, and no line in <code>pg_hba.conf</code> uses <code>md5</code> or <code>trust</code> for network access. Existing <code>md5</code> hashes cannot be converted, so reset those passwords after changing the setting.</li>
<li><strong>Least-privilege roles.</strong> Applications do not connect as a superuser or as the schema owner. Check with <code>\du</code> and by reviewing grants.</li>
<li><strong>Replication lag has thresholds.</strong> Derive them from your recovery point objective: one warning level and one paging level, measured on <code>pg_stat_replication</code> (<code>replay_lag</code> or byte lag) and on standbys. Alert also when a standby disconnects entirely, since a missing row looks like zero lag.</li>
<li><strong>Failover has been exercised.</strong> You have promoted a standby on purpose and confirmed that applications reconnect.</li>
<li><strong>Data checksums are on, or the plan is written down.</strong> New PostgreSQL 18 clusters have them by default. For older clusters, schedule an offline <code>pg_checksums --enable</code>.</li>
<li><strong>Disk and connection headroom are alerted.</strong> You get a warning before the data, WAL or archive volumes fill, and before connection counts approach <code>max_connections</code>.</li>
</ol>
<p class="code-label"><strong>Text</strong></p>
<pre><code class="language-text"># pg_hba.conf: TLS required, SCRAM only, no trust/md5 for network clients
# TYPE     DATABASE  USER  ADDRESS        METHOD
local      all       postgres              peer
hostssl    all       all   10.0.0.0/16    scram-sha-256
hostnossl  all       all   0.0.0.0/0      reject</code></pre>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">-- WAL archiving: failures should be zero and last_archived_time recent
SELECT archived_count, failed_count, last_archived_time, last_failed_time
FROM pg_stat_archiver;

-- Replication lag per standby (run on the primary)
SELECT application_name, state, replay_lag,
       pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS replay_lag_bytes
FROM pg_stat_replication;

-- Autovacuum: tables with the most dead tuples
SELECT relname, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;

-- Transaction ID age per database
SELECT datname, age(datfrozenxid) AS xid_age
FROM pg_database
ORDER BY xid_age DESC;

-- Auth and TLS settings
SHOW password_encryption;
SHOW ssl;</code></pre>
<h2 id="key-takeaways">Key takeaways</h2>
<ul>
<li><strong>Patch minors promptly.</strong> Run the latest minor of your major version. Minors carry only bug and security fixes, so they are low-risk, but still roll them out through staging first.</li>
<li><strong>Retire PostgreSQL 14 now.</strong> Set an upgrade date before its final fixes arrive in November 2026, and prefer PostgreSQL 18 as the target.</li>
<li><strong>Use <code>uuidv7()</code> for UUID primary keys.</strong> Timestamp-ordered values keep inserts localized in the index.</li>
<li><strong>Recheck composite index column order.</strong> Skip scan in PostgreSQL 18 may make some indexes redundant, so confirm with query plans.</li>
<li><strong>Enforce integrity in the database.</strong> Use temporal constraints instead of application-side overlap checks, and keep data checksums enabled.</li>
<li><strong>Rehearse <code>pg_upgrade</code>.</strong> Run <code>pg_upgrade --check</code> first and take a backup before using <code>--swap</code>.</li>
<li><strong>Prefer OAuth over shared static passwords, and benchmark <code>io_method</code> yourself.</strong> Inspect <code>pg_aios</code> on your own storage before changing the default.</li>
<li><strong>Keep PostgreSQL 19 beta out of production.</strong> Use it in test environments to try your own workloads.</li>
</ul>
<h2 id="faq">FAQ</h2>
<h3>Should I upgrade to PostgreSQL 18 or 17?</h3>
<p>Choose 18 unless something concrete blocks it, such as an extension, driver or managed service that does not support it yet. PostgreSQL 18 was first released on 2025-09-25 and is scheduled for final fixes on 2030-11-14, so it gives you the longest support window. Upgrading to 17 means you will have to run another major upgrade sooner.</p>
<p>PostgreSQL 18 also makes the upgrade itself easier:</p>
<ul>
<li>Planner statistics carry over, so the new cluster reaches normal performance sooner.</li>
<li><code>pg_upgrade</code> runs its checks in parallel with <code>--jobs</code>.</li>
<li>The new <code>--swap</code> flag swaps directories instead of copying, cloning or linking files, which helps most when a database has many objects.</li>
</ul>
<p>PostgreSQL 17 is a reasonable stop if your dependencies force it. It reworked vacuum memory management, improved high-concurrency workloads and bulk loading, and improved logical replication for high availability and major upgrades. Do not pick 16 or 15 as a target for a new upgrade. They have less support time left and you would repeat the work soon.</p>
<p>Either way, restore a production backup into a staging cluster, run <code>pg_upgrade</code> there, and replay your real workload before you commit. If you are still on 14, its last fixes are due on 2026-11-12, so schedule this now.</p>
<p>&nbsp;</p>
<h3>Can I enable data checksums on an existing cluster?</h3>
<p>Yes, but not online. <code>initdb</code> in PostgreSQL 18 enables checksums by default, which does nothing for clusters that already exist. First check your current state:</p>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">SHOW data_checksums;<br /></code></pre>
<p>If it returns <code>off</code>, the usual route is the <code>pg_checksums</code> tool. It requires a cleanly shut-down cluster and rewrites every data file to add checksums, so downtime grows with database size. Run it on a restored copy first to measure that time. If you cannot afford the downtime, build a new cluster with checksums enabled and move the data over with logical replication.</p>
<p>The setting matters for major upgrades because <code>pg_upgrade</code> requires the old and new clusters to match. If your old cluster has no checksums and you do not want to change that during the upgrade, initialize the new 18 cluster without them:</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p class="code-label"><strong>Bash</strong></p>
<pre><code class="language-bash">initdb --no-data-checksums -D /var/lib/postgresql/18/main
pg_upgrade \
  --old-bindir=/usr/lib/postgresql/16/bin \
  --new-bindir=/usr/lib/postgresql/18/bin \
  --old-datadir=/var/lib/postgresql/16/main \
  --new-datadir=/var/lib/postgresql/18/main \
  --jobs=4 --check</code></pre>
<p>Dropping <code>--check</code> runs the real upgrade. I recommend treating the upgrade and the checksum change as two separate maintenance steps. If something goes wrong, you then know which change caused it. The trade-off is that checksums add a small CPU cost, but they let PostgreSQL detect storage-level corruption instead of silently reading bad pages.</p>
<h3>Should I use uuidv7() on existing tables?</h3>
<p>Use it as the default for new rows and leave existing keys alone. <code>uuidv7()</code> is new in PostgreSQL 18 and generates timestamp-ordered UUIDs. New values are inserted near the end of a primary key index, which suits indexes and caching better than random UUIDs. Changing the default does not rewrite or invalidate existing rows, because both kinds of value are ordinary <code>uuid</code> values:</p>
<p class="code-label"><strong>SQL</strong></p>
<pre><code class="language-sql">ALTER TABLE orders
  ALTER COLUMN id SET DEFAULT uuidv7();</code></pre>
<p>Do not rewrite existing primary keys just to get ordering. That would mean updating every foreign key and external reference, and the benefit applies only to new inserts. Two caveats apply:</p>
<ul>
<li>A UUIDv7 embeds its creation time, so do not use it where exposing creation time to clients is a problem.</li>
<li>The function does not exist before PostgreSQL 18. If any replica or application environment still runs an older major, applying the default there will fail.</li>
</ul>
<p>Apply the change after every node runs 18. <code>uuidv4()</code> is also new in 18 as an alias for <code>gen_random_uuid()</code>, if you want a name that states the version.</p>
<h3>Do multicolumn indexes need to be redesigned for PostgreSQL 18?</h3>
<p>Not immediately. PostgreSQL 18 adds skip scan on multicolumn B-tree indexes, so a query that omits an equality condition on one or more leading columns can still use the index. That can make some single-purpose indexes redundant, and it relaxes how strictly you must order columns in new composite indexes.</p>
<p>Do not drop indexes on this basis alone. Compare the plans and timings of your real queries after the upgrade, and only then retire an index you can show is unused or covered. Dropping an index in a hurry is harder to undo than keeping it.</p>
<p>&nbsp;</p>
<h3>Is it safe to apply PostgreSQL minor releases without a long test cycle?</h3>
<p>Minor releases carry only bug and security fixes, which makes them low-risk, but not risk-free. Skipping them has a real cost: 18.1 fixed CVE-2025-12817, where <code>CREATE STATISTICS</code> skipped a schema <code>CREATE</code> privilege check, and 18.4 fixed CVE-2026-6575 in <code>pg_restore_attribute_stats</code> along with over 60 bugs.</p>
<p>Roll the update through staging first and confirm you have a backup you have actually restored. Then move production to the latest minor of your major: 18.6, 17.11, 16.15, 15.19 or 14.24. Since version 10, minor releases change the second number (for example 10.0 to 10.1), so 18.5 to 18.6 is a minor update.</p>
<h3>Should I test PostgreSQL 19 now?</h3>
<p>Yes, run your own workload against it in a non-production environment. Beta 4 was announced on 2026-09-24, and the project encourages this kind of testing, so problems can be reported before the final release. Do not run a beta in production. For production, use PostgreSQL 18.</p>
<h2 id="sources">Sources and further reading</h2>
<ul>
<li><a href="https://www.postgresql.org/" target="_blank" rel="noopener">PostgreSQL: The world&#8217;s most advanced open source database</a> (PostgreSQL Global Development Group)</li>
<li><a href="https://www.postgresql.org/support/versioning/" target="_blank" rel="noopener">PostgreSQL: Versioning Policy</a> (PostgreSQL Global Development Group)</li>
<li><a href="https://www.postgresql.org/about/news/postgresql-18-released-3142/" target="_blank" rel="noopener">PostgreSQL: PostgreSQL 18 Released!</a> (PostgreSQL Global Development Group)</li>
<li><a href="https://www.postgresql.org/docs/release/18.0/" target="_blank" rel="noopener">PostgreSQL 18.0 Release Notes</a> (PostgreSQL Global Development Group)</li>
</ul>
<p>&nbsp;</p>


<p class="wp-block-paragraph">Please share this article with your friends and <a rel="noreferrer noopener" href="https://www.thecodebuzz.com/subscription/" target="_blank"><em><strong>Subscribe</strong> </em></a>to the blog to get a notification on freshly published best practices of software development.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">        </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://thecodebuzz.com/postgresql-best-practices-production/">PostgreSQL – Best Practices for Production</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://thecodebuzz.com/postgresql-best-practices-production/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>What is Data Modelling &#8211; Fundamentals and Guidelines</title>
		<link>https://thecodebuzz.com/what-is-data-modelling-fundamentals-sql-nosql-guidelines/</link>
					<comments>https://thecodebuzz.com/what-is-data-modelling-fundamentals-sql-nosql-guidelines/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 25 Nov 2023 22:59:31 +0000</pubDate>
				<category><![CDATA[Database Best Practices]]></category>
		<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Data Modelling - Fundamentals and Guidelines]]></category>
		<guid isPermaLink="false">https://www.thecodebuzz.com/?p=28855</guid>

					<description><![CDATA[<p>What is Data Modelling &#8211; Fundamentals and Guidelines Today in this article, we will go over Data Modelling &#8211; Fundamentals and Building Blocks and their usage guidelines. What is Data Modelling Data modeling is an important technique for effective database design, understanding the data requirements of a particular use case, and offering a structured method [&#8230;]</p>
<p>The post <a href="https://thecodebuzz.com/what-is-data-modelling-fundamentals-sql-nosql-guidelines/">What is Data Modelling – Fundamentals and Guidelines</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1 class="wp-block-heading">What is Data Modelling &#8211; Fundamentals and Guidelines</h1>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="666" height="324" src="https://www.thecodebuzz.com/wp-content/uploads/2023/11/what-is-data-modelling-fundamentals-sql-nosql-guidelines.jpg" alt="What is Data Modelling - Fundamentals and Guidelines" class="wp-image-29209" srcset="https://thecodebuzz.com/wp-content/uploads/2023/11/what-is-data-modelling-fundamentals-sql-nosql-guidelines.jpg 666w, https://thecodebuzz.com/wp-content/uploads/2023/11/what-is-data-modelling-fundamentals-sql-nosql-guidelines-300x146.jpg 300w" sizes="auto, (max-width: 666px) 100vw, 666px" /></figure>



<p class="wp-block-paragraph">Today in this article, we will go over Data Modelling &#8211; Fundamentals and Building Blocks and their usage guidelines.</p>



<p class="wp-block-paragraph"></p>



<div class="wp-block-aioseo-table-of-contents"><ul><li><a href="#aioseo-what-is-data-modelling">What is Data Modelling</a></li><li><a href="#aioseo-sql-and-no-sql-data-modelling-is-still-valid-techniques">SQL and NO SQL &#8211; Data modeling is still a valid technique</a></li><li><a href="#aioseo-type-of-data-dodeling-concepts">Type of Data Modeling Concepts</a><ul><li><a href="#aioseo-conceptual-data-modeling">Conceptual Data Modeling</a></li><li><a href="#aioseo-logical-data-modeling">Logical Data Modeling</a></li><li><a href="#aioseo-physical-data-modeling">Physical Data Modeling:</a></li></ul></li><li><a href="#aioseo-building-blocks-of-data-modeling">Building blocks of Data modeling</a><ul><li><a href="#aioseo-entities-in-data-modelling">Entities in Data Modelling</a></li><li><a href="#aioseo-attributes-in-data-modelling">Attributes in Data Modelling</a></li><li><a href="#aioseo-relationships-in-data-modeling">Relationships in Data modeling</a></li><li><a href="#aioseo-keys-in-data-modeling">Keys in Data modeling</a></li><li><a href="#aioseo-benefits-of-data-modeling">Benefits of Data Modeling</a></li><li><a href="#aioseo-data-modeling-tools">Data modeling Tools</a></li></ul></li></ul></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-what-is-data-modelling">What is Data Modelling </h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"><a href="https://www.thecodebuzz.com/mongodb-schema-design-guidelines-best-practices/" target="_blank" rel="noopener" title="MongoDB Schema Design – Guidelines and Best practices">Data modeling</a> is an important technique for effective database design, understanding the data requirements of a particular use case, and offering a structured method for understanding, representing, and implementing data structures for a given requirement.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Data Modelling normally occurs at the beginning of the development process to understand and document business requirements before database implementation. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">This means it heavily helps you identify and documentation of business logic, rules, and relationships to ensure that the data model aligns with business objectives.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Data modeling focuses on organizing data at a <strong>Conceptual </strong>or <strong>Abstract or </strong> <strong>Physical </strong>level. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">It aims to understand the information requirements of a business or system and define the relationships between different data entities. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Data modeling utilizes techniques like Entity-Relationship Diagrams (<strong>ERD</strong>) to represent entities, attributes, and relationships between entities, but this evolution and brainstorming does help you define your requirements in a true sense. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Along with facilitating discussions, it ensures changes to the design are visited during the early stages of development. In the world of development, which fully relies on design in the first place this does help in a greater way.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Data Modelling encourages communication between various stakeholders including the product owner, scrum, developers, or architects by providing a visual representation of data concepts that is accessible to both technical and non-technical audiences.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">It very good technique for extending logical and physical design, normalization, relationship mapping, and performance optimization at the very beginning of use case or requirements explorations.</p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-sql-and-no-sql-data-modelling-is-still-valid-techniques">SQL and NO SQL &#8211; Data modeling is still a valid technique</h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Data Modelling operates at a more elevated level of <strong>abstraction</strong>, stressing entities, attributes, and relationships without getting into specific database implementation details, and hence this technique&#8217;s value holds for SQL or No SQL database design.</p>



<p class="wp-block-paragraph"> </p>



<p class="wp-block-paragraph">The outcomes of Data modeling ensure conceptualization, understanding, and representation of data requirements to various stake stakeholders and hence build confidence in the product which is going to evolve later stage as deliverables.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="278" src="https://www.thecodebuzz.com/wp-content/uploads/2023/11/Data-Modelling-vs-schema-modelling-1024x278.jpg" alt="" class="wp-image-28859" srcset="https://thecodebuzz.com/wp-content/uploads/2023/11/Data-Modelling-vs-schema-modelling-1024x278.jpg 1024w, https://thecodebuzz.com/wp-content/uploads/2023/11/Data-Modelling-vs-schema-modelling-300x81.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/11/Data-Modelling-vs-schema-modelling-768x208.jpg 768w, https://thecodebuzz.com/wp-content/uploads/2023/11/Data-Modelling-vs-schema-modelling-1536x417.jpg 1536w, https://thecodebuzz.com/wp-content/uploads/2023/11/Data-Modelling-vs-schema-modelling-785x213.jpg 785w, https://thecodebuzz.com/wp-content/uploads/2023/11/Data-Modelling-vs-schema-modelling.jpg 1770w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-type-of-data-dodeling-concepts">Type of Data Modeling Concepts</h2>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-conceptual-data-modeling"><strong>Conceptual Data Modeling</strong></h3>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Focuses on the high-level representation of the domain entities, business concepts, and relationships within a system.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Helps in getting all the the fundamental entities, attributes, and relationships between.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Provide a clear and abstract view of the business requirements, serving as a foundation for further development.</li>
</ul>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-logical-data-modeling"><strong>Logical Data Modeling</strong></h3>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>This modeling helps translate the conceptual data model into a more detailed and structured format that can be implemented in a database.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Defines tables, columns, fields, data types, relationships, and constraints for the given database management system.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>It acts as a bridge between the conceptual model and the physical implementation, ensuring a comprehensive and consistent representation of data.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-physical-data-modeling"><strong>Physical Data Modeling:</strong></h3>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Focuses on the actual implementation of the database on a specific database management system SQL or  No SQL.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Includes details such as storage structures, indexing, partitioning, and other optimization techniques to enhance performance.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Involves decisions about how data is stored, accessed, and retrieved at the physical level, considering the specific features and requirements of the chosen DBMS.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-building-blocks-of-data-modeling"><strong>Building blocks of Data modeling </strong></h2>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-entities-in-data-modelling">Entities in Data Modelling </h3>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="684" height="540" src="https://www.thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals.jpg" alt="" class="wp-image-28860" style="aspect-ratio:1.2666666666666666;width:683px;height:auto" srcset="https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals.jpg 684w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-300x237.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-659x520.jpg 659w" sizes="auto, (max-width: 684px) 100vw, 684px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">The best way to judge an entity is as some type of &#8220;<strong><em>real-world subject</em></strong>.&#8221;</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">At the end entity represents &#8221; <strong><em>a collection of attributes or fields</em></strong>.&#8221;</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Entities represent distinct objects, concepts, or things within a system that are described and stored as data. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">These entities encapsulate relevant information through attributes, defining the properties or characteristics associated with them. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">For example, in a customer relationship system, a &#8220;Customer&#8221; entity might include attributes such as &#8220;CustomerID,&#8221; &#8220;Name,&#8221; and &#8220;Email.&#8221; </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Identifying and modeling entities is foundational for a clear understanding of the information requirements and relationships within a given domain or system.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-attributes-in-data-modelling">Attributes in Data Modelling </h3>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Attributes provide granularity to the data model, offering a way to distinguish and categorize information within entities.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="862" height="434" src="https://www.thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Entity-Data-Model-and-attribute-examples.jpg" alt="Data Modelling Fundamentals and Building Blocks" class="wp-image-28865" style="aspect-ratio:1.9861751152073732;width:840px;height:auto" srcset="https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Entity-Data-Model-and-attribute-examples.jpg 862w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Entity-Data-Model-and-attribute-examples-300x151.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Entity-Data-Model-and-attribute-examples-768x387.jpg 768w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Entity-Data-Model-and-attribute-examples-785x395.jpg 785w" sizes="auto, (max-width: 862px) 100vw, 862px" /></figure>



<p class="wp-block-paragraph">By defining these attributes, data modeling achieves a more comprehensive representation of the underlying data, enabling the organization and retrieval of specific details associated with each entity in a structured and meaningful manner.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Characteristics or properties of <a href="https://www.thecodebuzz.com/getting-started-efcore-entity-framework-core-orm-asp-net-core/" target="_blank" rel="noopener" title="Getting Started with Entity Framework – ORM in ASP.NET Core">entities </a>that describe the data associated with them. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Attributes provide details about the entities and are often represented as adjectives, like &#8220;<strong>Name</strong>&#8221; or &#8220;<strong>DateOfBirth</strong>.&#8221;</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-relationships-in-data-modeling">Relationships in Data modeling</h3>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="706" height="607" src="https://www.thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-attributes-and-relationship.jpg" alt="" class="wp-image-28864" srcset="https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-attributes-and-relationship.jpg 706w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-attributes-and-relationship-300x258.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-attributes-and-relationship-605x520.jpg 605w" sizes="auto, (max-width: 706px) 100vw, 706px" /></figure>



<p class="wp-block-paragraph">In data modeling, relationships establish <a href="https://www.thecodebuzz.com/database-connection-resiliency-entity-framework-asp-net-core/">connections between entities,</a> defining how they interact. T</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">These connections convey associations and dependencies, crucial for understanding the dynamics within a system. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">For instance, in a database for a library, a &#8220;Customer&#8221; entity may have a relationship with an &#8220;Order&#8221; entity, indicating the association between individuals requesting an order. </p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Relationships specify the cardinality and nature of connections, such as one-to-one or many-to-many, providing a structured framework for data representation. </li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>By modeling relationships, data modeling ensures a comprehensive understanding of how entities relate to one another, fostering accurate and efficient retrieval of information from the database.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-keys-in-data-modeling">Keys in Data modeling</h3>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="722" height="659" src="https://www.thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-relationship-and-keys-defined.jpg" alt="" class="wp-image-28868" srcset="https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-relationship-and-keys-defined.jpg 722w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-relationship-and-keys-defined-300x274.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/11/Mastering-Data-Modeling-Fundamentals-relationship-and-keys-defined-570x520.jpg 570w" sizes="auto, (max-width: 722px) 100vw, 722px" /></figure>



<ul class="wp-block-list">
<li>Keys play a pivotal role in data modeling by uniquely identifying and organizing data within a database.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li><strong>In RDBMS or SQL </strong>worlds example &#8211; the &#8220;primary key&#8221; serves as a distinct identifier for each record, ensuring data integrity.
<ul class="wp-block-list">
<li>Foreign keys establish relationships between tables, linking data across entities. </li>



<li>Index keys enhance query performance, enabling swift data retrieval.</li>



<li>Composite keys combine multiple attributes to create a unique identifier.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>In <strong>No SQL</strong> Unique Keys identify documents or entries within a collection, ensuring data integrity.
<ul class="wp-block-list">
<li>In document-oriented databases, like MongoDB, keys often include a unique identifier, such as the document&#8217;s &#8220;_id.&#8221;</li>



<li>In key-value stores, like Redis, keys serve as direct access points to values.</li>



<li>NoSQL databases may also use composite keys or secondary indexes for diverse query patterns.</li>



<li>Keys are crucial for optimizing data access, retrieval, and navigation in NoSQL databases, contributing to performance in managing various data structures and relationships.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-benefits-of-data-modeling">Benefits of Data Modeling</h3>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Below are the top-level benefits of data modeling.</p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Creating a structure for collaboration between your IT and business teams.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Revealing opportunities for improving business processes by defining data needs and uses.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Saving time and money on IT and process investments through appropriate planning.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Reducing errors (and error-prone redundant data entry) while improving data integrity.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Increasing the speed and performance of data retrieval and analytics by planning for capacity and growth.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Setting and tracking target key performance indicators tailored to your business objectives.</li>
</ul>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" id="aioseo-data-modeling-tools"><strong>Data modeling Tools</strong></h3>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Here are a few useful tools for Data modeling examples:</p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li><strong>erwin Data Modeler</strong> is a data modeling tool based on the Integration DEFinition for information modeling (IDEF1X) data modeling language that now supports other notation methodologies, including a dimensional approach.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li><strong>Enterprise Architect</strong> is a visual modeling and design tool that supports the modeling of enterprise information systems and architectures. It’s based on object-oriented languages and standards.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li><strong>ER/Studio</strong> is database design software that’s compatible with several of today’s most popular database management systems. It supports both relational and dimensional data modeling.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li><strong>Open Source tools</strong> include open-source solutions such as Open ModelSphere.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">That&#8217;s all! Happy coding!</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Does this help you fix your issue? </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Do you have any better solutions or suggestions? Please sound off your comments below.</p>



<hr>



<p class="wp-block-paragraph"></p>



<p class="has-background" style="background-color:#b6d9ac;font-size:18px"><br>Please <strong><em>bookmark </em></strong>this page and <em><strong>share </strong></em>it with your friends.                                                    Please <a href="https://www.thecodebuzz.com/subscription/" target="_blank" rel="noreferrer noopener"><em><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-luminous-vivid-orange-color"><strong>Subscribe</strong> </mark></em></a>to the blog to receive notifications on freshly published (2026) best practices and guidelines for software design and development.</p>




<br>



<hr>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://thecodebuzz.com/what-is-data-modelling-fundamentals-sql-nosql-guidelines/">What is Data Modelling – Fundamentals and Guidelines</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://thecodebuzz.com/what-is-data-modelling-fundamentals-sql-nosql-guidelines/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Faster Insert and Update in Entity Framework Core &#8211; Guidelines</title>
		<link>https://thecodebuzz.com/faster-insert-update-entity-framework-core-performance-guidelines/</link>
					<comments>https://thecodebuzz.com/faster-insert-update-entity-framework-core-performance-guidelines/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 25 Mar 2023 03:16:49 +0000</pubDate>
				<category><![CDATA[Database Best Practices]]></category>
		<category><![CDATA[EFCore]]></category>
		<category><![CDATA[Faster Insert and Update in Entity Framework Core]]></category>
		<guid isPermaLink="false">https://www.thecodebuzz.com/?p=26312</guid>

					<description><![CDATA[<p>Faster Performance for Insert and Update in Entity Framework Core Today in this guidelines section, we will cover a few useful guidelines to get Faster Insert and Update in Entity Framework Core. Although the performance of SQL or entity framework query is a vast subject and has many aspects which are important. However, this guideline [&#8230;]</p>
<p>The post <a href="https://thecodebuzz.com/faster-insert-update-entity-framework-core-performance-guidelines/">Faster Insert and Update in Entity Framework Core – Guidelines</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1 class="wp-block-heading">Faster Performance for Insert and Update in Entity Framework  Core</h1>



<figure class="wp-block-image size-large"><a href="https://www.thecodebuzz.com/faster-insert-update-entity-framework-core-performance-guidelines/" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="1024" height="513" src="https://www.thecodebuzz.com/wp-content/uploads/2023/03/Faster-Read-Insert-and-Update-in-Entity-Framework-Core-1-1024x513.jpg" alt="Faster Insert and Update in Entity Framework Core - Guidelines" class="wp-image-26344" srcset="https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Read-Insert-and-Update-in-Entity-Framework-Core-1-1024x513.jpg 1024w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Read-Insert-and-Update-in-Entity-Framework-Core-1-300x150.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Read-Insert-and-Update-in-Entity-Framework-Core-1-768x385.jpg 768w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Read-Insert-and-Update-in-Entity-Framework-Core-1-785x393.jpg 785w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">#image_title</figcaption></figure>



<p class="wp-block-paragraph">Today in this guidelines section, we will cover a few useful guidelines to get Faster Insert and Update in Entity Framework Core.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Although the performance of SQL or entity framework query is a vast subject and has many aspects which are important. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">However, this guideline details some common guidelines for making your read query faster and helping you achieve efficient updating.</p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Indexing the Fields in SQL</h2>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>A powerful method for facilitating effective database searches is indexing. </li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Here, you searched through the sorted index first in order to increase performance rather than running a full database scan (scanning through everything).</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>It&#8217;s the most effective way to manage the database scan.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Allows you to effectively manage the scanning of each document. Please be aware that every single document in a collection will undergo a thorough scan if there are no indexes.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>It gives a query the ability to focus results set using the index.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Indexing improved the efficiency of queries.</li>
</ul>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Indexes as AntiPattern in SQL query</h2>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Don&#8217;t create Indexes that are not used or used rarely.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Build indexes on only fields that are used often in the query.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Use Composite indexes for filtering multiple columns.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Avoid duplicate indexes.</li>
</ul>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Schema Modelling for Database</h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Your DB Schema modeling normalization plays important role in the performance of EFCore queries.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">You need to perform Normalization and denormalization of domain entities and create them appropriately even before you could load the data the first time.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">The benefits of schema modeling are as below,</p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Optimize the query performance.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Help you focus on reading and writing only selected domain entities.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Eliminate heavy use of joins or evaluation of queries.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Break your class into small class entities. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">The below example gives a small glimpse of what is expected by schema modeling.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Below <strong><em>Employee </em></strong>class is broken into small entities like <strong><em>Employee</em></strong>, <strong><em>Contact</em></strong>, <strong><em>SocialSecurity</em></strong>, etc.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><a href="https://www.thecodebuzz.com/faster-insert-update-entity-framework-core-performance-guidelines/" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="1024" height="819" src="https://www.thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-1024x819.jpg" alt="" class="wp-image-26329" srcset="https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-1024x819.jpg 1024w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-300x240.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-768x614.jpg 768w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-650x520.jpg 650w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">#image_title</figcaption></figure>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Read Optimization &#8211; Don&#8217;t Load the entire Entity in the Application Memory</h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">An <strong>Entity </strong>consists of multiple properties which are internally mapped to multiple columns in a respective Database table.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Below Example loads entire <strong>Employee </strong>entities.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Let&#8217;s say an example: If <strong><em>Employee </em></strong>has 100 columns then EF will load all 100 columns even if they are not used.</p>



<p class="wp-block-paragraph"></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
 foreach (var employee in _context.Employee)
            {
                /// Do something here 
                Console.WriteLine(&quot;EmployeeID : &quot; + employee.EmployeeId);
            }
            _context.SaveChanges();

</pre></div>


<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">It&#8217;s not recommended to load the DB Context entity entirely in memory due to the below issues,</p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>It could cause huge memory problems if you are loading the entire Entity set (if not aware of the size of the set). &nbsp;This brings all the  Employee row data to the client side causing performance issues.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Loading unnecessary data could add additional load for processing the queries.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">We can optimize the above code by using the Select below,</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="548" src="https://www.thecodebuzz.com/wp-content/uploads/2023/03/Fastest-Way-of-Inserting-in-Entity-Framework-1024x548.jpg" alt="" class="wp-image-26333" srcset="https://thecodebuzz.com/wp-content/uploads/2023/03/Fastest-Way-of-Inserting-in-Entity-Framework-1024x548.jpg 1024w, https://thecodebuzz.com/wp-content/uploads/2023/03/Fastest-Way-of-Inserting-in-Entity-Framework-300x161.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/03/Fastest-Way-of-Inserting-in-Entity-Framework-768x411.jpg 768w, https://thecodebuzz.com/wp-content/uploads/2023/03/Fastest-Way-of-Inserting-in-Entity-Framework-785x420.jpg 785w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Content-Based Optimization &#8211; Limit your query resultset</h2>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Another optimization technique is to limit the resultset by means of some matching filter.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Use paging or Filter matching criteria can be derived using business requirements, if possible. </li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Content-based loading will let you Load only data that is much sufficient to serve the purpose. Exa UI-based application.</li>
</ul>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="142" src="https://www.thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-limit-resultset-1024x142.jpg" alt="" class="wp-image-26334" srcset="https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-limit-resultset-1024x142.jpg 1024w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-limit-resultset-300x42.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-limit-resultset-768x107.jpg 768w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-limit-resultset-1536x214.jpg 1536w, https://thecodebuzz.com/wp-content/uploads/2023/03/Faster-Insert-and-Update-in-Entity-Framework-Core-limit-resultset-785x109.jpg 785w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">#image_title</figcaption></figure>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Update Optimization: Use of BulkUpdate</h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">EFCore doesn&#8217;t support bulk updates as of now. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">But below is the example that developer tends to write.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Here we are going to add preceding zeros to all employee&#8217;s ID fields using EFCore.</p>



<p class="wp-block-paragraph"></p>



<pre class="wp-block-code"><code>     foreach(var employee in _context.Employee)
            {
                employee.EmployeeId = employee.EmployeeId.PadRight(4, '0');
                Console.WriteLine("EmployeeID : " + employee.EmployeeId);
                _context.SaveChanges();
            }
            </code></pre>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">In the above code,</p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>The first database roundtrip is performed by code <strong>_context.Employee </strong>brings all employee data on client-side code execution.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>The second database round trip is performed to save the changes. However 2nd roundtrip can be further optimized into a few more round trips depending on the database provider type and the amount of data.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>_context.SaveChanges() is being called for every record which could affect the performance.  </li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">The above code can be further optimized by calling SaveChanges at the end of <strong>foreach </strong>loop.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="515" src="https://www.thecodebuzz.com/wp-content/uploads/2023/03/SaveChanges-in-Entity-Framework-Core-1024x515.jpg" alt="" class="wp-image-26338" srcset="https://thecodebuzz.com/wp-content/uploads/2023/03/SaveChanges-in-Entity-Framework-Core-1024x515.jpg 1024w, https://thecodebuzz.com/wp-content/uploads/2023/03/SaveChanges-in-Entity-Framework-Core-300x151.jpg 300w, https://thecodebuzz.com/wp-content/uploads/2023/03/SaveChanges-in-Entity-Framework-Core-768x386.jpg 768w, https://thecodebuzz.com/wp-content/uploads/2023/03/SaveChanges-in-Entity-Framework-Core-1536x773.jpg 1536w, https://thecodebuzz.com/wp-content/uploads/2023/03/SaveChanges-in-Entity-Framework-Core-785x395.jpg 785w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">#image_title</figcaption></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">The second option can be further optimized as below by calling a<strong><em> raw stored procedure </em></strong></p>



<p class="wp-block-paragraph"></p>



<pre class="wp-block-preformatted">_context.Employee.FromSqlRaw("UPDATE [EmployeeDB] SET [EmployeeId] =  RIGHT( '0000' + EmployeeId, 4)");</pre>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Hope you find these guidelines useful. We will see some more guidelines in the next updates. Hence kindly stay tuned!</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph" style="font-size:18px">Do you have any <strong>comments or ideas or any better </strong>suggestions to share?</p>



<p class="has-small-font-size wp-block-paragraph"></p>



<p class="wp-block-paragraph" style="font-size:18px">Please sound off your comments below.</p>



<p class="has-medium-font-size wp-block-paragraph"></p>



<p class="has-medium-font-size wp-block-paragraph"><strong>Happy Coding </strong>!!</p>



<p class="wp-block-paragraph"></p>



<hr>



<p class="wp-block-paragraph"></p>



<p class="has-background" style="background-color:#b6d9ac;font-size:18px"><br>Please <strong><em>bookmark </em></strong>this page and <em><strong>share </strong></em>it with your friends.                                                    Please <a href="https://www.thecodebuzz.com/subscription/" target="_blank" rel="noreferrer noopener"><em><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-luminous-vivid-orange-color"><strong>Subscribe</strong> </mark></em></a>to the blog to receive notifications on freshly published (2026) best practices and guidelines for software design and development.</p>




<br>



<hr>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://thecodebuzz.com/faster-insert-update-entity-framework-core-performance-guidelines/">Faster Insert and Update in Entity Framework Core – Guidelines</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://thecodebuzz.com/faster-insert-update-entity-framework-core-performance-guidelines/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>MongoDB Security guidelines and best practices</title>
		<link>https://thecodebuzz.com/mongodb-security-guidelines-and-best-practices/</link>
					<comments>https://thecodebuzz.com/mongodb-security-guidelines-and-best-practices/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 22 Dec 2022 03:29:00 +0000</pubDate>
				<category><![CDATA[Database Best Practices]]></category>
		<category><![CDATA[mongodb access control]]></category>
		<category><![CDATA[mongodb antivirus exclusions]]></category>
		<category><![CDATA[mongodb atlas security best practices]]></category>
		<category><![CDATA[mongodb security authorization: enabled]]></category>
		<category><![CDATA[mongodb security checklist]]></category>
		<category><![CDATA[mongodb security features]]></category>
		<category><![CDATA[mongodb security vulnerabilities]]></category>
		<category><![CDATA[mongodb security whitepaper]]></category>
		<guid isPermaLink="false">https://www.thecodebuzz.com/?p=25115</guid>

					<description><![CDATA[<p>MongoDB Security guidelines and best practices Today in this article, we will discuss MongoDB Security guidelines and Best practices. Security measures can be applied while data is at rest i.e. storage level security and while data is at the move. Obviously, Security is not an afterthought process. You must build your system considering the security [&#8230;]</p>
<p>The post <a href="https://thecodebuzz.com/mongodb-security-guidelines-and-best-practices/">MongoDB Security guidelines and best practices</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1 class="wp-block-heading" id="aioseo-mongodb-security-guidelines-and-best-practices">MongoDB Security guidelines and best practices</h1>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.thecodebuzz.com/wp-content/uploads/2022/12/MongoDB-security-Guidelines-1-1024x304.jpg" alt=" mongodb security authorization: enabled, mongodb security features, mongodb security whitepaper," class="wp-image-25230"/></figure>



<p class="wp-block-paragraph">Today in this article, we will discuss  MongoDB Security guidelines and Best practices.</p>



<p class="wp-block-paragraph">Security measures can be applied while data is at rest i.e. storage level security and while data is at the move.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Obviously,  Security is not an afterthought process. You must build your system considering the security and risk exposure. You also need to design a risk mitigation process just in case there is a need.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">As with all software, MongoDB administrators must consider security and risk exposure for a MongoDB<br>deployment. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">We will cover the below aspects in today&#8217;s article,</p>



<div class="wp-block-aioseo-table-of-contents"><ul><li><a href="#aioseo-user-rights-management-authentication-and-authorization">User Rights Management &#8211; Enable Authentication and Authorization</a></li><li><a href="#aioseo-protect-sensitive-data-at-rest-encryption-and-decryption">Protect Sensitive Data at Rest &#8211; Encryption and Decryption</a></li><li><a href="#aioseo-protect-data-in-transit">Protect Data in Transit</a></li><li><a href="#aioseo-data-monitoring-or-database-activity-monitoring-dam">Data Monitoring or Database activity monitoring (DAM)</a></li><li><a href="#aioseo-implement-secure-key-and-certificate-management">Implement secure key and certificate management</a></li><li><a href="#aioseo-secure-network-access">Restrict Network Access</a></li><li><a href="#aioseo-upgrade-to-latest-mongodb-version">Upgrade to the Latest MongoDB version</a></li><li><a href="#aioseo-upgrade-to-the-latest-mongodb-version">Implement &#8211; Data backup policy</a></li><li><a href="#aioseo-implement-disaster-recovery-plan">Implement &#8211; Disaster Recovery plan</a></li><li><a href="#aioseo-regularly-perform-security-audits">Perform Security Audits</a></li><li><a href="#aioseo-summary">Summary</a></li></ul></div>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-user-rights-management-authentication-and-authorization">User Rights Management &#8211; Enable Authentication and Authorization </h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Control access to sensitive data authentication and authorization at the database level.  </p>



<p class="wp-block-paragraph">Define permissions for a user or application and define what data the application or user can access.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Provision users defined roles defining different entities accessing and managing the data. </p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Restrict write access at the application level or admin level. </li>
</ul>



<ul class="wp-block-list">
<li>Restrict access as <strong>ReadOnly </strong>for non-admin members.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Use any custom authorization or leverage LDAP level integration to verify (the user using a centralized Server.)</p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-protect-sensitive-data-at-rest-encryption-and-decryption">Protect Sensitive Data at Rest &#8211; Encryption and Decryption</h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Protecting data at rest in persistent storage is important. Field-level encryption is recommended for protecting any PII, or PHI, or PFI information. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Leverage MongoDB-supported encryption and decryption mechanism.</p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Field-level encryption is supported for MongoDB 4.2 and onwards support.</li>
</ul>



<ul class="wp-block-list">
<li>With client-side field-level encryption, developers can encrypt fields on the client side.</li>
</ul>



<ul class="wp-block-list">
<li>Encrypt fields are supported without any server-side configuration or directives.</li>
</ul>



<ul class="wp-block-list">
<li>Client-side field-level encryption in the .NET/C# driver is currently only supported on x64-compatible CPUs.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">For more details visit,</p>



<ul class="has-medium-font-size wp-block-list">
<li><a href="https://www.thecodebuzz.com/mongodb-field-encryption-decryption-pii-phi-csharp-net-core-driver/" target="_blank" rel="noopener" title="MongoDB Encryption- Field Level Encryption and Decryption C#">MongoDB Encryption- Field Level Encryption and Decryption C#</a></li>
</ul>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-protect-data-in-transit">Protect Data in Transit</h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">The below guidelines are more generic but ideal for most scenarios to implement secured data transfer.</p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li><span style="font-size: revert; color: initial;">Implement </span>encryption to protect the integrity of data when data transit for two-way communications.</li>
</ul>



<ul class="wp-block-list">
<li>Enforce user-defined encryption requirements based on the enterprise&#8217;s organizational and compliance requirements by following standards, guidelines, and best practices.</li>
</ul>



<ul class="wp-block-list">
<li>Add Encryption of data in transit using <strong>TLS v1.2</strong>, and above cipher suites for all publicly accessible sites or APIs or Applications.</li>
</ul>



<ul class="wp-block-list">
<li><strong>TLS </strong>(Transport Layer Security) and <strong>SSL </strong>(Secure&nbsp;Sockets Layer) are the primary means to over the wire or&nbsp;in-transit data.</li>
</ul>



<ul class="wp-block-list">
<li>Enforce <b>HTTPS-secured</b> transport protocol for accessing websites, API and database connection, etc.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-data-monitoring-or-database-activity-monitoring-dam">Data Monitoring or Database activity monitoring (DAM)  </h2>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Monitor Data Base Access using Health check monitoring tools if any. </li>
</ul>



<ul class="wp-block-list">
<li><strong>Whitelist </strong>and <strong>Backlist </strong>of IP and environment to control enterprise access.</li>
</ul>



<ul class="wp-block-list">
<li>Detect any anomalies or attempts to move data outside of defined boundaries.</li>
</ul>



<ul class="wp-block-list">
<li>Monitor Databases against malicious activity by firewalls and intrusion.</li>
</ul>



<ul class="wp-block-list">
<li>Audit and monitor all database activity separately, such as privileged user activities and SELECT transactions, without a loss of performance.</li>
</ul>



<ul class="wp-block-list">
<li>Produce notifications or alerts when a policy violation is identified.</li>
</ul>



<ul class="wp-block-list">
<li>Prevent tampering or manipulation of database logs.</li>
</ul>



<ul class="wp-block-list">
<li>Use of Database activity monitoring (DAM) tool (if suitable ) can be used to report any identify and report fraudulent, illegal, or other undesirable behavior.</li>
</ul>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-implement-secure-key-and-certificate-management">Implement secure key and certificate management</h2>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Implement secure key and certificate management process.</li>
</ul>



<ul class="wp-block-list">
<li><span style="font-size: revert; color: initial;">Store keys and certificates securely</span>.</li>
</ul>



<ul class="wp-block-list">
<li>Apply<span style="font-size: revert; color: initial;"> strict access control</span> on key access.</li>
</ul>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-secure-network-access">Restrict Network Access</h2>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Secure network access to your MongoDB server. Configure firewall and RBAC to allow connection only from Authorized IPs or networks.</li>



<li>Follow the Principle of Least Privilege.</li>



<li>Restrict administrative access to a limited number of trusted personnel.</li>
</ul>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-upgrade-to-latest-mongodb-version">Upgrade to the Latest MongoDB version</h2>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Plan and be ready to regularly update MongoDB to the latest stable version. </li>



<li>New releases often include security patches and bug fixes, so staying up to date helps protect against known vulnerabilities.</li>
</ul>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-upgrade-to-the-latest-mongodb-version">Implement &#8211; Data backup policy</h2>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Implement a regular backup strategy to ensure a copy of your data is available in case of data loss, data corruption, or any security incidents happens.</li>
</ul>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>Follow backup best practices, such as storing backups in secure locations and testing the restoration process.</li>
</ul>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-implement-disaster-recovery-plan">Implement &#8211; Disaster Recovery plan </h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Implement a robust disaster recovery strategy. It is important along with regular backup of MongoDB data to a secure place. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Your downtime and recovery time should address your enterprise application requirements which may be dependent on multiple factors.</p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-regularly-perform-security-audits">Perform Security Audits</h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Conduct security audits and vulnerability assessments to identify and address any security weaknesses in your MongoDB deployment. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">This can include performing penetration testing, code reviews, and infrastructure assessments.</p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="aioseo-summary">Summary</h2>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Security is not an afterthought process in fact it is an ongoing process, and it&#8217;s important to stay alert and assertive in managing and improving the security of your MongoDB Database. </p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph" style="font-size:18px">Do you have any <strong>comments or ideas or any better </strong>suggestions to share?</p>



<p class="has-small-font-size wp-block-paragraph"></p>



<p class="wp-block-paragraph" style="font-size:18px">Please sound off your comments below.</p>



<p class="has-medium-font-size wp-block-paragraph"></p>



<p class="has-medium-font-size wp-block-paragraph"><strong>Happy Coding </strong>!!</p>



<p class="wp-block-paragraph"></p>



<hr>



<p class="wp-block-paragraph"></p>



<p class="has-background" style="background-color:#b6d9ac;font-size:18px"><br>Please <strong><em>bookmark </em></strong>this page and <em><strong>share </strong></em>it with your friends.                                                    Please <a href="https://www.thecodebuzz.com/subscription/" target="_blank" rel="noreferrer noopener"><em><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-luminous-vivid-orange-color"><strong>Subscribe</strong> </mark></em></a>to the blog to receive notifications on freshly published (2026) best practices and guidelines for software design and development.</p>




<br>



<hr>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://thecodebuzz.com/mongodb-security-guidelines-and-best-practices/">MongoDB Security guidelines and best practices</a> first appeared on <a href="https://thecodebuzz.com">TheCodeBuzz</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://thecodebuzz.com/mongodb-security-guidelines-and-best-practices/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
