<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>rss.livelink.threads-in-node</title>
    <link>https://techcommunity.microsoft.com/t5/azure-data/ct-p/AzureDatabases</link>
    <description>rss.livelink.threads-in-node</description>
    <pubDate>Thu, 16 Jul 2026 08:20:50 GMT</pubDate>
    <dc:creator>AzureDatabases</dc:creator>
    <dc:date>2026-07-16T08:20:50Z</dc:date>
    <item>
      <title>ADF - Support for Federated Identity Credentials</title>
      <link>https://techcommunity.microsoft.com/t5/azure-data-factory/adf-support-for-federated-identity-credentials/m-p/4537444#M980</link>
      <description>&lt;P&gt;Our team is working on migrating existing pipelines to Azure Data Factory (ADF). As part of this effort, we are evaluating ADF for executing Kusto commands and would like to use an existing Microsoft Entra application registration authenticated through Federated Identity Credentials (OIDC workload identity federation).&lt;/P&gt;
&lt;P&gt;Today, ADF appears to primarily support Managed Identity-based authentication patterns. Is there any planned support for using a customer-owned App Registration with &lt;STRONG&gt;Federated Identity Credentials (FIC)&lt;/STRONG&gt;? If so, is there any public roadmap or timeline that can be shared?&lt;/P&gt;
&lt;P&gt;We are actively moving away from secret- and certificate-based authentication. Supporting FIC would allow us to continue using our existing application identities, which already have the required permissions on source and destination datasets, and would avoid the need to introduce additional User Assigned Managed Identities and request new permission grants from dataset owners as part of the migration.&lt;/P&gt;</description>
      <pubDate>Wed, 15 Jul 2026 18:01:00 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-data-factory/adf-support-for-federated-identity-credentials/m-p/4537444#M980</guid>
      <dc:creator>rcaidben</dc:creator>
      <dc:date>2026-07-15T18:01:00Z</dc:date>
    </item>
    <item>
      <title>Generally Available: SQL Migration to SQL Server on Azure Virtual Machines in Azure Architecture</title>
      <link>https://techcommunity.microsoft.com/t5/microsoft-data-migration-blog/generally-available-sql-migration-to-sql-server-on-azure-virtual/ba-p/4536940</link>
      <description>&lt;H3&gt;One Migration Experience, More Flexibility&lt;/H3&gt;
&lt;P&gt;Modernizing SQL Server estates is rarely a single-step journey. Organizations often operate across on-premises, hybrid, and cloud environments while balancing application dependencies, operational requirements, and modernization goals. SQL Server migration enabled by Azure Arc simplifies this process by bringing migration activities into a single experience in the Azure portal.&lt;/P&gt;
&lt;P&gt;With the July 2026 release, we are announcing &lt;STRONG&gt;General Availability of SQL Server on Azure Virtual Machines as a migration target in Azure Arc&lt;/STRONG&gt;, allowing customers to have a greater flexibility to choose Azure destination that best aligns with to your needs without introducing additional tools or migration processes.&lt;/P&gt;
&lt;P&gt;Whether migrating to the fully managed Azure SQL Managed Instance service or to SQL Server running on Azure VMs, the experience remains consistent and familiar.&lt;/P&gt;
&lt;H3&gt;Unified Migration Workflow&lt;/H3&gt;
&lt;P&gt;A key benefit of SQL Server migration enabled by Azure Arc is that the entire migration lifecycle is managed from a single tool in Azure portal.&lt;/P&gt;
&lt;P&gt;After a SQL Server instance is enabled by Azure Arc, customers can:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Assess migration readiness&lt;/LI&gt;
&lt;LI&gt;Select a migration target&lt;/LI&gt;
&lt;LI&gt;Configure migration settings&lt;/LI&gt;
&lt;LI&gt;Monitor migration progress&lt;/LI&gt;
&lt;LI&gt;Validate results&lt;/LI&gt;
&lt;LI&gt;Perform final cutover&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;All of these activities are performed directly from the Azure portal using a guided workflow designed to simplify migration planning and execution.&lt;/P&gt;
&lt;P&gt;The prerequisite remains unchanged: source SQL Server instances must be enabled by Azure Arc before migration can begin. The result is a flexible, scalable, and consistent migration experience that supports hybrid realities, reduces operational overhead, and helps customers modernize SQL Server estates at their own pace.&lt;/P&gt;
&lt;H3&gt;Consistent Experience Across Azure SQL Targets&lt;/H3&gt;
&lt;P&gt;Migration to SQL Server on Azure Virtual Machines follows the same operational model already available for Azure SQL Managed Instance migration scenarios.&lt;/P&gt;
&lt;P&gt;Customers use the same migration dashboard, monitoring experience, and guided workflow regardless of the destination. This consistency reduces learning curves, simplifies operational processes, and enables teams to select the most appropriate Azure SQL platform without changing migration methodology.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3&gt;Online Migration Using Backup and Log Shipping&lt;/H3&gt;
&lt;P&gt;Migration to SQL Server on Azure Virtual Machines uses backup and restore with log shipping to support online migration scenarios while minimizing downtime.&lt;/P&gt;
&lt;P&gt;The process begins with a full database backup that is restored to the target SQL Server instance running on an Azure Virtual Machine. Transaction log backups that are uploaded continuously by your workflows to Azure Blob Storage are continuously applied to the target database, keeping it closely synchronized with the source environment.&lt;/P&gt;
&lt;P&gt;Azure Blob Storage serves as the intermediary staging location between source and target systems. To support efficient data movement and restore operations, both the Azure Blob Storage account and the target SQL Server on Azure Virtual Machines must reside in the same Azure region.&lt;/P&gt;
&lt;P&gt;Within the Azure Arc migration experience, customers select the Azure Blob Storage container that stores the backup files. Azure Arc automatically restores the full backup and continuously applies transaction log backups as they become available. Customers are responsible for configuring and maintaining the continuous upload of transaction log backups to Azure Blob Storage.&lt;/P&gt;
&lt;H3&gt;Customer-Controlled Cutover&lt;/H3&gt;
&lt;P&gt;When the customer is ready to complete migration, upon customer initiated cutover, Azure Arc performs the final synchronization by applying the last uploaded backup and bringing the target database online.&lt;/P&gt;
&lt;P&gt;This approach gives organizations full control over the migration timeline and cutover window, allowing downtime to be planned according to business requirements while reducing operational complexity.&lt;/P&gt;
&lt;H3&gt;Learn More&lt;/H3&gt;
&lt;P&gt;To learn more about SQL Server migration enabled by Azure Arc, see:&amp;nbsp;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/sql/sql-server/azure-arc/migration-overview" target="_blank"&gt;Migration Overview&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;For information about migrating to SQL Server in Azure VM, see: &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/sql/sql-server/azure-arc/migrate-to-sql-server-on-azure-vms?view=sql-server-ver17" target="_blank"&gt;Migrate to SQL Server in Azure VM&lt;/A&gt;&lt;/P&gt;</description>
      <pubDate>Tue, 14 Jul 2026 15:02:54 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/microsoft-data-migration-blog/generally-available-sql-migration-to-sql-server-on-azure-virtual/ba-p/4536940</guid>
      <dc:creator>danimir</dc:creator>
      <dc:date>2026-07-14T15:02:54Z</dc:date>
    </item>
    <item>
      <title>Generally Available: SQL Migration to SQL Server on Azure Virtual Machines in Azure Architecture</title>
      <link>https://techcommunity.microsoft.com/t5/azure-sql-blog/generally-available-sql-migration-to-sql-server-on-azure-virtual/ba-p/4536939</link>
      <description>&lt;H3&gt;One Migration Experience, More Flexibility&lt;/H3&gt;
&lt;P&gt;Modernizing SQL Server estates is rarely a single-step journey. Organizations often operate across on-premises, hybrid, and cloud environments while balancing application dependencies, operational requirements, and modernization goals. SQL Server migration enabled by Azure Arc simplifies this process by bringing migration activities into a single experience in the Azure portal.&lt;/P&gt;
&lt;P&gt;With the July 2026 release, we are announcing &lt;STRONG&gt;General Availability of SQL Server on Azure Virtual Machines as a migration target in Azure Arc&lt;/STRONG&gt;, allowing customers to have a greater flexibility to choose Azure destination that best aligns with to your needs without introducing additional tools or migration processes.&lt;/P&gt;
&lt;P&gt;Whether migrating to the fully managed Azure SQL Managed Instance service or to SQL Server running on Azure VMs, the experience remains consistent and familiar.&lt;/P&gt;
&lt;H3&gt;Unified Migration Workflow&lt;/H3&gt;
&lt;P&gt;A key benefit of SQL Server migration enabled by Azure Arc is that the entire migration lifecycle is managed from a single tool in Azure portal.&lt;/P&gt;
&lt;P&gt;After a SQL Server instance is enabled by Azure Arc, customers can:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Assess migration readiness&lt;/LI&gt;
&lt;LI&gt;Select a migration target&lt;/LI&gt;
&lt;LI&gt;Configure migration settings&lt;/LI&gt;
&lt;LI&gt;Monitor migration progress&lt;/LI&gt;
&lt;LI&gt;Validate results&lt;/LI&gt;
&lt;LI&gt;Perform final cutover&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;All of these activities are performed directly from the Azure portal using a guided workflow designed to simplify migration planning and execution.&lt;/P&gt;
&lt;P&gt;The prerequisite remains unchanged: source SQL Server instances must be enabled by Azure Arc before migration can begin. The result is a flexible, scalable, and consistent migration experience that supports hybrid realities, reduces operational overhead, and helps customers modernize SQL Server estates at their own pace.&lt;/P&gt;
&lt;H3&gt;Consistent Experience Across Azure SQL Targets&lt;/H3&gt;
&lt;P&gt;Migration to SQL Server on Azure Virtual Machines follows the same operational model already available for Azure SQL Managed Instance migration scenarios.&lt;/P&gt;
&lt;P&gt;Customers use the same migration dashboard, monitoring experience, and guided workflow regardless of the destination. This consistency reduces learning curves, simplifies operational processes, and enables teams to select the most appropriate Azure SQL platform without changing migration methodology.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3&gt;Online Migration Using Backup and Log Shipping&lt;/H3&gt;
&lt;P&gt;Migration to SQL Server on Azure Virtual Machines uses backup and restore with log shipping to support online migration scenarios while minimizing downtime.&lt;/P&gt;
&lt;P&gt;The process begins with a full database backup that is restored to the target SQL Server instance running on an Azure Virtual Machine. Transaction log backups that are uploaded continuously by your workflows to Azure Blob Storage are continuously applied to the target database, keeping it closely synchronized with the source environment.&lt;/P&gt;
&lt;P&gt;Azure Blob Storage serves as the intermediary staging location between source and target systems. To support efficient data movement and restore operations, both the Azure Blob Storage account and the target SQL Server on Azure Virtual Machines must reside in the same Azure region.&lt;/P&gt;
&lt;P&gt;Within the Azure Arc migration experience, customers select the Azure Blob Storage container that stores the backup files. Azure Arc automatically restores the full backup and continuously applies transaction log backups as they become available. Customers are responsible for configuring and maintaining the continuous upload of transaction log backups to Azure Blob Storage.&lt;/P&gt;
&lt;H3&gt;Customer-Controlled Cutover&lt;/H3&gt;
&lt;P&gt;When the customer is ready to complete migration, upon customer initiated cutover, Azure Arc performs the final synchronization by applying the last uploaded backup and bringing the target database online.&lt;/P&gt;
&lt;P&gt;This approach gives organizations full control over the migration timeline and cutover window, allowing downtime to be planned according to business requirements while reducing operational complexity.&lt;/P&gt;
&lt;H3&gt;Learn More&lt;/H3&gt;
&lt;P&gt;To learn more about SQL Server migration enabled by Azure Arc, see:&amp;nbsp;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/sql/sql-server/azure-arc/migration-overview" target="_blank"&gt;Migration Overview&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;For information about migrating to SQL Server in Azure VM, see: &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/sql/sql-server/azure-arc/migrate-to-sql-server-on-azure-vms?view=sql-server-ver17" target="_blank"&gt;Migrate to SQL Server in Azure VM&lt;/A&gt;&lt;/P&gt;</description>
      <pubDate>Tue, 14 Jul 2026 15:01:52 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-sql-blog/generally-available-sql-migration-to-sql-server-on-azure-virtual/ba-p/4536939</guid>
      <dc:creator>danimir</dc:creator>
      <dc:date>2026-07-14T15:01:52Z</dc:date>
    </item>
    <item>
      <title>PostgreSQL on Azure: Two services, one future-proofed ecosystem</title>
      <link>https://techcommunity.microsoft.com/t5/microsoft-blog-for-postgresql/postgresql-on-azure-two-services-one-future-proofed-ecosystem/ba-p/4536578</link>
      <description>&lt;P&gt;&lt;SPAN data-contrast="none"&gt;At Microsoft Build 2026, the Azure Databases team announced the &lt;/SPAN&gt;&lt;A href="https://techcommunity.microsoft.com/blog/adforpostgresql/azure-horizondb-enterprise-ready-postgres-engineered-for-the-ai-era/4524094" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;public preview of&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt; Azure HorizonDB&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="none"&gt;, a new powerhouse for PostgreSQL in the cloud. It’s a fully managed, PostgreSQL-compatible cloud database service that delivers sub-millisecond latency, rapid read scale-out, and seamless integration with Microsoft Foundry to empower teams to build secure, compliant and high-performing applications with confidence. At the same event, we also &lt;/SPAN&gt;&lt;A href="https://techcommunity.microsoft.com/blog/adforpostgresql/announcing-new-security-maintenance-and-analytics-features-for-postgresql-at-mic/4524559" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;announced several enhancements to the existing managed PostgreSQL offering&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="none"&gt;, Azure Database for PostgreSQL flexible server, boosting performance, analytics and security, and expanding tooling for migration scenarios.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;Where there was one, now &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;there’s&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt; two&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:360,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Now our customers have two strong options to choose from. Azure Database for PostgreSQL remains a reliable, cost-effective, fully open-source compatible workhorse for most users’ everyday needs. Azure HorizonDB is the new PostgreSQL-compatible service with an elastic scale-out architecture built on a highly optimized shared storage system that unlocks &lt;/SPAN&gt;&lt;A href="https://techcommunity.microsoft.com/blog/adforpostgresql/azure-horizondb-enterprise-ready-postgres-engineered-for-the-ai-era/4524094" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;3&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;x &lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;faster OLTP &lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;performance&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="none"&gt; and other cloud-native advantages for the most demanding workloads. &lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;With this new service, you might be wondering which service is the best fit. Let’s take a closer look at these options and explore where they align and differ and what you might want to consider when making your choice.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;Azure Database for PostgreSQL: &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;Enterprise ready, &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;managed open source&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:360,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Microsoft is one of the largest contributors to the open-source Postgres project and has also invested heavily in PostgreSQL managed services on Azure. Microsoft engineers have authored or co-authored hundreds of code commits and provided extensive reviews, and, to date, have made more than 345 commits and changed more than 64K lines of code for PostgreSQL 19. In the cloud, Azure Database for PostgreSQL is built on the open-source ecosystem, sharing the same extensions and experience that developers and DBAs know and love. Patching, backups, scaling, and monitoring are all simple, one-click operations. If you have an app that already uses a PostgreSQL database, in another cloud or on-premises, migrating to Azure for the added benefits is an easy lift and shift.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H3 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Inside Azure Database for PostgreSQL&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:40,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Azure Database for PostgreSQL is a mature, feature-rich service already battle-tested by thousands of applications and being used by Fortune 500s across sectors.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="4" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;Enterprise-grade performance: &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;Compute tiers can scale up to 192 vCores with features like read replicas and elastic clusters, which is based on the open-source Citus extension and unique to this class of service, make it easy to right-size workloads and optimize performance by offloading read-heavy traffic or sharding data across nodes.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="4" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="2" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;Reliability and security: &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;Backed by Azure’s robust infrastructure, Azure Database for PostgreSQL comes equipped with high availability and zone-redundant options, point-in time restore and security features, including data encryption, network isolation, and Entra ID for enterprise identity.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="4" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="3" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;Frictionless migrations: &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;Migrating existing PostgreSQL workloads to Azure Database for PostgreSQL is very straightforward thanks to built-in migration tooling. We’ve even launched AI-assisted tooling for Oracle to PostgreSQL migrations in VS Code, which leverages GitHub Copilot AI to handle app and schema conversions and pre-migration validations.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;From incorporating cutting-edge hardware, horizontal scaling and Microsoft Fabric and Microsoft Foundry integrations, to supporting 90+ open-source extensions and counting, we continue to optimize the service to meet the needs of our customers building on open-source Postgres.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;Azure HorizonDB: &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;Next&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;-gen engine &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;to build &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt;what’s&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 1"&gt; next&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:360,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Azure HorizonDB was designed and purpose-built to meet the needs of modern AI-native applications and large-scale enterprise migrations. Shireesh Thota, Azure Databases CVP, describes it as the database of choice for workloads that need &lt;/SPAN&gt;&lt;A href="https://www.infoworld.com/article/4093191/azure-horizondb-microsoft-goes-big-with-postgresql.html" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;“a lot of storage, want really fast latencies and significantly higher IOPS.”&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt; &lt;SPAN data-contrast="none"&gt;The service offers faster throughput than open-source PostgreSQL and rapid compute scale-out to support the performance and availability needs of your most demanding applications.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H3 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Inside Azure HorizonDB&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:40,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Azure HorizonDB is where performance meets possibility, empowering teams to build intelligent apps to scale, modernize, and innovate without compromise.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;Cloud-tuned performance: &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;The cloud-native architecture of Azure &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;HorizonDB fully decouples compute and storage, enabling &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;users to scale database resources independently. The service can support deployments up to 3,072 vCores and 128 TB of shared storage for a single workload, and provides a single endpoint for read replicas with transparent load balancing to deliver massive read throughput seamlessly to the application.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="2" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;Reliability and security: &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;Azure HorizonDB comes standard with features to support production-level, mission-critical enterprise workloads. Built-in multi-availability zone (AZ) replication reduces failover time to less than 5 seconds, and native integration with Microsoft Entra ID and private endpoint networking ensures Azure HorizonDB meets the Azure-standard enterprise-grade security from day one.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="3" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;Tailored for AI and next-gen apps:&lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt; Azure &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;HorizonDB provides an extensive set of AI features for building modern applications. In comparison to similar PostgreSQL services in the cloud, &lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;IDC described Azure HorizonDB as having &lt;/SPAN&gt;&lt;A href="https://www.theregister.com/2025/11/19/microsoft_azure_horizondb/" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;"fewer moving parts and a straighter path to AI features.”&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="none"&gt; Azure HorizonDB ships with Microsoft’s latest version of DiskANN vector indexing, which includes advanced filtering that delivers up to &lt;/SPAN&gt;&lt;A href="https://techcommunity.microsoft.com/blog/adforpostgresql/azure-horizondb-enterprise-ready-postgres-engineered-for-the-ai-era/4524094" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;3&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;x faster vector search&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt; than traditional &lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;pgvector indexes&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="none"&gt;. It also comes with built-in AI Model Management for native integration to Microsoft Foundry models, AI Functions to invoke models from SQL, and AI Pipelines to provide durable orchestration of data modification.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="4" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;Developer productivity&lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;: Along with building the best Postgres service, Microsoft is committed to delivering the best Postgres developer tools to the entire community. The &lt;/SPAN&gt;&lt;A href="https://marketplace.visualstudio.com/items?itemName=ms-ossdata.vscode-pgsql" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;Microsoft &lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;PostgreSQL extension for Visual Studio (VS) Code&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="none"&gt; makes the coding environment Postgres-aware to help optimize queries, schemas and query performance using AI.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Azure HorizonDB is the next-generation of PostgreSQL on Azure for mission-critical, high-throughput, and data-intensive workloads. For everything else, Azure Database for PostgreSQL remains a strong choice.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Making &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;your&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="heading 2"&gt;selection&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:40,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Adopting technology should always be driven by a real need. Having two choices is great, but it raises the logical question: “which one is right for me and when?”&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H3 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Choose Azure Database for PostgreSQL when:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:40,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H3&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;You’re migrating existing Postgres databases as-is. You can migrate seamlessly to Azure Database for PostgreSQL with minimal tweaks or reconfigurations.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="2" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;You require full open-source compatibility, including rapid adoption of new community versions. Azure Database for PostgreSQL now ships major versions on the same day as the community release.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="3" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;You want to start now and decide later. Azure Database for PostgreSQL is generally available in 60+ regions today. Later, if your project requires greater scale, you can upgrade to Azure HorizonDB, and the migration process will be quick and easy.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Choos&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;e Azure &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;HorizonDB when&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:40,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H3&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="2" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;You’re migrating tier-1 workloads to the cloud that already have critical scale, performance, and availability requirements. Up to 128 TB of storage and 3,072 vCores for a single workload makes Azure HorizonDB the ideal destination for these workloads.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="2" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="2" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;You anticipate requirements that go beyond Azure Database for PostgreSQL’s capabilities. Azure HorizonDB expands on the capabilities of Azure Database for PostgreSQL, so you’ll be future proofed for scale and reliability.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="2" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="3" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;You are focused on building next-gen intelligent apps. Azure HorizonDB is optimized for building new AI applications, enabling developers to ship faster with fewer moving parts.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Both services are built on the core Postgres engine, and upgrading to Azure HorizonDB is easy. If your scenario changes, your toolkit can change too. Azure offers the managed service to support you either way.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Choose &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;the cloud with the deepest Postgres &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;expertise&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:40,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;The PostgreSQL ecosystem on Azure is richer than ever. With both Azure Database for PostgreSQL and Azure HorizonDB, Azure covers the spectrum from steady, everyday workloads to cutting-edge, innovative ones. Whether you’re in a two-person startup or a Fortune 500 enterprise, PostgreSQL on Azure can meet your business’ needs.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Now is the perfect time to make a move to Postgres on Azure:&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;A href="https://azure.microsoft.com/en-us/products/postgresql/" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;Learn more about &lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;Azure Database for PostgreSQL&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1" data-list-defn-props="{&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;hybridMultilevel&amp;quot;}" data-aria-posinset="2" data-aria-level="1"&gt;&lt;A href="https://azure.microsoft.com/en-us/products/horizondb" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;Learn more about &lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;Azure HorizonDB&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Tue, 14 Jul 2026 15:00:00 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/microsoft-blog-for-postgresql/postgresql-on-azure-two-services-one-future-proofed-ecosystem/ba-p/4536578</guid>
      <dc:creator>charlesfeddersenMS</dc:creator>
      <dc:date>2026-07-14T15:00:00Z</dc:date>
    </item>
    <item>
      <title>Lessons Learned #544: How to Detect INT Identity Exhaustion Before Inserts Fail.</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/lessons-learned-544-how-to-detect-int-identity-exhaustion-before/ba-p/4536565</link>
      <description>&lt;P&gt;Recently, I worked on a support case involving an Azure SQL Database table where the customer &lt;STRONG&gt;had reached the maximum value supported&lt;/STRONG&gt; by the INT data type. The table used an INT IDENTITY(1,1) column as its primary key. Over time, the generated identity value approached the maximum value supported by INT. Once the available range was exhausted, the application was no longer able to insert new rows.&lt;/P&gt;
&lt;P&gt;At that point, the column needed to be changed from INT to BIGINT. However, performing this type of migration on a very large table can be a complex and time-consuming operation. &lt;STRONG&gt;The situation is that an INT column uses 4 bytes and supports values from: -2,147,483,648 to: 2,147,483,647.&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;To prevent similar problems in the future, I suggested using the following query to review the current status of all INT IDENTITY columns in the database. The query uses the &lt;STRONG&gt;sys.identity_columns&lt;/STRONG&gt; catalog view:&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;SELECT
    s.name AS SchemaName,
    t.name AS TableName,
    c.name AS ColumnName,
    CONVERT(bigint, c.last_value) AS CurrentIdentityValue,
    CONVERT(bigint, 2147483647) AS MaximumIntValue,
    CONVERT(bigint, 2147483647) - 
        ISNULL(CONVERT(bigint, c.last_value), 0) AS RemainingValues,
    CAST(
        ISNULL(CONVERT(decimal(20,2), c.last_value), 0)
        / 2147483647 * 100
        AS decimal(6,2)
    ) AS PercentUsed
FROM sys.identity_columns AS c
INNER JOIN sys.tables AS t
    ON c.object_id = t.object_id
INNER JOIN sys.schemas AS s
    ON t.schema_id = s.schema_id
WHERE TYPE_NAME(c.system_type_id) = 'int'
ORDER BY PercentUsed DESC;&lt;/LI-CODE&gt;
&lt;P&gt;I prefer using this query instead of relying on: SELECT COUNT(*) FROM dbo.TableName. &lt;STRONG&gt;The number of rows in a table does not necessarily match the current identity value. Rows might have been deleted, transactions might have been rolled back, and identity values might contain gaps.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;For this reason, the current identity value is a better indicator of the remaining capacity. &lt;STRONG&gt;Adding this query as a regular preventive check can help identify identity columns that are approaching their limits before they cause application failures.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;I would like to share with you an example creates a table with an identity seed close to the maximum value supported by INT:&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;DROP TABLE IF EXISTS dbo.IdentityCapacityDemo2; 
CREATE TABLE dbo.IdentityCapacityDemo2 ( Id INT IDENTITY(2147483600,1) NOT NULL, CreatedDate datetime2(0) NOT NULL CONSTRAINT DF_IdentityCapacityDemo2_CreatedDate DEFAULT SYSUTCDATETIME(), CONSTRAINT PK_IdentityCapacityDemo2 PRIMARY KEY CLUSTERED (Id) )&lt;/LI-CODE&gt;
&lt;P&gt;Insert 20 rows using this command:&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;insert into IdentityCapacityDemo2(CreatedDate) values(SYSUTCDATETIME())&lt;/LI-CODE&gt;
&lt;P&gt;Example of returns:&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;I think runnning this preventive check can help detect identity exhaustion before it affects the application.&lt;/P&gt;</description>
      <pubDate>Mon, 13 Jul 2026 17:28:24 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/lessons-learned-544-how-to-detect-int-identity-exhaustion-before/ba-p/4536565</guid>
      <dc:creator>Jose_Manuel_Jurado</dc:creator>
      <dc:date>2026-07-13T17:28:24Z</dc:date>
    </item>
    <item>
      <title>Lessons Learned #543: Evaluating MultiSubnetFailover with Azure SQL Database</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/lessons-learned-543-evaluating-multisubnetfailover-with-azure/ba-p/4536554</link>
      <description>&lt;P&gt;Last week, I worked on a support case in which the use of the &lt;STRONG&gt;MultiSubnetFailover connection-string&lt;/STRONG&gt; feature was being considered for an application connecting to Azure SQL Database.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The expectation was that enabling the following option could improve connection recovery during a database failover changing MultiSubnetFailover to True.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This option is commonly associated with SQL Server high availability, and Azure SQL Database is also designed to remain available by moving databases between replicas when required. However, after reviewing the Azure SQL Database connectivity architecture and comparing the behavior with the property enabled and disabled, I did not observe a clear improvement.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The property could be added to the connection string without generating an error, and the application was able to connect successfully with both configurations.&lt;/P&gt;
&lt;H1&gt;What MultiSubnetFailover is designed for&lt;/H1&gt;
&lt;P&gt;MultiSubnetFailover was introduced primarily for SQL Server high-availability configurations such as:&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Always On Availability Group listeners.&lt;/LI&gt;
&lt;LI&gt;SQL Server Failover Cluster Instance virtual network names.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;In a multi-subnet Availability Group, a listener name may resolve to multiple IP addresses located in different network subnets.&lt;/P&gt;
&lt;P&gt;Without &lt;STRONG&gt;MultiSubnetFailover=True&lt;/STRONG&gt;, the application may try those addresses sequentially. If the first address is not currently active, the connection can be delayed while the attempt waits for a timeout. When the option is enabled, supported SQL client drivers can attempt connections to the listener addresses in parallel and use the first address that responds successfully. This can reduce connection time after an Availability Group failover because the SQL client is directly involved in selecting the reachable listener address.&lt;/P&gt;
&lt;H1&gt;Why Azure SQL Database is different&lt;/H1&gt;
&lt;P&gt;Azure SQL Database uses a different connectivity architecture. The application connects to a logical server endpoint: &amp;lt;server-name&amp;gt;.database.windows.net. The Azure SQL connectivity layer receives the connection and routes it to the infrastructure currently hosting the database.&lt;/P&gt;
&lt;P&gt;Depending on the configured connection policy, the Azure SQL gateway &lt;STRONG&gt;either proxies the connection or redirects &lt;/STRONG&gt;the application to the appropriate database node. The important difference is that the SQL client does not receive a list containing the IP addresses of the Azure SQL Database primary and secondary replicas. The decision and the associated routing are managed by the Azure SQL Database platform.&lt;/P&gt;
&lt;P&gt;Although Azure SQL Database internally uses multiple replicas for high availability, this is not the same connectivity model as a SQL Server Availability Group listener that publishes multiple addresses through DNS.&lt;/P&gt;
&lt;H1&gt;What about Failover Groups?&lt;/H1&gt;
&lt;P&gt;Azure SQL Database Failover Groups provide a stable listener endpoint such as: &amp;lt;failover-group-name&amp;gt;.database.windows.net. Following a regional failover, &lt;STRONG&gt;the listener is updated so that it points to the logical server hosting the new primary databases&lt;/STRONG&gt;. This process depends partly on DNS. The listener name remains the same, but its DNS target changes after the failover.&lt;/P&gt;
&lt;P&gt;This is still different from a SQL Server multi-subnet Availability Group listener. The Failover Group listener does not expose the addresses of the Azure SQL Database replicas to the SQL client. Therefore, MultiSubnetFailover=True cannot directly select the new primary replica.&lt;/P&gt;
&lt;P&gt;In this scenario, &lt;STRONG&gt;application recovery continues to depend on the service transition, DNS resolution, and retry behavior.&lt;/STRONG&gt;&lt;/P&gt;
&lt;H1&gt;The importance of retry logic&lt;/H1&gt;
&lt;P&gt;One of the main lessons from this case was that retry logic is more relevant to Azure SQL Database resiliency than enabling MultiSubnetFailover. An application connecting to Azure SQL Database must expect occasional transient connectivity errors. These can occur during maintenance, scaling, failover, network interruptions, or temporary service conditions.&lt;/P&gt;
&lt;P&gt;An appropriate retry strategy should normally include:&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;A &lt;STRONG&gt;limited number&lt;/STRONG&gt; of &lt;STRONG&gt;retry attempts&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;A &lt;STRONG&gt;short delay before the first retry&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;Increasing &lt;STRONG&gt;delays between subsequent&lt;/STRONG&gt; attempts.&lt;/LI&gt;
&lt;LI&gt;A maximum &lt;STRONG&gt;retry interval&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;Creation of a fresh SQL connection.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN style="color: rgb(30, 30, 30);"&gt;&lt;STRONG&gt;For transactions, retry logic requires additional care.&lt;/STRONG&gt; The application must determine whether the transaction was committed, rolled back, or left in an unknown state before repeating the complete operation.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 13 Jul 2026 16:34:02 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/lessons-learned-543-evaluating-multisubnetfailover-with-azure/ba-p/4536554</guid>
      <dc:creator>Jose_Manuel_Jurado</dc:creator>
      <dc:date>2026-07-13T16:34:02Z</dc:date>
    </item>
    <item>
      <title>Number of concurrent transactions supported for an Azure SQL 4 vCores</title>
      <link>https://techcommunity.microsoft.com/t5/azure-sql/number-of-concurrent-transactions-supported-for-an-azure-sql-4/m-p/4534251#M267</link>
      <description>&lt;P&gt;I have an Azure SQL:&lt;/P&gt;&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;P&gt;Parameters&lt;/P&gt;&lt;/td&gt;&lt;td&gt;&lt;P&gt;Specifications&lt;/P&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;P&gt;Deployment Model&lt;/P&gt;&lt;/td&gt;&lt;td&gt;&lt;P&gt;General Purpose – Serverless&lt;/P&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;P&gt;SKU / Performance Tier&lt;/P&gt;&lt;/td&gt;&lt;td&gt;&lt;P&gt;Standard Series&lt;/P&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;P&gt;Database Size&lt;/P&gt;&lt;/td&gt;&lt;td&gt;&lt;P&gt;128 GB&lt;/P&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;P&gt;Max vCores&lt;/P&gt;&lt;/td&gt;&lt;td&gt;&lt;P&gt;4 vCores (scalable within Serverless range)&lt;/P&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/DIV&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;How many concurrent transactions are supported for an Azure SQL db with the above specifications.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thanks&lt;/P&gt;</description>
      <pubDate>Tue, 07 Jul 2026 02:51:17 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-sql/number-of-concurrent-transactions-supported-for-an-azure-sql-4/m-p/4534251#M267</guid>
      <dc:creator>SudeepSahdeva</dc:creator>
      <dc:date>2026-07-07T02:51:17Z</dc:date>
    </item>
    <item>
      <title>From RAG to agents: Build AI pipelines inside Azure HorizonDB</title>
      <link>https://techcommunity.microsoft.com/t5/microsoft-blog-for-postgresql/from-rag-to-agents-build-ai-pipelines-inside-azure-horizondb/ba-p/4532696</link>
      <description>&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;By Abe Omorogbe, &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;Navya&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; Teja Gajula&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;,&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-teams="true"&gt;&lt;SPAN data-person-mri="8:orgid:5d314a16-231c-40c3-b2d7-60818259729f" data-is-share-contact="false" data-mention-type="person" aria-label="Mentioned Binnur Gorer"&gt;Binnur Gorer, B Harsha Kashyap,&lt;/SPAN&gt;&amp;nbsp;&lt;SPAN data-person-mri="8:orgid:4f6ccf88-de1e-417e-9971-f4263b13b4d2" data-is-share-contact="false" data-mention-type="person" aria-label="Mentioned Krishnakumar Ravi (KK)"&gt;Krishnakumar Ravi (KK) &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;from &lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;Microsoft&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; PostgreSQL AI team&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;If &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;you’ve&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; ever shipped a RAG app, this &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;will feel&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;familiar. Your data lives in Postgres. But the pipeline that turns that data into vectors lives somewhere else, &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;s&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;pread&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; across &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;external&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; service&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;s&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;, queue&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;s&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;, and retry logic. And &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;when&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; the embedding API &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;hiccups&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; mid-batch? &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;That’s&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; a 2 a.m. &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;p&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;roduction incident&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;. You &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;didn’t&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; set out to build your own embedding service. You just wanted to &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;search&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; your documents.&lt;/SPAN&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;BR /&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;And RAG is only the beginning. The moment AI works on your data: extraction, summarization, reranking, keeping embeddings fresh, or powering agent&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;, &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;you’re&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; back to stitching together more services, queues, and glue code, all outside the database.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;AI pipelines in Azure &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; (Preview)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;removes that entir&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;e &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;stack&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;. &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;Define your workflows steps like chunking, embeding, extracting, and generating in SQL, and &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; runs them as &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;AI&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; pipelines next to your data. No orchestrator. No glue code. Just Postgres.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;BR /&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;In this post &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;we'll&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; cover:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A class="lia-internal-link" href="#community--1-ai-preprocessing" target="_blank" rel="noopener" data-lia-auto-title="The external-orchestrator issue that every AI on Postgres team eventually hits" data-lia-auto-title-active="0"&gt;The external-orchestrator issue that every AI on Postgres team eventually hits&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A class="lia-internal-link" href="#community--1-anatomy" target="_blank" rel="noopener" data-lia-auto-title="What AI pipelines are, and the four-part anatomy that makes them click&amp;nbsp;" data-lia-auto-title-active="0"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;What AI pipelines are, and the four-part anatomy that makes them click&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A class="lia-internal-link" href="#community--1-use-cases" target="_blank" rel="noopener" data-lia-auto-title="Use cases worth trying: semantic search, knowledge extraction, content generation, smarter reranking, and always-fresh embeddings&amp;nbsp;" data-lia-auto-title-active="0"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;U&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;se cases&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Compact"&gt;worth &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;trying:&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="Compact"&gt;semantic search, knowledge extraction, content generation, smarter reranking, and always-fresh embeddings&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A class="lia-internal-link" href="#community--1-vs-code" target="_blank" rel="noopener" data-lia-auto-title="How to watch your pipelines run as live graphs in VS Code" data-lia-auto-title-active="0"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;How to watch your pipelines run as live graphs in VS Code&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A class="lia-internal-link" href="#community--1-start-now" target="_blank" rel="noopener" data-lia-auto-title="How to spin up&amp;nbsp;HorizonDB and run your first pipeline today&amp;nbsp;" data-lia-auto-title-active="0"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;How to spin up&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt; and run your first pipeline today&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt; &lt;/SPAN&gt;&lt;/A&gt;&amp;nbsp;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN class="lia-linked-item" data-ccp-parastyle="heading 2"&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;🚀 Try it on Azure &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;STRONG&gt; &lt;/STRONG&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;AI pipelines are built into Microsoft's new PostgreSQL cloud service&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;, &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;no&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; extra infrastructure to stand up. Write&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char" data-ccp-charstyle-defn="{&amp;quot;ObjectId&amp;quot;:&amp;quot;a31b87fc-7929-525d-a968-aa0f568a0536|1&amp;quot;,&amp;quot;ClassId&amp;quot;:1073872969,&amp;quot;Properties&amp;quot;:[201342446,&amp;quot;1&amp;quot;,201342447,&amp;quot;5&amp;quot;,201342448,&amp;quot;3&amp;quot;,201342449,&amp;quot;1&amp;quot;,469777841,&amp;quot;Consolas&amp;quot;,469777842,&amp;quot;&amp;quot;,469777843,&amp;quot;&amp;quot;,469777844,&amp;quot;Consolas&amp;quot;,201341986,&amp;quot;1&amp;quot;,469769226,&amp;quot;Consolas&amp;quot;,268442635,&amp;quot;22&amp;quot;,469775450,&amp;quot;Verbatim Char&amp;quot;,201340122,&amp;quot;1&amp;quot;,134233614,&amp;quot;true&amp;quot;,469778129,&amp;quot;VerbatimChar&amp;quot;,335572020,&amp;quot;1&amp;quot;,469778324,&amp;quot;Body Text Char&amp;quot;]}"&gt;ai.create_pipeline&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;(...)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;, call&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.run&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;(...)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;, and it runs.&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/horizondb/" target="_blank" rel="noopener"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;Get started in HorizonDB →&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;a id="community--1-ai-preprocessing" class="lia-anchor"&gt;&lt;/a&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN class="lia-linked-item" data-ccp-parastyle="heading 2"&gt;AI preprocessing runs outside the database, far from your&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;&amp;nbsp;data &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:160,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph" data-ccp-parastyle-defn="{&amp;quot;ObjectId&amp;quot;:&amp;quot;276295ed-5df2-5456-988c-5fdbab071054|1&amp;quot;,&amp;quot;ClassId&amp;quot;:1073872969,&amp;quot;Properties&amp;quot;:[201342446,&amp;quot;1&amp;quot;,201342447,&amp;quot;5&amp;quot;,201342448,&amp;quot;3&amp;quot;,201342449,&amp;quot;1&amp;quot;,469777841,&amp;quot;Aptos&amp;quot;,469777842,&amp;quot;&amp;quot;,469777843,&amp;quot;&amp;quot;,469777844,&amp;quot;Aptos&amp;quot;,201341986,&amp;quot;1&amp;quot;,469769226,&amp;quot;Aptos&amp;quot;,268442635,&amp;quot;24&amp;quot;,335559739,&amp;quot;180&amp;quot;,335559738,&amp;quot;180&amp;quot;,469775450,&amp;quot;First Paragraph&amp;quot;,201340122,&amp;quot;2&amp;quot;,134234082,&amp;quot;true&amp;quot;,134233614,&amp;quot;true&amp;quot;,469778129,&amp;quot;FirstParagraph&amp;quot;,335572020,&amp;quot;1&amp;quot;,469775498,&amp;quot;Body Text&amp;quot;,469778324,&amp;quot;Body Text&amp;quot;]}"&gt;The standard way to get data into a vector store looks reasonable on a whiteboard: a service reads source rows, calls an embedding API, and writes chunks back to Postgres. &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;However, some interesting &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;issues&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; often &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;occur&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; in&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;production.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1002" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="6" data-aria-level="1"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;The embedding API &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;fails &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;mid-&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;batch,&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt; and &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;there's&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;no shared checkpoint&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;STRONG&gt; &lt;/STRONG&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;showing which rows were completed. You rerun the job, and the extra API calls increases &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;cost&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1002" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="8" data-aria-level="1"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;A worker crashes after writing chunks but&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;before&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Compact"&gt;flipping the parent row's&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;processed&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Compact"&gt;flag. Now your &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;embeddings&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="Compact"&gt;are&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt; quietly &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;inconsistent,&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt; and nobody knows.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;Every one of these is the same missing primitive:&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;&lt;STRONG&gt;durable, checkpointed execution that lives where your data lives&lt;/STRONG&gt;.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;External orchestrators&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; can do it, but now &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;you're&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;operating&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; a second &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;service&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; just to feed the first one.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;AI pipelines move that logic into &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; itself. The source, the steps, the sink, and the full run history are all SQL protected by the same transactions, backups, and point-in-time &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;restore&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; your data already has. The database is already where your data &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;commits&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;. &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;It's&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;a&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; natural place for the pipeline to &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;live&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;too.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;a id="community--1-anatomy" class="lia-anchor"&gt;&lt;/a&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN class="lia-linked-item" data-ccp-parastyle="heading 2"&gt;Anatomy of an AI pipeline&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:160,&amp;quot;335559739&amp;quot;:80}"&gt; in HorizonDB&lt;/SPAN&gt;&lt;/H2&gt;
&lt;img&gt;AI Pipeline in HorizonDB, the steps are optional and can be adjusted as needed.&lt;/img&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;A pipeline has four parts:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI aria-setsize="-1" data-leveltext="%1." data-font="" data-listid="1003" data-list-defn-props="{&amp;quot;335552541&amp;quot;:0,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769242&amp;quot;:[65533,0],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;%1.&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Source&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt; where rows come from. A&lt;/SPAN&gt; &lt;EM&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;table_source&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;(...)&lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&amp;nbsp;&lt;SPAN data-ccp-parastyle="Compact"&gt;over a &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt; table, optionally with an&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;incremental_column&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Compact"&gt;so the pipeline skips rows it already processed.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI aria-setsize="-1" data-leveltext="%1." data-font="" data-listid="1003" data-list-defn-props="{&amp;quot;335552541&amp;quot;:0,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769242&amp;quot;:[65533,0],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;%1.&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;STRONG style="color: rgb(30, 30, 30);"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Steps&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;&lt;STRONG&gt; &lt;/STRONG&gt;the AI operations that transform each row, in order. Each step appends columns to the in-flight batch.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt; &lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI aria-setsize="-1" data-leveltext="%1." data-font="" data-listid="1003" data-list-defn-props="{&amp;quot;335552541&amp;quot;:0,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769242&amp;quot;:[65533,0],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;%1.&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;STRONG style="color: rgb(30, 30, 30);"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Sink&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;&lt;STRONG&gt; &lt;/STRONG&gt;where results land, ready for&amp;nbsp;use by&amp;nbsp;your AI apps or agent.&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI aria-setsize="-1" data-leveltext="%1." data-font="" data-listid="1003" data-list-defn-props="{&amp;quot;335552541&amp;quot;:0,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769242&amp;quot;:[65533,0],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;%1.&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="1" data-aria-level="1"&gt;&lt;STRONG style="color: rgb(30, 30, 30);"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Trigger&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN style="color: rgb(30, 30, 30);"&gt; &lt;/SPAN&gt;&lt;EM style="color: rgb(30, 30, 30);"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;'&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;on_change&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;'&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Compact"&gt;(run automatically when source rows change) or&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM style="color: rgb(30, 30, 30);"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;'manual'&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Compact"&gt;(run only when you call&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM style="color: rgb(30, 30, 30);"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.run&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;).&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;Those four parts give the pipeline its shape. &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;The &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;steps &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;are&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; where you define the AI work itself, using composable building blocks:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 94.0741%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Step&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;What it does&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.chunk&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Split long text into overlapping chunks&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.embed&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Generate vector embeddings&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.extract&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Pull structured fields out of text with an LLM&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.generate&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Generate text from a prompt&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp; (i.e content generation, classify, summarize and more)&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.rank&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Score documents against a query&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 23.1693%" /&gt;&lt;col style="width: 76.9095%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;STRONG style="color: rgb(30, 30, 30);"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;How &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;the&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt; pieces fit &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;together.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;&lt;STRONG&gt; &lt;/STRONG&gt;The &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;ai.*&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt; API gives you the&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt; AI&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt; pipeline shape: sources define where data comes from, steps define the AI work to perform, sinks define where results land, and triggers define when the pipeline runs. Under the covers, HorizonDB turns that definition into a durable execution graph, where each step can be checkpointed, retried, and resumed if something fails.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;335559685&amp;quot;:0,&amp;quot;335559731&amp;quot;:0,&amp;quot;335559737&amp;quot;:480,&amp;quot;335559738&amp;quot;:100,&amp;quot;335559739&amp;quot;:100}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;Built on open source&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Block Text"&gt;That durability &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;isn't&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt; magic&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;, &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;every AI pipeline compiles down to a graph that runs on&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;A href="https://github.com/microsoft/pg_durable" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;pg_durable&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;, Microsoft's open-source durable-execution engine for PostgreSQL (built on the&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;A href="https://github.com/microsoft/duroxide" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;duroxide&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Block Text"&gt;Rust runtime). The&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.*&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Block Text"&gt;API is the AI-shaped surface &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;(&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;sources, steps, sinks, triggers&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Block Text"&gt;and&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;pg_durable&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Block Text"&gt;is the general-purpose engine underneath that handles checkpointing, retries, and crash recovery. &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;So,&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt; your pipelines stand on a transparent, inspectable foundation you can read, and run on any Postgres 17&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt; &amp;amp; 18&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;. No black &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;box, no lock-i&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Block Text"&gt;n.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559685&amp;quot;:0,&amp;quot;335559731&amp;quot;:0,&amp;quot;335559737&amp;quot;:480,&amp;quot;335559738&amp;quot;:100,&amp;quot;335559739&amp;quot;:100}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;a id="community--1-use-cases" class="lia-anchor"&gt;&lt;/a&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN class="lia-linked-item" data-ccp-parastyle="heading 2"&gt;Use case 1&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;:&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt; Semantic search over &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;your d&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;ata&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:160,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;This is one of the most popular use cases. Turn a table of documents into searchable vectors, durably, and&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;keep them fresh&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;as&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; the data changes. That last part matters: in production, documents are edited, added, and &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;deleted&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; constantly, and every change needs the right chunks and embeddings updated without reprocessing the entire corpus or leaving stale vectors behind. With &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;AI &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;pipeline&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;s&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;, &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; can track those incremental updates for you. Chunk the body, embed each chunk, and land the result in a &lt;/SPAN&gt;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/horizondb/ai/vector-index-diskann" target="_blank" rel="noopener"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;DiskANN&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/horizondb/ai/vector-index-diskann" target="_blank" rel="noopener"&gt;-indexed&lt;/A&gt; table.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;-- Define the pipeline: source -&amp;gt; chunk -&amp;gt; embed -&amp;gt; sink. 
SELECT ai.create_pipeline( 
    name   =&amp;gt; 'rag_pipeline', 
    source =&amp;gt; ai.table_source(table_name =&amp;gt; 'documents'), 
    steps  =&amp;gt; ARRAY[ 
        ai.chunk(input =&amp;gt; 'content', chunk_size =&amp;gt; 512, overlap =&amp;gt; 64), 
        ai.embed(model =&amp;gt; 'default-embedding', input =&amp;gt; 'chunk_text', dimensions =&amp;gt; 1536) 
    ], 
    trigger =&amp;gt; 'on_change',   -- re-embed automatically as rows change 
    sink    =&amp;gt; ai.table_sink('rag_pipeline_output') 
); 

-- Run it
SELECT ai.run('rag_pipeline'); 
 
-- Search your data 
SELECT chunk_text, embedding &amp;lt;=&amp;gt; azure_openai.create_embeddings('text-embedding-3-small', 'how does vector search work?')::vector AS distance 
FROM rag_pipeline_output
ORDER BY distance 
LIMIT 3; &lt;/LI-CODE&gt;
&lt;P&gt;📘&amp;nbsp;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/horizondb/ai/ai-pipelines" target="_blank" rel="noopener"&gt;Read more details in the AI Pipelines documentation&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;That's&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; the entire ingestion &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;layer;&lt;/SPAN&gt;&amp;nbsp;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;chunking, embedding, checkpointing, retries, and sink writes in one definition. Because&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;trigger =&amp;gt; '&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;on_change&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;'&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;&lt;EM&gt;,&lt;/EM&gt; the pipeline &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;update&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;s &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;embeddings whenever source rows change, processing only what is new or &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;modified&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; instead of redoing the whole corpus. Your vectors stay &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;in sync&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; with your data, and your ingestion work stays efficient as the dataset grows. Point a query at the &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/horizondb/ai/vector-index-diskann" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;DiskANN&lt;/SPAN&gt; &lt;SPAN data-ccp-charstyle="Hyperlink"&gt;index&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; and &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;you've&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; got production semantic search without a single line of application glue.&lt;/SPAN&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;BR /&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;That's&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; the whole loop: define, run, inspect. The embedding service you were about to build the queue, the workers, the retry logic, the checkpoint table, the 2 a.m. &lt;SPAN data-ccp-parastyle="Body Text"&gt;p&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;roduction incident&lt;/SPAN&gt; doesn't happens.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;Why &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;it's&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; better than &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;an external &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;service:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;a failure in&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.embed&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;EM&gt; &lt;/EM&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;never re-runs&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;EM&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.chunk&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;(&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;)&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;,&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;each step is a durable node. If the database restarts mid-run, it resumes from the last checkpointed batch, not row zer&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;o.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Use case 2&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;:&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt; Turn unstructured text into structured metadata &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:160,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;Support tickets, contracts, product reviews&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;, research&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;papers&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; are&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; full of structure &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;that's&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; locked inside &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;unstructured &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;document&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;s&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;.&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.extract&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;EM&gt; &lt;/EM&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;pulls named fields out of text and merges them into the&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;metadata&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;JSONB column, so you can filter and &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;aggregate on&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; thing&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;s an LLM r&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;ead for you.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;SELECT ai.create_pipeline( 
    name   =&amp;gt; 'extraction_pipeline', 
    source =&amp;gt; ai.table_source(table_name =&amp;gt; 'documents'), 
    steps  =&amp;gt; ARRAY[ 
        ai.chunk(input =&amp;gt; 'content'), 
        ai.extract( 
            input =&amp;gt; 'chunk_text', 
            data  =&amp;gt; ARRAY['topics: string - the main topics discussed', 
                           'entities: string - named people, products, or places'] 
             model =&amp;gt; 'my-gpt' -- optional, the default model when AI model management is activate 
        ) 
    ], 
    sink =&amp;gt; ai.table_sink('extraction_pipeline_output') 
); 
 
SELECT ai.run('extraction_pipeline'); 
 
-- Now query the structured fields the LLM extracted: 
SELECT doc_id, metadata-&amp;gt;'topics' AS topics, metadata-&amp;gt;'entities' AS entities 
FROM extraction_pipeline_output; &lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;📘&amp;nbsp;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/horizondb/ai/ai-pipelines" target="_blank" rel="noopener"&gt;Read more details in the AI Pipelines documentation&lt;/A&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;You describe each field as a&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;label: description&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;string&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; in the&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;EM&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;ai.extract&lt;/SPAN&gt;&lt;/EM&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; step&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;, and &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; does the rest durably, in bulk, with the same retry-and-resume guarantees.&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;Each field is a label, either a bare name like &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;product&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;, or the detailed form &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;&lt;EM&gt;name: type - description&lt;/EM&gt; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;(for example `sentiment: number - sentiment score from 1 to 5`). &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; does the rest, durably, in bulk, with the same retry-and-resume guarantees.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Use case 3&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;:&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt; Summarize and rewrite content at scale &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:160,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;ai.generate&lt;/SPAN&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;()&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;EM&gt; &lt;/EM&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;runs an LLM prompt against every row&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;,&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; perfect for bulk summarization, classification, tone normalization, or generating titles. Because &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;it's&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; a pipeline, "&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;summarize&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; 4 million documents" becomes a job that survives restarts instead of a script you &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;have to&lt;/SPAN&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;monitor&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; overnight.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;SELECT ai.create_pipeline( 
    name   =&amp;gt; 'summary_pipeline', 
    source =&amp;gt; ai.table_source(table_name =&amp;gt; 'documents'), 
    steps  =&amp;gt; ARRAY[ 
        ai.chunk(input =&amp;gt; 'content'), 
        ai.generate( 
            input =&amp;gt; 'chunk_text', 
            system_prompt =&amp;gt; 'Create a concise summary in 50 words or fewer.'  
            model =&amp;gt; 'my-gpt' -- optional, the default model when AI model management is activate 
        ) 
    ], 
    sink =&amp;gt; ai.table_sink('generation_pipeline_output') 
); 
 
SELECT ai.run('summary_pipeline'); 
 
-- Now query the generated text: 
SELECT doc_id, left(generated_text, 100) AS summary_preview 
FROM generation_pipeline_output 
WHERE generated_text IS NOT NULL 
LIMIT 5; &lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN style="color: rgb(30, 30, 30);"&gt;📘 &lt;/SPAN&gt;&lt;A class="lia-external-url" style="font-style: normal; font-weight: 400; background-color: rgb(255, 255, 255);" href="https://learn.microsoft.com/en-us/azure/horizondb/ai/ai-pipelines" target="_blank" rel="noopener"&gt;Read more details in the AI Pipelines documentation&lt;/A&gt;&lt;SPAN style="color: rgb(30, 30, 30);"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;Swap the&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;system_prompt&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;and the same shape becomes a classifier ("&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;Label&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; this ticket as billing, bug, or feature request"), a translator, or a headline generator. The instruction goes in&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;system_prompt&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;; the result lands in&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;generated_text&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;Use case &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;4&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt;:&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="heading 2"&gt; Keep embeddings fresh, and re-embed cleanly when the model changes&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:160,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;This is where AI pipelines become especially useful. In a real AI app, two things change constantly: &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;your data&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; and &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;&lt;STRONG&gt;your model&lt;/STRONG&gt;.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; AI pipelines are designed to handle both changes directly.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;Your data changes.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;Set&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;incremental_column&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;and an&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;on_change&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;trigger, and the pipeline only embeds&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;new or changed&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="Body Text"&gt;rows, automatically, forever, until you pause or drop it.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;SELECT ai.create_pipeline( 
    name   =&amp;gt; 'rag_pipeline', 
    source =&amp;gt; ai.table_source( 
        table_name =&amp;gt; 'documents', 
        incremental_column =&amp;gt; 'updated_at'   -- only process what changed 
    ), 
    steps  =&amp;gt; ARRAY[ 
        ai.chunk(input =&amp;gt; 'content'), 
        ai.embed(model =&amp;gt; 'default-embedding', input =&amp;gt; 'chunk_text', dimensions =&amp;gt; 1536) 
    ], 
    trigger =&amp;gt; 'on_change', 
    sink    =&amp;gt; ai.table_sink('rag_pipeline_output') 
); &lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;Your model changes.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;Bump the model or the dimensions, then run a single, resumable backfill&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;,&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt; no migration script, no babysitting:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;TRUNCATE rag_pipeline_output;  
SELECT ai.backfill('rag_pipeline'); &lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;📘&amp;nbsp;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/horizondb/ai/ai-pipelines" target="_blank" rel="noopener"&gt;Read more details in the AI Pipelines documentation&lt;/A&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;The backfill runs as one durable instance. If the database restarts mid-backfill, it picks up from the last checkpointed batch instead of starting over.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;The painful "re-embed everything" migration becomes a one-liner you can actually trust.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="2"&gt;&lt;a id="community--1-vs-code" class="lia-anchor"&gt;&lt;/a&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN class="lia-linked-item" data-ccp-parastyle="heading 2"&gt;Watch your pipelines run as live graphs in VS Code&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:160,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;A pipeline you can&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;see&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;is a pipeline you can trust. Install the&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/horizondb/development/vs-code-extension/vs-code-overview" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;PostgreSQL extension for VS Code&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;, connect to &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;, then right-click your database and open&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;Pipelines &amp;amp; Workflows → AI Pipelines&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;img&gt;AI Pipelines in HorizonDB&lt;/img&gt;
&lt;P&gt;&lt;SPAN data-ccp-props="{&amp;quot;335551550&amp;quot;:2,&amp;quot;335551620&amp;quot;:2,&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;Select any run and the center pane&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;renders&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt; the execution as a&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;color-coded graph&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Body Text"&gt;:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1004" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="9" data-aria-level="1"&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Blue 🔵 :&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;source and sink (where data enters and exits)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1004" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="9" data-aria-level="1"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;&lt;STRONG&gt;Green 🟢 :&lt;/STRONG&gt; &lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;processing steps (chunk, embed, extract, generate, rank)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt; &lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1004" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="9" data-aria-level="1"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;&lt;STRONG&gt;Pink 🟣&amp;nbsp;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;&lt;STRONG&gt;:&lt;/STRONG&gt; &lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;external model and service calls&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;335559738&amp;quot;:36,&amp;quot;335559739&amp;quot;:36}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;For each run you can read the&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;status&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;(&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;completed&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;,&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;running&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;,&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-charstyle="Verbatim Char"&gt;failed&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;), the&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;run ID&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;STRONG&gt; &lt;/STRONG&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;for traceability,&lt;/SPAN&gt; &lt;/SPAN&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;start time and duration&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;SPAN data-contrast="auto"&gt; &lt;SPAN data-ccp-parastyle="First Paragraph"&gt;for performance, and a link back to the pipeline definition. When a run fails, open the graph and jump straight to the step where execution stopped&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;, &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="First Paragraph"&gt;no log spelunking.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;335559738&amp;quot;:180,&amp;quot;335559739&amp;quot;:180}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 aria-level="4"&gt;&lt;a id="community--1-start-now" class="lia-anchor"&gt;&lt;/a&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN class="lia-linked-item" data-ccp-parastyle="heading 4"&gt;Get Started: Try It Now&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:600,&amp;quot;335559739&amp;quot;:300}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;We have a few demoes of AI pipelines in action:&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:150}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 92.5%; height: 194px; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr style="height: 38.8px;"&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="none"&gt;Resource&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="none"&gt;Link&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr style="height: 38.8px;"&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Microsoft Build AI Pipeline Demo&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;201341983&amp;quot;:0,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559685&amp;quot;:0,&amp;quot;335559737&amp;quot;:0,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:0,&amp;quot;335559740&amp;quot;:240}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;A class="lia-external-url" href="https://www.youtube.com/watch?v=_9JC2s7G3l8" target="_blank" rel="noopener"&gt;&lt;SPAN data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;Simplify app dev with cloud-native PostgreSQL in Azure HorizonDB | DEM364&lt;/SPAN&gt;&lt;/A&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr style="height: 38.8px;"&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Microsoft Build AI Pipeline GitHub&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;201341983&amp;quot;:0,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335559740&amp;quot;:240}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;A class="lia-external-url" href="https://github.com/microsoft/Build26-DEM364-simplify-app-dev-with-cloud-native-postgresql-in-azure-horizondb" target="_blank" rel="noopener"&gt;AI Pipelines Demo GitHub Repo | DEM364&lt;/A&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr style="height: 38.8px;"&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Microsoft Mechanic Demo&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;201341983&amp;quot;:0,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559685&amp;quot;:0,&amp;quot;335559737&amp;quot;:0,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:0,&amp;quot;335559740&amp;quot;:240}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;SPAN data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:0}"&gt;&amp;nbsp;&lt;A class="lia-external-url" href="https://youtu.be/EzEPFMJuvrk?si=3dofK1sq3g1upHt5&amp;amp;t=504" target="_blank" rel="noopener"&gt;AI Pipeline Demo on Microsoft Mechanic&lt;/A&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr style="height: 38.8px;"&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;Documentation&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;201341983&amp;quot;:0,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335559740&amp;quot;:240}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td style="height: 38.8px;"&gt;
&lt;P&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN data-contrast="none"&gt;&lt;A href="http://learn.microsoft.com/azure/horizondb/ai/ai-pipelines&amp;nbsp;" target="_blank" rel="noopener"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;AI pipelines on &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;HorizonDB&lt;/SPAN&gt;&lt;/A&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 27.4417%" /&gt;&lt;col style="width: 72.5383%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;SPAN data-contrast="none"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="none"&gt;Enabling AI pipelines takes minutes: enable to &lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="none"&gt;&lt;EM&gt;azure_ai, pg_durable, vecto&lt;/EM&gt;r &lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="none"&gt;and &lt;/SPAN&gt;&lt;EM&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="none"&gt;pg_diskann&lt;/SPAN&gt;&lt;/EM&gt;&lt;SPAN style="color: rgb(30, 30, 30);"&gt; &lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="auto"&gt;extensions and you can get started.&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:150}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;-- On Azure HorizonDB — the extensions are built in. 
CREATE EXTENSION IF NOT EXISTS pg_durable; 
CREATE EXTENSION IF NOT EXISTS azure_ai; 
CREATE EXTENSION IF NOT EXISTS vector; 
CREATE EXTENSION IF NOT EXISTS pg_diskann; &lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-contrast="none"&gt;That's it, your PostgreSQL database can now run AI pipelines&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30);" data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:150}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN class="lia-linked-item" data-ccp-props="{&amp;quot;134233117&amp;quot;:false,&amp;quot;134233118&amp;quot;:false,&amp;quot;335551550&amp;quot;:1,&amp;quot;335551620&amp;quot;:1,&amp;quot;335557856&amp;quot;:16777215,&amp;quot;335559738&amp;quot;:0,&amp;quot;335559739&amp;quot;:150}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;a id="community--1-learn" class="lia-anchor"&gt;&lt;/a&gt;&lt;SPAN style="color: rgb(30, 30, 30); font-size: 32px;" data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="heading 3"&gt;Learn more&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="color: rgb(30, 30, 30); font-size: 32px;" data-ccp-props="{&amp;quot;134245418&amp;quot;:true,&amp;quot;134245529&amp;quot;:true,&amp;quot;335559738&amp;quot;:160,&amp;quot;335559739&amp;quot;:80}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1005" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="12" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;&lt;A class="lia-external-url" href="http://learn.microsoft.com/azure/horizondb/ai/ai-pipelines&amp;nbsp;" target="_blank" rel="noopener"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;MS Learn AI pipelines on &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;HorizonDB&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;:&lt;/SPAN&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1005" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="13" data-aria-level="1"&gt;&lt;A class="lia-external-url" href="http://learn.microsoft.com/azure/horizondb&amp;nbsp;" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;Azure &lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;HorizonDB&lt;/SPAN&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt; Preview&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1005" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="14" data-aria-level="1"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;A class="lia-external-url" href="http://github.com/microsoft/pg_durable" target="_blank" rel="noopener"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;pg_durable&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;&lt;A class="lia-external-url" href="http://github.com/microsoft/pg_durable" target="_blank" rel="noopener"&gt; on GitHub (open source)&lt;/A&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1005" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="15" data-aria-level="1"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;&lt;A class="lia-external-url" href="http://learn.microsoft.com/azure/horizondb/development/durable-functions" target="_blank" rel="noopener"&gt;MS Learn Durable Functions on HorizonDB&lt;/A&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1005" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="16" data-aria-level="1"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;A class="lia-external-url" href="http://learn.microsoft.com/azure/horizondb/ai/vector-index-diskann" target="_blank" rel="noopener"&gt;Scalable vector search with DiskANN&lt;/A&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI aria-setsize="-1" data-leveltext="" data-font="Symbol" data-listid="1005" data-list-defn-props="{&amp;quot;335551671&amp;quot;:0,&amp;quot;335552541&amp;quot;:1,&amp;quot;335559685&amp;quot;:720,&amp;quot;335559991&amp;quot;:360,&amp;quot;469769226&amp;quot;:&amp;quot;Symbol&amp;quot;,&amp;quot;469769242&amp;quot;:[8226],&amp;quot;469777803&amp;quot;:&amp;quot;left&amp;quot;,&amp;quot;469777804&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;469777815&amp;quot;:&amp;quot;multilevel&amp;quot;}" data-aria-posinset="17" data-aria-level="1"&gt;&lt;SPAN data-contrast="auto"&gt;&lt;SPAN data-ccp-parastyle="Compact"&gt;&lt;A class="lia-external-url" href="http://learn.microsoft.com/azure/horizondb/development/vs-code-extension" target="_blank" rel="noopener"&gt;PostgreSQL extension for VS Code&lt;/A&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Thu, 02 Jul 2026 16:52:43 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/microsoft-blog-for-postgresql/from-rag-to-agents-build-ai-pipelines-inside-azure-horizondb/ba-p/4532696</guid>
      <dc:creator>abeomor-msft</dc:creator>
      <dc:date>2026-07-02T16:52:43Z</dc:date>
    </item>
    <item>
      <title>Understanding % Characters in Azure Blob File Names Using SQL OPENROWSET (BULK)</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/understanding-characters-in-azure-blob-file-names-using-sql/ba-p/4532593</link>
      <description>&lt;MAIN class="page"&gt;&lt;HEADER&gt;&lt;/HEADER&gt;
&lt;SECTION class="callout"&gt;&lt;/SECTION&gt;
&lt;SECTION class="callout warning"&gt;&lt;/SECTION&gt;
&lt;H2&gt;Why the % character is different&lt;/H2&gt;
&lt;P&gt;In URL percent-encoding, the &lt;CODE&gt;%&lt;/CODE&gt; character starts an encoded sequence. For example:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;CODE&gt;%20&lt;/CODE&gt; represents a space.&lt;/LI&gt;
&lt;LI&gt;&lt;CODE&gt;%25&lt;/CODE&gt; represents a literal &lt;CODE&gt;%&lt;/CODE&gt; character.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Because of this, file names that contain a literal &lt;CODE&gt;%&lt;/CODE&gt; can behave differently from file names containing characters such as &lt;CODE&gt;#&lt;/CODE&gt;, &lt;CODE&gt;&amp;amp;&lt;/CODE&gt;, &lt;CODE&gt;+&lt;/CODE&gt;, &lt;CODE&gt;;&lt;/CODE&gt;, &lt;CODE&gt;=&lt;/CODE&gt;, or &lt;CODE&gt;@&lt;/CODE&gt;, depending on how the path is processed before blob lookup.&lt;/P&gt;
&lt;H2&gt;Observed symptom&lt;/H2&gt;
&lt;P&gt;The customer reported an import failure for a file name similar to:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE&gt;Company Data - Company Data - éêçëЮй_%25$£#.csv&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The error message started at the &lt;CODE&gt;%&lt;/CODE&gt; sequence instead of showing the full file name:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE&gt;Invalid format specification: '%25$#.45752234198410731.csv.processed' cannot be opened&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;This was a useful clue because the reported path appeared to begin at the first &lt;CODE&gt;%&lt;/CODE&gt; sequence, while the preceding portion of the file name was not present in the error text.&lt;/P&gt;
&lt;H2&gt;Test setup&lt;/H2&gt;
&lt;P&gt;The examples below use an external data source pointing to Azure Blob Storage. Replace all placeholders with values from the test environment. Sensitive values such as storage account names, container names, credential names, and SAS tokens should be masked before sharing.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE&gt;CREATE DATABASE SCOPED CREDENTIAL [&amp;lt;credential_name&amp;gt;]
WITH IDENTITY = 'SHARED ACCESS SIGNATURE',
SECRET = '&amp;lt;SAS_TOKEN&amp;gt;';

CREATE EXTERNAL DATA SOURCE [MyBlobStorageSource]
WITH (
    TYPE = BLOB_STORAGE,
    LOCATION = 'https://&amp;lt;storage_account&amp;gt;.blob.core.windows.net/&amp;lt;container&amp;gt;',
    CREDENTIAL = [&amp;lt;credential_name&amp;gt;]
);&lt;/CODE&gt;&lt;/PRE&gt;
&lt;H2&gt;Reproduction results&lt;/H2&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Scenario&lt;/th&gt;&lt;th&gt;Blob name / character&lt;/th&gt;&lt;th&gt;OPENROWSET path&lt;/th&gt;&lt;th&gt;Result&lt;/th&gt;&lt;th&gt;Observation&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Space in file name&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;Test File.pdf&lt;/CODE&gt;&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;BULK 'Test File.pdf'&lt;/CODE&gt;&lt;/td&gt;&lt;td class="result-ok"&gt;Succeeded&lt;/td&gt;&lt;td&gt;Spaces alone did not reproduce the failure.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Literal &lt;CODE&gt;%&lt;/CODE&gt; in file name&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;Test%File.pdf&lt;/CODE&gt;&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;BULK 'Test%File.pdf'&lt;/CODE&gt;&lt;/td&gt;&lt;td class="result-fail"&gt;Failed&lt;/td&gt;&lt;td&gt;The file could not be opened when &lt;CODE&gt;%&lt;/CODE&gt; was passed literally.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Literal &lt;CODE&gt;%&lt;/CODE&gt; encoded as &lt;CODE&gt;%25&lt;/CODE&gt;&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;Test%File.pdf&lt;/CODE&gt;&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;BULK 'Test%25File.pdf'&lt;/CODE&gt;&lt;/td&gt;&lt;td class="result-ok"&gt;Succeeded&lt;/td&gt;&lt;td&gt;Encoding &lt;CODE&gt;%&lt;/CODE&gt; as &lt;CODE&gt;%25&lt;/CODE&gt; allowed the same blob to be accessed.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Literal string &lt;CODE&gt;%25&lt;/CODE&gt; in file name&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;Test%25File.pdf&lt;/CODE&gt;&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;BULK 'Test%2525File.pdf'&lt;/CODE&gt;&lt;/td&gt;&lt;td class="result-ok"&gt;Succeeded&lt;/td&gt;&lt;td&gt;The observed result is consistent with one percent-decoding pass during path resolution.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Other special characters&lt;/td&gt;&lt;td&gt;&lt;CODE&gt;#&lt;/CODE&gt;, &lt;CODE&gt;&amp;amp;&lt;/CODE&gt;, &lt;CODE&gt;+&lt;/CODE&gt;, &lt;CODE&gt;;&lt;/CODE&gt;, &lt;CODE&gt;=&lt;/CODE&gt;, &lt;CODE&gt;@&lt;/CODE&gt;&lt;/td&gt;&lt;td&gt;Tested individually&lt;/td&gt;&lt;td class="result-ok"&gt;Succeeded&lt;/td&gt;&lt;td&gt;These characters did not reproduce the same behavior in the tests performed.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 20.00%" /&gt;&lt;col style="width: 20.00%" /&gt;&lt;col style="width: 20.00%" /&gt;&lt;col style="width: 20.00%" /&gt;&lt;col style="width: 20.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2&gt;Commands used for testing&lt;/H2&gt;
&lt;H3&gt;1. Space in the file name&lt;/H3&gt;
&lt;PRE&gt;&lt;CODE&gt;INSERT INTO testfiles(pdfData)
SELECT BulkColumn
FROM OPENROWSET(
    BULK 'Test File.pdf',
    DATA_SOURCE = 'MyBlobStorageSource',
    SINGLE_BLOB
) AS PdfFile;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;H3&gt;2. Literal % in the file name&lt;/H3&gt;
&lt;PRE&gt;&lt;CODE&gt;INSERT INTO testfiles(pdfData)
SELECT BulkColumn
FROM OPENROWSET(
    BULK 'Test%File.pdf',
    DATA_SOURCE = 'MyBlobStorageSource',
    SINGLE_BLOB
) AS PdfFile;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Observed error:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE&gt;Msg 13822, Level 16, State 1
File 'Test%File.pdf' cannot be opened because it does not exist or it is used by another process.&lt;/CODE&gt;&lt;/PRE&gt;
&lt;H3&gt;3. URL-encoded % character&lt;/H3&gt;
&lt;PRE&gt;&lt;CODE&gt;INSERT INTO testfiles(pdfData)
SELECT BulkColumn
FROM OPENROWSET(
    BULK 'Test%25File.pdf',
    DATA_SOURCE = 'MyBlobStorageSource',
    SINGLE_BLOB
) AS PdfFile;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;H3&gt;4. Literal %25 in the blob name&lt;/H3&gt;
&lt;PRE&gt;&lt;CODE&gt;INSERT INTO testfiles(pdfData)
SELECT BulkColumn
FROM OPENROWSET(
    BULK 'Test%2525File.pdf',
    DATA_SOURCE = 'MyBlobStorageSource',
    SINGLE_BLOB
) AS PdfFile;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;H2&gt;Interpretation&lt;/H2&gt;
&lt;P&gt;The tests suggest that the path provided to &lt;CODE&gt;OPENROWSET (BULK)&lt;/CODE&gt; is processed in a way that is consistent with URL-style percent-encoding rules.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;A literal &lt;CODE&gt;%&lt;/CODE&gt; character in a blob name may need to be referenced as &lt;CODE&gt;%25&lt;/CODE&gt; in the &lt;CODE&gt;BULK&lt;/CODE&gt; path.&lt;/LI&gt;
&lt;LI&gt;If the actual blob name contains the literal characters &lt;CODE&gt;%25&lt;/CODE&gt;, the &lt;CODE&gt;BULK&lt;/CODE&gt; path may need to use &lt;CODE&gt;%2525&lt;/CODE&gt; so that the observed path-resolution behavior resolves it back to &lt;CODE&gt;%25&lt;/CODE&gt;.&lt;/LI&gt;
&lt;LI&gt;Spaces and the tested characters &lt;CODE&gt;#&lt;/CODE&gt;, &lt;CODE&gt;&amp;amp;&lt;/CODE&gt;, &lt;CODE&gt;+&lt;/CODE&gt;, &lt;CODE&gt;;&lt;/CODE&gt;, &lt;CODE&gt;=&lt;/CODE&gt;, and &lt;CODE&gt;@&lt;/CODE&gt; did not reproduce the same behavior in these tests.&lt;/LI&gt;
&lt;LI&gt;The customer error beginning at the &lt;CODE&gt;%25&lt;/CODE&gt; sequence is consistent with the file name being interpreted or transformed when the &lt;CODE&gt;%&lt;/CODE&gt; sequence is encountered.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Practical guidance&lt;/H2&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table class="guidance-table" border="1" style="width: 97.2222%; height: 410.985px; border-width: 1px;"&gt;&lt;thead&gt;&lt;tr style="height: 35px;"&gt;&lt;th style="height: 35px;"&gt;Recommended handling for &lt;CODE&gt;%&lt;/CODE&gt; characters in blob names&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr style="height: 91.797px;"&gt;&lt;td style="height: 91.797px;"&gt;
&lt;P&gt;&lt;U&gt;Main recommendation&lt;/U&gt;&lt;/P&gt;
&lt;P&gt;Avoid passing blob names containing a literal % directly to OPENROWSET (BULK).&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr style="height: 91.1719px;"&gt;&lt;td style="height: 91.1719px;"&gt;
&lt;P&gt;&lt;U&gt;When the blob name contains &lt;CODE&gt;%&lt;/CODE&gt;&lt;/U&gt;&lt;/P&gt;
&lt;P&gt;URL-encode the character before generating the BULK path. For example, test referencing a literal % as %25.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr style="height: 97.1719px;"&gt;&lt;td style="height: 97.1719px;"&gt;
&lt;P&gt;&lt;U&gt;When the blob name contains literal &lt;CODE&gt;%25&lt;/CODE&gt;&lt;/U&gt;&lt;/P&gt;
&lt;P&gt;Test whether the path needs to use %2525. In the observed tests, this was consistent with one percent-decoding pass during path resolution.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr style="height: 95.8438px;"&gt;&lt;td style="height: 95.8438px;"&gt;
&lt;P&gt;&lt;U&gt;Application or stored procedure checks&lt;/U&gt;&lt;/P&gt;
&lt;P&gt;Confirm the import process is not decoding, encoding, or re-encoding the file name multiple times before invoking OPENROWSET.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 100.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2&gt;Optional PowerShell test using Invoke-Sqlcmd&lt;/H2&gt;
&lt;P&gt;If testing outside SSMS, &lt;CODE&gt;Invoke-Sqlcmd&lt;/CODE&gt; can be used with an Entra ID access token. The SAS token is not needed in the command if the database scoped credential already exists in SQL.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE&gt;Connect-AzAccount

$query = @"
INSERT INTO testfiles(pdfData)
SELECT BulkColumn
FROM OPENROWSET(
    BULK 'Test%25File.pdf',
    DATA_SOURCE = 'MyBlobStorageSource',
    SINGLE_BLOB
) AS PdfFile;
"@

Invoke-Sqlcmd `
    -ServerInstance '&amp;lt;managed-instance-fqdn&amp;gt;,3342' `
    -Database '&amp;lt;database_name&amp;gt;' `
    -AccessToken (Get-AzAccessToken -ResourceUrl 'https://database.windows.net/').Token `
    -Query $query `
    -Verbose `
    -ErrorAction Stop&lt;/CODE&gt;&lt;/PRE&gt;
&lt;H2&gt;Conclusion&lt;/H2&gt;
&lt;P&gt;The controlled tests indicate that the import behavior is related to how &lt;CODE&gt;%&lt;/CODE&gt; is handled in the file path supplied to SQL &lt;CODE&gt;OPENROWSET (BULK)&lt;/CODE&gt;. The observed results are consistent with percent-decoding during path resolution: &lt;CODE&gt;%25&lt;/CODE&gt; behaves like a literal &lt;CODE&gt;%&lt;/CODE&gt;, and &lt;CODE&gt;%2525&lt;/CODE&gt; behaves like a literal &lt;CODE&gt;%25&lt;/CODE&gt;.&lt;/P&gt;
&lt;P&gt;Based on these tests, this should not be described as a general limitation with spaces, Unicode characters, or common special characters in blob names. The evidence points specifically to handling of the &lt;CODE&gt;%&lt;/CODE&gt; character and percent-encoded sequences in the path passed to &lt;CODE&gt;OPENROWSET (BULK)&lt;/CODE&gt;.&lt;/P&gt;
&lt;/MAIN&gt;</description>
      <pubDate>Thu, 02 Jul 2026 16:22:14 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/understanding-characters-in-azure-blob-file-names-using-sql/ba-p/4532593</guid>
      <dc:creator>Thamires_Lemes</dc:creator>
      <dc:date>2026-07-02T16:22:14Z</dc:date>
    </item>
    <item>
      <title>3 Reasons Enterprise SQL Server Migrations Slow Down - and How to Avoid Them</title>
      <link>https://techcommunity.microsoft.com/t5/azure-sql-blog/3-reasons-enterprise-sql-server-migrations-slow-down-and-how-to/ba-p/4532209</link>
      <description>&lt;H2&gt;Summary&lt;/H2&gt;
&lt;P&gt;Many of Enterprises around the globe have relied on &lt;A class="lia-external-url" href="https://www.microsoft.com/en-us/sql-server" target="_blank" rel="noopener"&gt;SQL Server&lt;/A&gt; for over 3 decades to run their mission critical business applications. Their &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/sql/sql-server/?view=sql-server-ver17" target="_blank" rel="noopener"&gt;SQL Server&lt;/A&gt; estates face pressure from downtime risk, cost volatility, end of support timelines and modernization demands. As these customers get ready to modernize their data to use the latest capabilities of A.I and cloud native application trends, they want to migrate and modernize their SQL Servers to use &lt;A class="lia-external-url" href="https://azure.microsoft.com/en-us/products/azure-sql" target="_blank" rel="noopener"&gt;Azure SQL&lt;/A&gt; with a &lt;A class="lia-external-url" href="https://azure.microsoft.com/en-us/solutions/migration" target="_blank" rel="noopener"&gt;modernization strategy&lt;/A&gt; built on confidence of customer success. Enterprise migrations rarely fail because of migration tools.&lt;/P&gt;
&lt;P&gt;They slow down because organizations struggle to answer three questions:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;How much downtime can we tolerate?&lt;/LI&gt;
&lt;LI&gt;What will it cost after migration?&lt;/LI&gt;
&lt;LI&gt;Are we choosing the right target platform?&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;The organizations that answer these questions early move faster and with less risk. For the DB Administrators, Data architects, application architect and cloud-cost decision makers there are important technical considerations before, during and after data modernization to avoid long term costs and operational concerns. The Microsoft SQL Team has helped many customers modernize their SQL. We discuss important guidelines that can help resolve the 3 major concerns that block or slow &lt;A class="lia-external-url" href="https://azure.microsoft.com/en-us/solutions/azure-accelerate/databases" target="_blank" rel="noopener"&gt;SQL Server migration and modernization&lt;/A&gt; in Enterprises. This is covered in the &lt;A class="lia-external-url" href="https://youtu.be/daydaG7k4oE?si=76rNQHJC5Br5MjQq" target="_blank" rel="noopener"&gt;episode &lt;/A&gt;of DataExposed for which this companion blog goes into the details.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;div data-video-id="https://youtu.be/daydaG7k4oE?si=76rNQHJC5Br5MjQq/1782837514385" data-video-remote-vid="https://youtu.be/daydaG7k4oE?si=76rNQHJC5Br5MjQq/1782837514385" class="lia-video-container lia-media-is-center lia-media-size-large"&gt;&lt;iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FdaydaG7k4oE%3Ffeature%3Doembed&amp;amp;display_name=YouTube&amp;amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdaydaG7k4oE&amp;amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FdaydaG7k4oE%2Fhqdefault.jpg&amp;amp;type=text%2Fhtml&amp;amp;schema=youtube" allowfullscreen="" style="max-width: 100%"&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;H2&gt;What are important triggers that cause customers and partners to consider &amp;nbsp;SQL modernization?&lt;/H2&gt;
&lt;P&gt;There are many business triggers that force Enterprises to migrate their data to public cloud. As SQL Server 2012 to SQL Server 2016 are already in the end of support stage of their lifecycle, customers need to upgrade SQL Server in place or migrate to AzureSQL. Due to cyber security threats, customers are feeling more vulnerable to attackers. Moving their data into a secure environment is essential for protecting not just their data but their business. Customers are reporting the need to free up IT dollars to invest into other parts of the business that may need it more. These may be anything from datacenter contract expirations, need for Hardware refreshes to software license renewals. As the business grows or becomes cyclical, there is surge in demand. Capacity constraints become a barrier for such expansions. These are triggers that cause them to rethink their data modernization strategy. Data modernization and moving the data to a elastic, scalable, secure and resilient data platform such as Azure SQL, becomes essential.&lt;/P&gt;
&lt;H2&gt;The Three Migration Blockers&lt;/H2&gt;
&lt;P&gt;However, data modernization and migration is not without any risk. Based on our customers experience, here are three key reasons that we have commonly encountered that halt or slow down SQL modernization.&lt;/P&gt;
&lt;H3&gt;1. Downtime Risk&lt;/H3&gt;
&lt;P&gt;Business stakeholders often require strict service level commitments before authorizing production cutovers. Even when migrations are technically feasible, organizations may delay projects if they believe downtime windows could impact revenue, customer experience, or regulatory obligations. Most customers are still offered offline migration paths which can take hours to days, even though zero-downtime migrations are possible which take seconds to minutes.&lt;/P&gt;
&lt;H3&gt;2. Cost uncertainty&lt;/H3&gt;
&lt;P&gt;Many modernization projects are approved based on expected cost savings. However, if infrastructure sizing, licensing assumptions, storage consumption, or disaster recovery requirements are not evaluated properly, the actual operational cost can exceed initial expectations.&lt;/P&gt;
&lt;P&gt;Cost uncertainty often slows executive approval processes and extends migration timelines.&lt;/P&gt;
&lt;H3&gt;3. Compatibility and Feature Fit&lt;/H3&gt;
&lt;P&gt;When migrating SQL Server, Azure SQL has &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/azure-sql-iaas-vs-paas-what-is-overview?view=azuresql" target="_blank" rel="noopener"&gt;several deployment offerings&lt;/A&gt; from IaaS to PaaS. These include &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/virtual-machines/windows/doc-changes-updates-release-notes-whats-new?view=azuresql" target="_blank" rel="noopener"&gt;SQL Server on Azure VM&lt;/A&gt;, &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/doc-changes-updates-release-notes-whats-new?view=azuresql" target="_blank" rel="noopener"&gt;Azure SQL Managed Instance&lt;/A&gt;, &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/database/doc-changes-updates-release-notes-whats-new?view=azuresql" target="_blank" rel="noopener"&gt;Azure SQL DB&lt;/A&gt; Hyperscale and Azure SQL in Microsoft Fabric. Many customers maybe using SQL Server features like Cross-database queries, CLR, SSIS, SQL Agent, and linked servers. They make a safe decision to lift and shift migrate to SQL Server on Azure VMs IaaS instead of modernizing to a PaaS service like Azure SQL Managed Instance. However, in the process, they lose the opportunity to use the PaaS capabilities, manageability and AI/Fabric capabilities in Azure by making this choice. Enterprise Architects, Application Architects, Database developers and DB Administrators have to make the &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/azure-sql-decision-tree?view=azuresql" target="_blank" rel="noopener"&gt;right choice&lt;/A&gt; taking both development as well as operational costs and compatibility when they make their SQL modernization decisions.&lt;/P&gt;
&lt;P&gt;Here are best practices some of the biggest and successful SQL migrations have used to make the migration and modernization journey with confidence.&amp;nbsp; While we cannot disclose specific customer names, these guidelines are based on helping many large to small Enterprise customers.&lt;/P&gt;
&lt;H2&gt;Azure SQL Managed Instance as the Resiliency Anchor&lt;/H2&gt;
&lt;P&gt;Azure SQL Managed Instance is often the platform that helps organizations overcome all three concerns simultaneously because it combines near-full SQL Server compatibility with platform-as-a-service benefits.&lt;/P&gt;
&lt;P&gt;&lt;A class="lia-internal-link lia-internal-url lia-internal-url-content-type-blog" href="https://techcommunity.microsoft.com/blog/azuresqlblog/generally-available-azure-sql-managed-instance-next-gen-general-purpose/4470970" target="_blank" rel="noopener" data-lia-auto-title="Azure SQL Managed Instance (Azure SQL MI) Next-gen General Purpose" data-lia-auto-title-active="0"&gt;Azure SQL Managed Instance (Azure SQL MI) Next-gen General Purpose&lt;/A&gt; is now generally available, bringing a built-in performance and scale upgrade for General Purpose workloads, including up to 500 databases per instance, up to 32 TB storage, lower latency, and higher IOPS. The release also adds more flexible cost-performance tuning with independent vCore, IOPS, and memory scaling, plus faster management operations to adapt to changing workload demand. For enterprise SQL Server modernization, this positions Azure SQL MI as a stronger path for high-compatibility migrations that need better price-performance without moving to a full replatform.&lt;/P&gt;
&lt;P&gt;Let us dive deeper into how this helps address the downtime risk concerns by enables three levels of resiliency and high availability features.&lt;/P&gt;
&lt;H3&gt;Local Redundancy&lt;/H3&gt;
&lt;P&gt;Azure SQL Managed Instance provides first layer of Local Redundancy — built into every Azure SQL MI instance at no extra cost. Azure SQL Managed Instance uses local redundancy by default to keep workloads available during node, VM, rack, maintenance, and other local failures within a single datacenter, with Service Fabric orchestrating failover. In General Purpose (including Next-gen GP), this is implemented as stateless compute plus remote stateful storage; during failover, the engine process moves to another compute node and reattaches data, which can cause temporary performance impact due to cold cache. In Business Critical, local redundancy uses multiple synchronized replicas with local SSD storage (Always On-like architecture), enabling fast failover and read scale-out on secondaries.Next-gen General Purpose is an architectural upgrade to the existing General Purpose service tier that uses an upgraded remote storage layer that stores instance data and log files on Elastic SAN instead of page blobs and maintains it locally. Local redundancy protects against local infrastructure issues. This gives you a 99.99% SLA but not full datacenter/zone disasters, so zone redundancy (where supported) or disaster recovery (DR) options like failover groups/geo-restore are needed for broader resilience.&lt;/P&gt;
&lt;H3&gt;Zone Redundancy&lt;/H3&gt;
&lt;P&gt;The second layer is Zone Redundancy, which is accomplished placing data replicas across availability zones. Your Azure SQL MI resources are distributed across multiple availability zones within a region. This protects against the failure of an entire datacenter because each Azure availability zone is a separate physical location with independent power, cooling and networking. It relies on synchronous replication using zone-redundant storage for General Purpose. For Business critical, it uses Always On Availability group replicas across zones for Business Critical. Always On availability group technology replicates data changes from the primary instance to standby replicas in other availability zones. In the event of an outage, there's an automatic failover that seamlessly transitions one of the standby replicas to be prima. These replicas are always in sync — which means zero data loss. Failover typically happens in under 30 seconds, and your SLA jumps to 99.995%.&lt;/P&gt;
&lt;H3&gt;Failover Groups&lt;/H3&gt;
&lt;P&gt;The third layer is Failover Groups. This is your cross-region disaster recovery solution. It asynchronously replicates all user databases to a secondary Azure SQL MI instance in a different Azure region. Because it is asynchronous replication, there is potential for momentary data loss in the case of a datacenter outage. But it still protects the data against the worst case failure — a full regional outage. If the replica is a standby replica, there is no license required and it is used only for disaster recovery.&lt;/P&gt;
&lt;P&gt;Using these options, business stakeholders can get their assurance that they have Enterprise grade availability and resiliency platform of AzureSQL for running their mission critical workloads. You can read more about these &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/high-availability-sla-local-zone-redundancy?view=azuresql" target="_blank" rel="noopener"&gt;HA &lt;/A&gt;and &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/failover-group-sql-mi?view=azuresql" target="_blank" rel="noopener"&gt;Resiliency&lt;/A&gt; options in Microsoft Learn.&lt;/P&gt;
&lt;H2&gt;Cost Governance for Enterprise Buyers&lt;/H2&gt;
&lt;P&gt;The total cost of data modernization and migration is not a one-time estimate but an ongoing one. In this case, Azure SQL MI provides Enterprise DB Administrators many levers through &lt;A class="lia-external-url" href="https://azure.microsoft.com/en-us/products/azure-sql/#pricing" target="_blank" rel="noopener"&gt;pricing model choice&lt;/A&gt;, &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/data-migration/sql-server/overview#assessment" target="_blank" rel="noopener"&gt;right-sizing&lt;/A&gt;, &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/database/elastic-pool-overview?view=azuresql" target="_blank" rel="noopener"&gt;elasticity&lt;/A&gt;, &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/database/serverless-tier-overview?view=azuresql&amp;amp;tabs=general-purpose" target="_blank" rel="noopener"&gt;serverless&lt;/A&gt; options and dev/test &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/database/free-offer?view=azuresql" target="_blank" rel="noopener"&gt;free&lt;/A&gt; tiers. Let us explore how these can be combined for smart cost estimations.&lt;/P&gt;
&lt;P&gt;Lets also look at the best offering for the cost-conscious Enterprises - &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/database/service-tier-hyperscale?view=azuresql" target="_blank" rel="noopener"&gt;Azure SQL DB Hyperscale&lt;/A&gt;. With Azure SQL DB Hyperscale, you get the SQL Server engine, T-SQL compatibility, High Availability, Disaster recovery, security, backups, and management all bundled into the service price. No separate cost for SQL Server license. Hyperscale separates compute and storage that can scale independently and does not force you to overprovision. You have to only pay what you use which is ideal for seasonal workloads, Dev/Test, SaaS applications, predictable daytime trends, and up to 60% savings when you use Elastic pools.&lt;/P&gt;
&lt;P&gt;&lt;A class="lia-external-url" href="https://azure.microsoft.com/en-us/pricing/offers/hybrid-benefit/" target="_blank" rel="noopener"&gt;Azure Hybrid benefit&lt;/A&gt; (AHB)- Azure Hybrid Benefit lets you bring your existing SQL Server investments to Azure and reduce compute costs, accelerating your ROI from cloud migration while preserving all the benefits of Azure SQL&lt;/P&gt;
&lt;P&gt;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/database/free-offer-faq?view=azuresql" target="_blank" rel="noopener"&gt;Azure SQL DB Free&lt;/A&gt; offer – is the strongest product offering. Enterprises can use all features of Azure SQL at no cost for up to 10 Azure SQL DB free-tier. 100,000 vCore-seconds of serverless compute per month, 32GB data storage, 32 GB backup storage, serverless auto-scaling and auto-pause if you hit the limit per month. Run your POCs at no cost and evaluate before you move to Azure SQLDB, especially SMB&amp;amp; some enterprise&lt;/P&gt;
&lt;P&gt;Azure SQL Managed Instance also offers 1 &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/free-offer?view=azuresql" target="_blank" rel="noopener"&gt;free Azure SQL MI instance&lt;/A&gt; per Azure subscription giving you 720vCore hours per month, 64GB storage, up to 500 databases, automated backups and 12 months free.&lt;/P&gt;
&lt;P&gt;And if data migration is not possible due to data compliance or data proximity purposes, &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/sql/sql-server/azure-arc/manage-pay-as-you-go-transition?view=sql-server-ver17" target="_blank" rel="noopener"&gt;Azure Arc Pay-As-You-Go&lt;/A&gt; (PAYG) gives you cloud-style SQL licensing for servers running anywhere—on-premises, at the edge, or in other clouds. Instead of making large up-front licensing investments, you only pay for SQL Server while it's running, while still gaining access to Azure Arc management, security, monitoring, and modernization capabilities.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;For seasonal, variable, or growth-oriented workloads, PAYG can improve cash flow and reduce licensing complexity. &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/database/reservations-discount-overview?view=azuresql" target="_blank" rel="noopener"&gt;Reserved instances&lt;/A&gt; allow Enterprise customers to commit to using Azure SQL resource for a period of one or three years to receive a significant discount. This option combined with AHB can save you even more up to 80%. We have a comprehensive licensing&amp;nbsp;&lt;A href="https://go.microsoft.com/fwlink/p/?linkid=2215573" target="_blank" rel="noopener"&gt;guide &lt;/A&gt;for on-premises SQL Server for your reference.&lt;/P&gt;
&lt;P&gt;Azure SQL enables a variety of cloud cost-models for a wide range of enterprise workload needs to help Enterprise cloud cost decision makers and DB Administrators make the right choice for their workloads.&lt;/P&gt;
&lt;H2&gt;Target selection guidance&lt;/H2&gt;
&lt;P&gt;While Azure SQL has multiple deployment options to migrate your on-premises work loads, it is critical to make the right choice long term. Customers can install SQL Server on-premises, they can use Azure SQL deployment options, and also run SQL Server in other clouds like Amazon Web Services and Google Cloud.&lt;/P&gt;
&lt;P&gt;If there is an Enterprise workload that is not ready to modernize, you have the ability to &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/data-migration/sql-server/virtual-machines/overview" target="_blank" rel="noopener"&gt;lift and shift&lt;/A&gt; into SQL Server in Azure VM. It is a low cost migration option, because the application does not need any modification and it gives DB Administrators full control over the SQL server and underlying Windows or Linux OS. This can be a first step to modernization for some customers who are risk-averse.&lt;/P&gt;
&lt;P&gt;For those Enterprise customers who are willing to modernize their workloads and SQL Server instances, Azure SQL DB Hyperscale is the best &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/data-migration/sql-server/database/guide" target="_blank" rel="noopener"&gt;option&lt;/A&gt;. Azure SQL Database Hyperscale helps organizations modernize their most demanding database workloads with virtually unlimited growth, high performance, and cloud-scale economics. Customers can scale storage and compute independently, support large multi-terabyte databases, accelerate application performance with read-scale replicas, and eliminate the operational complexity of managing infrastructure, backups, patching, and high availability. They can build cloud-native applications or cloud-enable existing applications.&lt;/P&gt;
&lt;P&gt;However, if Enterprise customers want good compatibility with their on-premises SQL Server but continue down the modernization path - their best option is &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/data-migration/sql-server/managed-instance/guide" target="_blank" rel="noopener"&gt;Azure SQL Managed Instance&lt;/A&gt;. They can modernize the instance and not impact the application as there is no application change required. Applications will continue to work and the DB Administrators do not need to worry about managing infrastructure and all the overhead that comes with managing, self-managing your SQL Server virtual machines.&lt;/P&gt;
&lt;P&gt;For SQL Server customers, PostgreSQL may look like an attractive low cost option. However, it requires re-platforming that could add significant hidden cost due to retraining all their DBAs and their developers to do performance optimization, performance best practices and operational maintenance. Lastly, our same SQL engine is also available to customers as a SaaS-ified version, Fabric SQL database as well.&lt;/P&gt;
&lt;P&gt;All these options use the exact same SQL engine which makes it easier for Database developers and DB Administrators continue to use the same expertise, tools and process. Making &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/azure-sql/azure-sql-iaas-vs-paas-what-is-overview?view=azuresql" target="_blank" rel="noopener"&gt;the right choice&lt;/A&gt; of Azure SQL deployment is not just on the fastest way to modernize but the right long term approach.&lt;/P&gt;
&lt;H2&gt;Conclusion and Next steps&lt;/H2&gt;
&lt;P&gt;Enterprise SQL Server &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/data-migration/" target="_blank" rel="noopener"&gt;migrations &lt;/A&gt;rarely stall because of migration technology. More often, they are delayed by concerns around downtime, cost predictability, and platform selection. Organizations that address these questions early can accelerate modernization while reducing operational risk.&lt;/P&gt;
&lt;P&gt;Azure SQL provides &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/data-migration/sql-server/overview" target="_blank" rel="noopener"&gt;multiple modernization paths&lt;/A&gt;—from SQL Server on Azure Virtual Machines to Azure SQL Managed Instance and Azure SQL Database—allowing organizations to balance compatibility, operational simplicity, resiliency, and cost efficiency based on their business requirements.&lt;/P&gt;
&lt;P&gt;As modernization initiatives accelerate, the most successful projects are those that treat migration not as a one-time infrastructure event, but as a &lt;A class="lia-external-url" href="https://azure.microsoft.com/en-us/products/database-migration" target="_blank" rel="noopener"&gt;long-term platform strategy&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Whether its the newest and the fastest way for us to migrate customers, we have all the comprehensive Copilot enabled AI-assisted migration tooling, technical training and support you need. Look for more blogs, whitepapers, &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/data-migration/sql-server/self-hosted-integration-runtime" target="_blank" rel="noopener"&gt;guides &lt;/A&gt;and training based on best practices used real-world data modernization projects.&lt;/P&gt;</description>
      <pubDate>Tue, 30 Jun 2026 23:45:00 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-sql-blog/3-reasons-enterprise-sql-server-migrations-slow-down-and-how-to/ba-p/4532209</guid>
      <dc:creator>dhanMMS</dc:creator>
      <dc:date>2026-06-30T23:45:00Z</dc:date>
    </item>
    <item>
      <title>Log Insights in Minutes: A Simpler pgBadger Workflow</title>
      <link>https://techcommunity.microsoft.com/t5/microsoft-blog-for-postgresql/log-insights-in-minutes-a-simpler-pgbadger-workflow/ba-p/4531932</link>
      <description>&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;Sometimes the fastest way to understand a PostgreSQL workload is not another dashboard. It is a good log report.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;A href="https://github.com/darold/pgbadger" target="_blank" rel="noopener"&gt;pgBadger&lt;/A&gt; is a PostgreSQL log analysis tool that turns raw PostgreSQL logs into an interactive HTML report. It helps summarize query activity, connection patterns, errors, temporary files, lock waits, autovacuum activity, and more.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;Earlier &lt;A href="https://techcommunity.microsoft.com/blog/adforpostgresql/how-to-generate-pgbadger-report-from-azure-database-for-postgresql-flexible-serv/3756328" target="_blank" rel="noopener"&gt;guidance&lt;/A&gt; for generating pgBadger reports from Azure Database for PostgreSQL Flexible Server focused on exporting logs through Diagnostic Settings, storing them in a storage account, and then using tools such as BlobFuse and &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;jq&lt;/CODE&gt; to extract PostgreSQL log lines from JSON files.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;That workflow is still useful when customers centralize logs across multiple servers. However, if you are already using the &lt;A href="https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/how-to-server-logs-portal" target="_blank" rel="noopener"&gt;Server logs feature&lt;/A&gt; in Azure Database for PostgreSQL Flexible Server, there is a much simpler path.&lt;/P&gt;
&lt;DIV style="border-left: 5px solid #0078d4; background-color: #f3f9ff; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;In this post:&lt;/STRONG&gt; You’ll learn how to generate a pgBadger HTML report from Azure Database for PostgreSQL Flexible Server by downloading native PostgreSQL &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;.log&lt;/CODE&gt; files directly from the Azure portal. No storage account, BlobFuse mount, or JSON extraction required.&lt;/P&gt;
&lt;/DIV&gt;
&lt;DIV style="border: 1px solid #d0d7de; border-radius: 8px; padding: 18px 22px; margin: 24px 0; background-color: #f6f8fa;"&gt;
&lt;P style="font-size: 18px; line-height: 1.65; margin-top: 0;"&gt;&lt;STRONG&gt;Fast path&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL style="font-size: 18px; line-height: 1.65; margin-bottom: 0;"&gt;
&lt;LI&gt;Configure &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_line_prefix&lt;/CODE&gt;.&lt;/LI&gt;
&lt;LI&gt;Enable &lt;A class="lia-external-url" href="https://review.learn.microsoft.com/azure/postgresql/monitor/how-to-configure-server-logs?branch=pr-en-us-5322&amp;amp;tabs=portal-enable-capture-of-logs%2Cportal-disable-capture-of-logs%2Cportal-list-captured-logs%2Cportal-download-captured-logs#steps-to-enable-the-capture-of-postgresql-and-upgrade-logs-for-download" target="_blank" rel="noopener"&gt;Server logs for download&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;Download the PostgreSQL &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;.log&lt;/CODE&gt; files.&lt;/LI&gt;
&lt;LI&gt;Run pgBadger with the matching prefix.&lt;/LI&gt;
&lt;LI&gt;Open &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;pgbadger-report.html&lt;/CODE&gt;.&lt;/LI&gt;
&lt;/OL&gt;
&lt;/DIV&gt;
&lt;H2&gt;Why use this workflow?&lt;/H2&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;With Server logs, you can download native PostgreSQL &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;.log&lt;/CODE&gt; files directly from the Azure portal and run pgBadger locally.&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Older path&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Simpler path in this blog&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Diagnostic Settings → Storage account → BlobFuse → JSON extraction → pgBadger&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Server logs → Download &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;.log&lt;/CODE&gt; files → pgBadger&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Area&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Older Diagnostic Settings workflow&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Server logs workflow&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Export path&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Diagnostic Settings to storage account&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Download &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;.log&lt;/CODE&gt; files directly from the portal&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Format&lt;/td&gt;&lt;td style="padding: 10px;"&gt;JSON payloads need extraction&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Native PostgreSQL &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;.log&lt;/CODE&gt; files&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Extra tooling&lt;/td&gt;&lt;td style="padding: 10px;"&gt;BlobFuse and &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;jq&lt;/CODE&gt; JSON parsing&lt;/td&gt;&lt;td style="padding: 10px;"&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Best suited for&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Centralized or multi-server logging&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Quick per-server analysis&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Outcome&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Flexible, but more setup&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Faster path to pgBadger&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;DIV style="border-left: 5px solid #107c10; background-color: #f3fbf3; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;Recommended:&lt;/STRONG&gt; Use the &lt;A class="lia-external-url" href="https://review.learn.microsoft.com/azure/postgresql/monitor/how-to-configure-server-logs?branch=pr-en-us-5322&amp;amp;tabs=portal-enable-capture-of-logs%2Cportal-disable-capture-of-logs%2Cportal-list-captured-logs%2Cportal-download-captured-logs" target="_blank" rel="noopener"&gt;Server logs&lt;/A&gt; workflow when you want a fast, low-friction way to generate a pgBadger report from one Azure Database for PostgreSQL Flexible Server.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;When should you use this workflow?&lt;/H2&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Use this workflow when...&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Use Diagnostic Settings when...&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;You need a quick report for one Flexible Server.&lt;/td&gt;&lt;td style="padding: 10px;"&gt;You centralize logs from many servers.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;You want to run pgBadger locally.&lt;/td&gt;&lt;td style="padding: 10px;"&gt;You need long-term retention or workspace-level querying.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;You want to avoid JSON extraction.&lt;/td&gt;&lt;td style="padding: 10px;"&gt;You already have automated log export pipelines.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2&gt;Before you start&lt;/H2&gt;
&lt;UL style="font-size: 18px; line-height: 1.65;"&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;A machine where you can install or run pgBadger.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;A working Perl runtime.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Git Bash on Windows, so the multi-line shell commands work as shown.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Portal access to your Azure Database for PostgreSQL Flexible Server.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Permission to update server parameters and enable Server logs.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;DIV style="border-left: 5px solid #ffb900; background-color: #fff8e5; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;Important:&lt;/STRONG&gt; pgBadger can only analyze what PostgreSQL logs capture. To populate query timing and slow-query sections in the report, enable &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_min_duration_statement&lt;/CODE&gt; before collecting logs. Logs collected before that change will not include duration data.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;Workflow overview&lt;/H2&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Task&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Type&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Rough effort&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Install or prepare pgBadger&lt;/td&gt;&lt;td style="padding: 10px;"&gt;One-time setup per analysis machine&lt;/td&gt;&lt;td style="padding: 10px;"&gt;5–10 minutes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Configure &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_line_prefix&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;One-time setup per server&lt;/td&gt;&lt;td style="padding: 10px;"&gt;2–3 minutes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Enable Server logs&lt;/td&gt;&lt;td style="padding: 10px;"&gt;One-time setup per server&lt;/td&gt;&lt;td style="padding: 10px;"&gt;2–3 minutes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Download logs and run pgBadger&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Repeatable&lt;/td&gt;&lt;td style="padding: 10px;"&gt;2–5 minutes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL style="font-size: 18px; line-height: 1.65;"&gt;
&lt;LI&gt;Install or prepare pgBadger on the machine where you will analyze logs.&lt;/LI&gt;
&lt;LI&gt;Configure &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_line_prefix&lt;/CODE&gt; so pgBadger can parse each log line.&lt;/LI&gt;
&lt;LI&gt;Enable Server logs, so PostgreSQL logs are available for download.&lt;/LI&gt;
&lt;LI&gt;Download the logs and run pgBadger locally.&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV style="border-left: 5px solid #0078d4; background-color: #f3f9ff; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;💡Pro tip:&lt;/STRONG&gt; Start with a narrow log window first. Use one or two hourly log files, confirm the report looks right, and then expand the analysis window if needed.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;Step 1: Install pgBadger&lt;/H2&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Before generating a report, you need pgBadger available on the machine where you plan to analyze the downloaded PostgreSQL log files. Run this on a Linux VM, WSL, or another Linux-based environment where you can install packages.&lt;/P&gt;
&lt;DIV style="border-left: 5px solid #0078d4; background-color: #f3f9ff; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;Note:&lt;/STRONG&gt; Azure Cloud Shell may work for quick testing, but package installation and build-tool availability can vary by session. For repeatable analysis, use a Linux VM, WSL, or another environment you control.&lt;/P&gt;
&lt;/DIV&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Copy and run&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y git perl make gcc &amp;amp;&amp;amp; \
git clone https://github.com/darold/pgbadger.git &amp;amp;&amp;amp; \
cd pgbadger &amp;amp;&amp;amp; \
perl Makefile.PL &amp;amp;&amp;amp; \
make &amp;amp;&amp;amp; \
sudo make install &amp;amp;&amp;amp; \
pgbadger -V&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;DIV style="border-left: 5px solid #107c10; background-color: #f3fbf3; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;What good looks like:&lt;/STRONG&gt; The install command completes successfully and &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;pgbadger -V&lt;/CODE&gt; returns the installed pgBadger version.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;Step 2: Configure &lt;CODE&gt;log_line_prefix&lt;/CODE&gt;&lt;/H2&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;This is a one-time server configuration step.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;The &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_line_prefix&lt;/CODE&gt; parameter controls the beginning of each PostgreSQL log line. pgBadger uses this prefix to extract useful fields such as timestamp, user, database, and process ID.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;In the Azure portal, open your Flexible Server and go to &lt;STRONG&gt;Server parameters&lt;/STRONG&gt;. Search for:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Parameter&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;log_line_prefix&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Set this value&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;%m user=%u db=%d pid=%p:&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Then select &lt;STRONG&gt;Save&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;In Server parameters, confirm that the custom value is saved for &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_line_prefix&lt;/CODE&gt;.&lt;/P&gt;
&lt;img /&gt;
&lt;P class="lia-align-center" style="font-size: 18px; line-height: 1.65;"&gt;&lt;SPAN class="lia-text-color-15"&gt;&lt;EM&gt;Figure 1: Set &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_line_prefix&lt;/CODE&gt; so pgBadger can correctly parse timestamp, user, database, and process ID from each log line.&lt;/EM&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H3&gt;Prefix tokens&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Token&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Meaning&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;%m&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Timestamp with milliseconds&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;%u&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Username&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;%d&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Database name&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;%p&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Process ID&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;After this change, log lines should look like this:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Example log line&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-10"&gt;&lt;CODE&gt;2026-06-22 19:00:00.070 UTC user=pgadmin db=highcpu pid=3805603: LOG: statement: SELECT 1 FROM pg_extension WHERE extname='pg_stat_statements'&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;The matching pgBadger prefix for this log format is:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Matching pgBadger prefix&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;%m user=%u db=%d pid=%p:&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;You will use this same value later in the pgBadger command.&lt;/P&gt;
&lt;DIV style="border-left: 5px solid #107c10; background-color: #f3fbf3; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;What good looks like:&lt;/STRONG&gt; The server parameter is saved, and new PostgreSQL log lines begin with timestamp, user, database, and process ID fields that match the pgBadger prefix.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;Step 3: Enable Server logs for download&lt;/H2&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;This is also a one-time setup step.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;In the Azure portal, open your Flexible Server and go to &lt;STRONG&gt;Server logs&lt;/STRONG&gt;. Enable:&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Portal setting&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE class="lia-align-justify" style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;Capture logs for download&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;Set the retention period based on how long you want logs to remain available for download. For example, a 7-day retention period keeps logs available for download for 7 days.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;In Server logs, enable &lt;STRONG&gt;Capture logs for download&lt;/STRONG&gt; and choose the retention window.&lt;/P&gt;
&lt;img /&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;SPAN class="lia-text-color-15"&gt;&lt;EM&gt;Figure 2: Enable &lt;STRONG&gt;Capture logs for download&lt;/STRONG&gt; and set a retention period long enough to cover the analysis window you want to inspect.&lt;/EM&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;DIV style="border-left: 5px solid #107c10; background-color: #f3fbf3; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;What good looks like:&lt;/STRONG&gt; After Server logs are enabled, hourly PostgreSQL log files appear in the Server logs blade and can be downloaded from the Azure portal.&lt;/P&gt;
&lt;/DIV&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Once enabled, hourly log files appear in the Server logs blade. The files are named by date and hour, for example:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Example log files&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-10"&gt;&lt;CODE&gt;postgresql_2026_06_22_19_00_00.log
postgresql_2026_06_22_20_00_00.log&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;H2&gt;Step 4: Download and organize the logs locally&lt;/H2&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;From the Server logs page, select the &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;.log&lt;/CODE&gt; files for the time window you want to analyze and download them.&lt;/P&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;For example, to analyze activity between 19:00 and 21:00 UTC, download:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Example files to download&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-10"&gt;&lt;CODE&gt;postgresql_2026_06_22_19_00_00.log
postgresql_2026_06_22_20_00_00.log&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;On your local machine, create a folder for that analysis window. A simple convention is to use the &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;Mon-DD&lt;/CODE&gt; format.&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Folder name&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-10"&gt;&lt;CODE&gt;Jun-22&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Place the downloaded &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;.log&lt;/CODE&gt; files inside that folder. Your local folder structure should look like this:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Folder structure&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-10"&gt;&lt;CODE&gt;pgbadger-13.1/
  pgbadger
  Jun-22/
    postgresql_2026_06_22_19_00_00.log
    postgresql_2026_06_22_20_00_00.log&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;H2&gt;Step 5: Generate the pgBadger report&lt;/H2&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;Open Git Bash from the folder where pgBadger is located. For example, if pgBadger is inside the &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;pgbadger-13.1&lt;/CODE&gt; folder, open Git Bash from that folder.&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;#&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Action&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Command&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;1&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Set the folder&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;FOLDER=Jun-22&lt;/CODE&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;2&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Confirm files&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;ls -lh ./$FOLDER&lt;/CODE&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;3&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Run pgBadger&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Use the full command below.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Copy and run&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;FOLDER=Jun-22

ls -lh ./$FOLDER

perl -X ./pgbadger -f stderr \
  --prefix '%m user=%u db=%d pid=%p:' \
  ./$FOLDER/*.log \
  -o ./$FOLDER/pgbadger-report.html&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;H3&gt;Command breakdown&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Part of command&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Purpose&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;perl -X ./pgbadger&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Runs pgBadger and suppresses non-critical Perl warnings.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;-f stderr&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Parses PostgreSQL stderr log files.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;--prefix '%m user=%u db=%d pid=%p:'&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Matches the &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_line_prefix&lt;/CODE&gt; set on the server.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;./$FOLDER/*.log&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Analyzes every &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;.log&lt;/CODE&gt; file in the selected folder.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;-o ./$FOLDER/pgbadger-report.html&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Writes the HTML report into the same folder.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;When the command completes successfully, you should see output like this:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Expected output&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #fff8e5; border: 1px solid #ffb900; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;CODE&gt;Parsed 12134249 bytes of 12134249 (100.00%), queries: 26684, events: 83
LOG: Ok, generating html report...&lt;/CODE&gt;&lt;/PRE&gt;
&lt;DIV style="border-left: 5px solid #107c10; background-color: #f3fbf3; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;What good looks like:&lt;/STRONG&gt; pgBadger finishes parsing the logs and creates &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;pgbadger-report.html&lt;/CODE&gt; in the selected folder.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;Step 6: Open the report&lt;/H2&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Open the generated report:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Copy and run&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;start ./$FOLDER/pgbadger-report.html&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;The report opens in your default browser. The final report is created here:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Generated report path&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;Jun-22/pgbadger-report.html&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;H2&gt;What the report can show&lt;/H2&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;The pgBadger report gives you a quick view into the workload shape for the selected log window. For example, in a sample run across two hourly log files, pgBadger summarized:&lt;/P&gt;
&lt;UL class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;
&lt;LI&gt;Total number of queries.&lt;/LI&gt;
&lt;LI&gt;Number of unique normalized queries.&lt;/LI&gt;
&lt;LI&gt;Query traffic over time.&lt;/LI&gt;
&lt;LI&gt;Events such as errors and fatal messages.&lt;/LI&gt;
&lt;LI&gt;Session and connection patterns.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;Once the report opens, start with &lt;STRONG&gt;Global Stats&lt;/STRONG&gt; to confirm the time range, total queries, normalized queries, and query peak.&lt;/P&gt;
&lt;img /&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;SPAN class="lia-text-color-15"&gt;&lt;EM&gt;Figure 3: Start with Global Stats to validate the selected time range, total query count, normalized query count, and query peak.&lt;/EM&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H3&gt;Query volume and normalized queries&lt;/H3&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;Many raw queries can often reduce to a smaller number of normalized query patterns. This helps identify whether the workload is spread across many different query shapes or dominated by a smaller set of repeated statements.&lt;/P&gt;
&lt;DIV style="border-left: 5px solid #0078d4; background-color: #f3f9ff; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;Example:&lt;/STRONG&gt; In this sample run, &lt;STRONG&gt;26,684 queries&lt;/STRONG&gt; reduced to &lt;STRONG&gt;59 normalized query shapes&lt;/STRONG&gt;. That suggests the workload is mostly a small set of repeated statements, which can help focus tuning effort.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H3&gt;Traffic patterns&lt;/H3&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;The SQL Traffic section helps identify spikes, quiet periods, and workload changes over time.&lt;/P&gt;
&lt;img /&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;SPAN class="lia-text-color-15"&gt;&lt;EM&gt;Figure 4: Use SQL Traffic to identify query spikes, quiet periods, and workload changes during the selected log window.&lt;/EM&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;img /&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;SPAN class="lia-text-color-15"&gt;&lt;EM&gt;Figure 5: Review the query breakdown to compare read vs. write volume and query-type distribution for the selected Server logs window.&lt;/EM&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;For example, if the report shows a steady baseline followed by a sharp spike, that spike can be correlated with application activity, batch jobs, synthetic tests, or operational events during the same time window.&lt;/P&gt;
&lt;H3&gt;Query duration&lt;/H3&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;If query duration shows &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;0 ms&lt;/CODE&gt; or the slow query sections are empty, it usually means duration logging was not enabled when the logs were collected.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;In that case, pgBadger can still show query counts and events, but it cannot calculate the slowest queries, total execution time, average duration, or maximum duration.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;To unlock those timing sections, enable &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_min_duration_statement&lt;/CODE&gt;, collect fresh logs, and rerun pgBadger.&lt;/P&gt;
&lt;H2&gt;What pgBadger cannot infer from missing logs&lt;/H2&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;pgBadger reports are only as complete as the log data you provide. If PostgreSQL did not log duration, lock waits, temporary files, or autovacuum activity during the selected time window, pgBadger cannot reconstruct those details later.&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;To analyze...&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Enable before collecting logs&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Slow queries&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_min_duration_statement&lt;/CODE&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Lock waits&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_lock_waits&lt;/CODE&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Temporary files&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_temp_files&lt;/CODE&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Autovacuum activity&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_autovacuum_min_duration&lt;/CODE&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2&gt;Repeatable copy/paste block&lt;/H2&gt;
&lt;DIV style="border: 2px solid #107c10; border-radius: 8px; padding: 18px 22px; margin: 28px 0; background-color: #f3fbf3;"&gt;
&lt;P style="font-size: 18px; line-height: 1.65; margin-top: 0;"&gt;&lt;STRONG&gt;Reusable command block&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style="font-size: 18px; line-height: 1.65; margin-bottom: 0;"&gt;Change only &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;FOLDER&lt;/CODE&gt; for each new analysis window.&lt;/P&gt;
&lt;/DIV&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Copy and run&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;FOLDER=Jun-22

ls -lh ./$FOLDER

perl -X ./pgbadger -f stderr \
  --prefix '%m user=%u db=%d pid=%p:' \
  ./$FOLDER/*.log \
  -o ./$FOLDER/pgbadger-report.html

start ./$FOLDER/pgbadger-report.html&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;For another date, change only this line:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Update this value&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;FOLDER=Jun-22&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Examples:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Example folder values&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;FOLDER=Jun-23
FOLDER=Jul-01
FOLDER=Aug-15&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;H2&gt;Optional: Improve report quality&lt;/H2&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;pgBadger can only analyze the information captured in PostgreSQL logs.&lt;/P&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;The default logs may be enough for query frequency, connection activity, and errors. For deeper performance troubleshooting, consider enabling additional logging parameters based on your scenario.&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Scenario&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Parameter&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Suggested value&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Slow query analysis&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_min_duration_statement&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;1000&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Logs statements slower than 1 second.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Short controlled test&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_min_duration_statement&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;0&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Logs every statement. Use carefully.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Lock troubleshooting&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_lock_waits&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;on&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Helps identify lock waits.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Temporary file analysis&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_temp_files&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;0&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Logs all temporary files.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Autovacuum visibility&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_autovacuum_min_duration&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;0&lt;/CODE&gt;&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Useful during focused analysis.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 25.00%" /&gt;&lt;col style="width: 25.00%" /&gt;&lt;col style="width: 25.00%" /&gt;&lt;col style="width: 25.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Useful parameters include:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Recommended logging parameters&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;log_lock_waits = on
log_temp_files = 0
log_autovacuum_min_duration = 0&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;To capture query durations, configure:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Duration logging&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;log_min_duration_statement = 1000&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;This logs statements that run longer than 1000 milliseconds.&lt;/P&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;For short test runs, you can temporarily use:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Short test run only&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;log_min_duration_statement = 0&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;DIV style="border-left: 5px solid #ffb900; background-color: #fff8e5; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;Caution:&lt;/STRONG&gt; Use &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_min_duration_statement = 0&lt;/CODE&gt; carefully on busy production servers. It logs every statement and can generate a large volume of logs.&lt;/P&gt;
&lt;/DIV&gt;
&lt;DIV style="border-left: 5px solid #0078d4; background-color: #f3f9ff; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;Duration matters:&lt;/STRONG&gt; If duration logging is not enabled, pgBadger can still show query counts and events, but slowest-query, total duration, average duration, and maximum duration sections will be limited or empty.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;Common mistakes and quick fixes&lt;/H2&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Symptom&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Likely cause&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Fix&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;Report is empty&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Prefix mismatch&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Match &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;--prefix&lt;/CODE&gt; with &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_line_prefix&lt;/CODE&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;No duration data&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Duration logging was not enabled&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Set &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;log_min_duration_statement&lt;/CODE&gt; before collecting logs.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;No files visible&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Server logs disabled or retention expired&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Enable capture and check retention.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="padding: 10px;"&gt;pgBadger command fails&lt;/td&gt;&lt;td style="padding: 10px;"&gt;pgBadger is not in the current folder or path&lt;/td&gt;&lt;td style="padding: 10px;"&gt;Run &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 15px;"&gt;pgbadger -V&lt;/CODE&gt; to confirm installation.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2&gt;Common troubleshooting FAQs&lt;/H2&gt;
&lt;DIV style="border: 1px solid #d0d7de; border-radius: 6px; padding: 16px 20px; margin: 18px 0;"&gt;
&lt;H3&gt;1. Report is created but empty&lt;/H3&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;This usually means the pgBadger prefix did not match the actual log format.&lt;/P&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Check the first few lines:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Copy and run&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;head -5 ./$FOLDER/*.log&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Make sure the pgBadger &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;--prefix&lt;/CODE&gt; matches the server’s &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_line_prefix&lt;/CODE&gt;.&lt;/P&gt;
&lt;/DIV&gt;
&lt;DIV style="border: 1px solid #d0d7de; border-radius: 6px; padding: 16px 20px; margin: 18px 0;"&gt;
&lt;H3&gt;2. Report shows queries but no duration&lt;/H3&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;PostgreSQL logged statements but did not log durations.&lt;/P&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Enable one of the following, collect fresh logs, and rerun pgBadger:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Parameter options&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;log_min_duration_statement = 1000

# or temporarily for testing
log_min_duration_statement = 0&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;/DIV&gt;
&lt;DIV style="border: 1px solid #d0d7de; border-radius: 6px; padding: 16px 20px; margin: 18px 0;"&gt;
&lt;H3&gt;3. No &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;.log&lt;/CODE&gt; files are visible&lt;/H3&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Confirm that Server logs are enabled:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Portal setting&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;Capture logs for download&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Also check the retention period. If the retention period has expired, older logs may no longer be available for download.&lt;/P&gt;
&lt;/DIV&gt;
&lt;DIV style="border: 1px solid #d0d7de; border-radius: 6px; padding: 16px 20px; margin: 18px 0;"&gt;
&lt;H3&gt;4. pgBadger command fails&lt;/H3&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;Confirm that pgBadger is available in the current folder or installed in your path.&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Copy and run&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;pgbadger -V&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P style="font-size: 18px; line-height: 1.65;"&gt;If you are running pgBadger from the local folder, use:&lt;/P&gt;
&lt;P style="font-size: 16px; line-height: 1.4; margin-bottom: 6px;"&gt;&lt;STRONG&gt;Copy and run&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; padding: 16px; font-size: 15px; line-height: 1.55; overflow-x: auto; white-space: pre;"&gt;&lt;SPAN class="lia-text-color-13"&gt;&lt;CODE&gt;perl -X ./pgbadger&lt;/CODE&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;/DIV&gt;
&lt;H2&gt;Summary&lt;/H2&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;For customers already using Azure Database for PostgreSQL Flexible Server logs, the pgBadger workflow is straightforward:&lt;/P&gt;
&lt;OL style="font-size: 18px; line-height: 1.65;"&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Install pgBadger.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Configure &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;log_line_prefix&lt;/CODE&gt;.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Enable Server logs for download.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Download the &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;.log&lt;/CODE&gt; files.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Place them in a local date-based folder.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Run pgBadger with the matching prefix.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Open &lt;CODE style="background-color: #f6f8fa; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;pgbadger-report.html&lt;/CODE&gt;.&lt;/DIV&gt;
&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV style="border-left: 5px solid #107c10; background-color: #f3fbf3; padding: 16px 20px; margin: 24px 0;"&gt;
&lt;P class="lia-align-justify" style="font-size: 18px; line-height: 1.65;"&gt;&lt;STRONG&gt;Bottom line:&lt;/STRONG&gt; Server logs give you the shortest path from Azure Database for PostgreSQL Flexible Server logs to a pgBadger report. Download the native &lt;CODE style="background-color: #ffffff; border: 1px solid #d0d7de; border-radius: 4px; padding: 2px 5px; font-size: 16px;"&gt;.log&lt;/CODE&gt; files, run pgBadger with the matching prefix, and open the generated HTML report.&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;References&lt;/H2&gt;
&lt;UL style="font-size: 18px; line-height: 1.65;"&gt;
&lt;LI&gt;&lt;A href="https://github.com/darold/pgbadger" target="_blank" rel="noopener"&gt;pgBadger - source and documentation GitHub&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://pgbadger.darold.net/" target="_blank" rel="noopener"&gt;pgBadger - project site&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/how-to-server-logs-portal" target="_blank" rel="noopener"&gt;Azure - Download server logs from the portal Flexible Server&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-logging" target="_blank" rel="noopener"&gt;Azure - Logging concepts Flexible Server&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/how-to-configure-server-parameters-using-portal" target="_blank" rel="noopener"&gt;Azure - Configure server parameters via the portal&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-LOG-LINE-PREFIX" target="_blank" rel="noopener"&gt;PostgreSQL - log_line_prefix and logging parameters&lt;/A&gt;&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Wed, 01 Jul 2026 00:09:22 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/microsoft-blog-for-postgresql/log-insights-in-minutes-a-simpler-pgbadger-workflow/ba-p/4531932</guid>
      <dc:creator>varun-dhawan</dc:creator>
      <dc:date>2026-07-01T00:09:22Z</dc:date>
    </item>
    <item>
      <title>Lessons Learned #542: Reviewing Historical Azure SQL Database Storage Growth</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/lessons-learned-542-reviewing-historical-azure-sql-database/ba-p/4531791</link>
      <description>&lt;P&gt;This week I worked on a service request where our customer needed to understand how an Azure SQL Database had grown over time. This information can be useful for capacity planning, cost analysis, and performance reviews.&lt;/P&gt;
&lt;P&gt;There are several possible approaches, depending on whether we need to review recent historical data that is still available in Azure Monitor, or whether we need to start collecting long-term historical data from now on.&lt;/P&gt;
&lt;P&gt;In this lesson learned, I would like to summarize some of the options available.&lt;/P&gt;
&lt;H2&gt;1. Reviewing recent historical data using Azure Monitor metrics&lt;/H2&gt;
&lt;P&gt;The first point to clarify is how Azure Monitor metrics retention works.&lt;/P&gt;
&lt;P&gt;Most Azure platform metrics are retained for up to 93 days. However, a single Azure Monitor Metrics chart can query no more than 30 days of data at a time. This means that, if the data is still within the Azure Monitor retention window, we might need to review the metric in 30-day intervals.&lt;/P&gt;
&lt;P&gt;For Azure SQL Database storage usage, the metric commonly used is &lt;STRONG style="color: rgb(30, 30, 30);"&gt;Data space used&lt;/STRONG&gt;&lt;/P&gt;
&lt;H2&gt;2. Exporting metrics to Log Analytics for long-term analysis&lt;/H2&gt;
&lt;P&gt;If the requirement is to perform long-term analysis, I would like to recommended option is to enable Diagnostic Settings on the Azure SQL Database and send the metrics to a Log Analytics workspace.&lt;/P&gt;
&lt;P&gt;Azure SQL Database diagnostic telemetry can be exported to different destinations, including:&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;&lt;STRONG&gt;Log Analytics workspace&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Storage Account&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Event Hubs&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Using Log Analytics provides a very flexible way to query, aggregate, and visualize the data by using KQL.&lt;/P&gt;
&lt;P&gt;Once the metrics are available in Log Analytics, we can calculate the monthly database growth. For example:&lt;/P&gt;
&lt;LI-CODE lang="kusto"&gt;AzureMetrics 
| where ResourceProvider =~ "MICROSOFT.SQL" 
| where ResourceId == "/SUBSCRIPTIONS/your subscription/RESOURCEGROUPS/yourresourcegroup/PROVIDERS/MICROSOFT.SQL/SERVERS/yourserver/DATABASES/yourdatabase"
| where MetricName == "storage" | summarize arg_max(TimeGenerated, Average) by Month = startofmonth(TimeGenerated) 
| project Month, DataSpaceUsedGB = round(Average / 1024 / 1024 / 1024, 2) 
| order by Month asc 
&lt;/LI-CODE&gt;
&lt;P&gt;This query takes the last available value for each month and converts the metric from bytes to GB. Depending on the analysis requirements, the query can be customized.&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;3. Creating a custom database space usage history process&lt;/H2&gt;
&lt;P&gt;If we need more control, or if we want to collect more granular database-level information, another option is to create a custom process that periodically captures the current database space usage into a table. This approach can be useful when we want to keep the information inside the database itself and avoid depending on external telemetry storage for this specific requirement.&lt;/P&gt;
&lt;P&gt;For example, the following table can be used to store daily or weekly snapshots:&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;CREATE TABLE dbo.DatabaseSpaceUsageHistory
(
   SnapshotTimeUtc datetime2(3) NOT NULL DEFAULT SYSUTCDATETIME(),
   DatabaseName sysname NOT NULL,
   DataAllocatedMB decimal(19,2) NULL,
   DataUsedMB decimal(19,2) NULL,
   DataUnusedMB decimal(19,2) NULL,
   LogAllocatedMB decimal(19,2) NULL
);
 
--Example collection query:
INSERT INTO dbo.DatabaseSpaceUsageHistory
(
   DatabaseName,
   DataAllocatedMB,
   DataUsedMB,
   DataUnusedMB,
   LogAllocatedMB
)
SELECT
   DB_NAME() AS DatabaseName,
   SUM(CASE WHEN type_desc = 'ROWS' THEN size END) * 8.0 / 1024 AS DataAllocatedMB,
   SUM(CASE WHEN type_desc = 'ROWS' THEN FILEPROPERTY(name, 'SpaceUsed') END) * 8.0 / 1024 AS DataUsedMB,
   (
       SUM(CASE WHEN type_desc = 'ROWS' THEN size END)
       - SUM(CASE WHEN type_desc = 'ROWS' THEN FILEPROPERTY(name, 'SpaceUsed') END)
   ) * 8.0 / 1024 AS DataUnusedMB,
   SUM(CASE WHEN type_desc = 'LOG' THEN size END) * 8.0 / 1024 AS LogAllocatedMB
FROM sys.database_files;
&lt;/LI-CODE&gt;
&lt;P&gt;This process can be executed daily, weekly, or monthly using the automation method that best fits the environment. This approach provides more control over the data collected, the retention period, and the frequency of collection.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 29 Jun 2026 10:46:52 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/lessons-learned-542-reviewing-historical-azure-sql-database/ba-p/4531791</guid>
      <dc:creator>Jose_Manuel_Jurado</dc:creator>
      <dc:date>2026-06-29T10:46:52Z</dc:date>
    </item>
    <item>
      <title>Take control of your PostgreSQL maintenance</title>
      <link>https://techcommunity.microsoft.com/t5/microsoft-blog-for-postgresql/take-control-of-your-postgresql-maintenance/ba-p/4529918</link>
      <description>&lt;P&gt;Maintenance is an important part of keeping Azure Database for PostgreSQL flexible server secure, reliable, and up to date. It helps deliver platform updates, security patches, operating system updates, and PostgreSQL engine updates that keep servers running smoothly.&lt;/P&gt;
&lt;P&gt;But we also know that timing matters.&lt;/P&gt;
&lt;P&gt;For teams running production workloads, a maintenance event during peak traffic, a migration, financial close, a major release, or a seasonal business event can create unnecessary stress. Even a brief restart or connection interruption can affect applications, customers, and business operations.&lt;/P&gt;
&lt;P&gt;That’s why we’re excited to share that new self-service maintenance controls for Azure Database for PostgreSQL flexible server are now generally available in the Azure portal.&lt;/P&gt;
&lt;P&gt;With these new capabilities, customers can see upcoming maintenance, reschedule eligible planned maintenance to a preferred date and time, apply maintenance when they’re ready, and review maintenance history after events complete.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Why we built this&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Azure Database for PostgreSQL flexible server already offers maintenance scheduling options through Custom Maintenance Windows (CMW) and System-managed Maintenance Windows (SMW). These options give you a starting point for controlling when maintenance updates are applied.&lt;/P&gt;
&lt;P&gt;But customers told us they needed more flexibility after a specific maintenance event was scheduled.&lt;/P&gt;
&lt;P&gt;Sometimes the original maintenance time still lands during a critical business period. In the past, customers who needed to defer maintenance often had to open a support request. That added time, extra coordination, and operational overhead for something many teams wanted to handle directly.&lt;/P&gt;
&lt;P&gt;With this release, you now have more control from the Azure portal.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;What’s new&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The new maintenance experience introduces four key capabilities.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;1. View upcoming maintenance&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;You can now view upcoming maintenance before it begins. This gives teams a clearer view of when maintenance is scheduled, what type of maintenance is planned, and whether the event can be rescheduled.&lt;/P&gt;
&lt;P&gt;To view upcoming maintenance:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;In the Azure portal, go to your Azure Database for PostgreSQL flexible server.&lt;/LI&gt;
&lt;LI&gt;On the server &lt;STRONG&gt;Overview&lt;/STRONG&gt; page, review the &lt;STRONG&gt;Next Maintenance&lt;/STRONG&gt; field.&lt;/LI&gt;
&lt;/OL&gt;
&lt;img&gt;Figure 1: View upcoming maintenance&lt;/img&gt;
&lt;P&gt;If upcoming maintenance is available, the &lt;STRONG&gt;Next Maintenance&lt;/STRONG&gt; field displays the scheduled maintenance time.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Select the &lt;STRONG&gt;Next Maintenance&lt;/STRONG&gt; value to open the &lt;STRONG&gt;Maintenance&lt;/STRONG&gt; page.&lt;/LI&gt;
&lt;LI&gt;On the &lt;STRONG&gt;Maintenance&lt;/STRONG&gt; page, review the &lt;STRONG&gt;Maintenance status&lt;/STRONG&gt; section.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;The &lt;STRONG&gt;Maintenance status&lt;/STRONG&gt; section shows upcoming maintenance events that apply to your server, including the scheduled time, status, maintenance type, and available actions.&lt;/P&gt;
&lt;P&gt;Instead of reacting at the last minute, database administrators and application teams can plan ahead with more confidence.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;2. Reschedule maintenance to a preferred date and time&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;For eligible maintenance events, you can reschedule planned maintenance to a preferred date and time up to two weeks later.&lt;/P&gt;
&lt;P&gt;To reschedule maintenance:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;In the Azure portal, go to your Azure Database for PostgreSQL flexible server.&lt;/LI&gt;
&lt;LI&gt;In the left menu, under &lt;STRONG&gt;Settings&lt;/STRONG&gt;, select &lt;STRONG&gt;Maintenance&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;In the &lt;STRONG&gt;Maintenance status&lt;/STRONG&gt; section, review the upcoming maintenance event.&lt;/LI&gt;
&lt;LI&gt;If the event is eligible, select &lt;STRONG&gt;Reschedule&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;Choose an eligible future date and time.&lt;/LI&gt;
&lt;/OL&gt;
&lt;img&gt;Figure 2: Reschedule maintenance to a preferred date/time&lt;/img&gt;
&lt;P&gt;Only dates and times that meet the service rules and your maintenance policy are available for selection. &lt;STRONG&gt;Note:&lt;/STRONG&gt; Reschedule maintenance is not supported for servers on SMW schedule.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Select &lt;STRONG&gt;Reschedule&lt;/STRONG&gt; to confirm the new maintenance time.&lt;/LI&gt;
&lt;LI&gt;After confirmation, review the &lt;STRONG&gt;Maintenance status&lt;/STRONG&gt; section to verify that the new start time is displayed.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;The portal shows a confirmation after the maintenance event is successfully rescheduled.&lt;/P&gt;
&lt;P&gt;This is useful when the original maintenance time overlaps with a period where even a short interruption could be disruptive, such as peak application traffic, end-of-quarter processing, planned migrations, major releases, holiday events, or internal change freeze periods.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;3. Apply maintenance on demand&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;You can also apply eligible maintenance immediately when the timing works better for you.&lt;/P&gt;
&lt;P&gt;To apply maintenance on demand:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;In the Azure portal, go to your Azure Database for PostgreSQL flexible server.&lt;/LI&gt;
&lt;LI&gt;In the left menu, under &lt;STRONG&gt;Settings&lt;/STRONG&gt;, select &lt;STRONG&gt;Maintenance&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;In the &lt;STRONG&gt;Maintenance status&lt;/STRONG&gt; section, review the upcoming maintenance event.&lt;/LI&gt;
&lt;LI&gt;If the event is eligible, select &lt;STRONG&gt;Reschedule&lt;/STRONG&gt;, followed by &lt;STRONG&gt;Apply now&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;Select &lt;STRONG&gt;Yes - Apply Maintenance Now&lt;/STRONG&gt; to start maintenance.&lt;/LI&gt;
&lt;LI&gt;Monitor the &lt;STRONG&gt;Maintenance status&lt;/STRONG&gt; section.&lt;/LI&gt;
&lt;/OL&gt;
&lt;img&gt;Figure 3: Apply maintenance on demand&lt;/img&gt;
&lt;P&gt;The maintenance event status updates as the workflow progresses. When maintenance completes, the status changes to &lt;STRONG&gt;Complete&lt;/STRONG&gt; and the event moves to the &lt;STRONG&gt;Maintenance history&lt;/STRONG&gt; section.&lt;/P&gt;
&lt;P&gt;For example, a team might decide to apply maintenance during a quieter period, after validating application readiness, or before a planned release. This gives customers a way to complete maintenance on their own timeline instead of waiting for the scheduled window.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;4. View maintenance history&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;After maintenance completes, you can review maintenance history for your server. This helps teams confirm when maintenance occurred and supports operational reviews, troubleshooting, and audit-related workflows.&lt;/P&gt;
&lt;P&gt;To view maintenance history:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;In the Azure portal, go to your Azure Database for PostgreSQL flexible server.&lt;/LI&gt;
&lt;LI&gt;In the left menu, under &lt;STRONG&gt;Settings&lt;/STRONG&gt;, select &lt;STRONG&gt;Maintenance&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;On the &lt;STRONG&gt;Maintenance&lt;/STRONG&gt; page, review the &lt;STRONG&gt;Maintenance history&lt;/STRONG&gt; section.&lt;/LI&gt;
&lt;LI&gt;Select a maintenance event &lt;STRONG&gt;Tracking ID&lt;/STRONG&gt; to view more details, such as the maintenance type, start time, and final status.&lt;/LI&gt;
&lt;LI&gt;Select &lt;STRONG&gt;Export to CSV&lt;/STRONG&gt; to download maintenance history.&lt;/LI&gt;
&lt;/OL&gt;
&lt;img&gt;Figure 4: View maintenance history&lt;/img&gt;
&lt;P&gt;If no past maintenance events are available for the server, the maintenance history section might be empty.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Built for real production schedules&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Production environments rarely operate on a simple schedule. Maintenance often needs to be coordinated with application releases, internal change windows, customer commitments, and business calendars.&lt;/P&gt;
&lt;P&gt;These new controls are designed to make that coordination easier. By making maintenance more visible and actionable, Azure Database for PostgreSQL flexible server helps you plan with less uncertainty and more control.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Frequently asked questions&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Which maintenance events can I reschedule?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Only eligible planned maintenance events on Custom Maintenance Schedule (CMW) can be rescheduled. Some maintenance, such as time-sensitive security or compliance updates, might not be eligible for rescheduling.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;How far can I reschedule maintenance?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Eligible maintenance can be moved to a preferred date and time up to two weeks from the originally scheduled maintenance date.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Can I reschedule maintenance more than once?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Yes. You can update the selected maintenance date and time again, as long as the maintenance event remains eligible and the new time is within the allowed two-week rescheduling window.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Why can’t I reschedule maintenance right before it starts?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Rescheduling is unavailable shortly before the originally scheduled maintenance time. This lock-in period helps ensure the maintenance workflow can begin reliably.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Can I apply maintenance before its scheduled time?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Yes. When an upcoming maintenance event is eligible, you can select &lt;STRONG&gt;Apply now&lt;/STRONG&gt; in the Azure portal to begin maintenance immediately.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Will applying maintenance on demand restart my server?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;It might. Some maintenance operations require a server restart, which can result in a brief interruption or connection churn. Apply maintenance when your application can tolerate that impact.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Where can I use these maintenance controls?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;The new controls are available in the Azure portal. Open your Azure Database for PostgreSQL flexible server and go to &lt;STRONG&gt;Settings&lt;/STRONG&gt; &amp;gt; &lt;STRONG&gt;Maintenance&lt;/STRONG&gt;.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Can I use Azure CLI or REST API?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Azure CLI and REST API support are coming soon. At general availability, customers can use the Azure portal to view upcoming maintenance, reschedule eligible events, apply maintenance on demand, and view maintenance history.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Can I view maintenance that has already completed?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Yes. The &lt;STRONG&gt;Maintenance history&lt;/STRONG&gt; section in the Azure portal shows completed maintenance events. You can select an event to review its details and export the history to CSV when needed.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;What should I do if I need to defer maintenance for more than two weeks?&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Create an Azure support request. The self-service experience supports rescheduling eligible maintenance for up to two weeks, but support can help assess requests that require a longer deferral.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Getting started&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;To get started, open your Azure Database for PostgreSQL flexible server in the Azure portal and navigate to &lt;STRONG&gt;Settings&lt;/STRONG&gt; &amp;gt; &lt;STRONG&gt;Maintenance&lt;/STRONG&gt;. These new self-service maintenance controls are now generally available in the Azure portal for Azure Database for PostgreSQL flexible server. CLI and API support are coming soon.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Learn More&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;To learn more about rescheduling maintenance and related Azure PostgreSQL capabilities, see:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/postgresql/configure-maintain/concepts-maintenance" target="_blank" rel="noopener"&gt;Planned maintenance for Azure Database for PostgreSQL&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/postgresql/configure-maintain/how-to-configure-scheduled-maintenance?tabs=portal-maintenance-settings#steps-to-reschedule-maintenance-to-a-future-date" target="_blank" rel="noopener"&gt;Reschedule planned maintenance to a future date&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/postgresql/configure-maintain/concepts-maintenance#consolidated-maintenance-notifications" target="_blank" rel="noopener"&gt;Consolidated planned maintenance notifications&lt;/A&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 26 Jun 2026 22:21:20 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/microsoft-blog-for-postgresql/take-control-of-your-postgresql-maintenance/ba-p/4529918</guid>
      <dc:creator>jasomaning</dc:creator>
      <dc:date>2026-06-26T22:21:20Z</dc:date>
    </item>
    <item>
      <title>Generic Best Practices for HikariCP with Azure Database for PostgreSQL</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/generic-best-practices-for-hikaricp-with-azure-database-for/ba-p/4531059</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Author:&lt;/STRONG&gt; Mohamed Baioumy&lt;BR /&gt;&lt;STRONG&gt;Technology:&lt;/STRONG&gt; Azure Database for PostgreSQL (Flexible Server &amp;amp; Single Server)&lt;BR /&gt;&lt;STRONG&gt;Category:&lt;/STRONG&gt; Connectivity | Performance | Application Design&lt;/P&gt;
&lt;H2&gt;Introduction&lt;/H2&gt;
&lt;P&gt;Connection pooling is a critical component of application performance when connecting to Azure Database for PostgreSQL. Creating a new PostgreSQL connection is an expensive operation that consumes CPU, memory, and networking resources. Reusing existing connections through a connection pool significantly reduces connection latency, improves throughput, and helps applications scale more efficiently.&lt;/P&gt;
&lt;P&gt;Many Java applications use&amp;nbsp;&lt;STRONG&gt;HikariCP&lt;/STRONG&gt;, one of the most popular high-performance JDBC connection pools. While HikariCP provides excellent performance out of the box, improperly configured connection pool settings can lead to issues such as:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Connection pool exhaustion&lt;/LI&gt;
&lt;LI&gt;Stale or invalid connections&lt;/LI&gt;
&lt;LI&gt;Increased connection acquisition latency&lt;/LI&gt;
&lt;LI&gt;Excessive connection creation and destruction&lt;/LI&gt;
&lt;LI&gt;Database resource contention&lt;/LI&gt;
&lt;LI&gt;Application timeouts&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;This article summarizes generic guidance and best practices for configuring HikariCP when working with &lt;STRONG&gt;Azure Database for PostgreSQL Flexible Server&lt;/STRONG&gt; and &lt;STRONG&gt;Azure Database for PostgreSQL Single Server&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H1&gt;Understanding Key HikariCP Parameters&lt;/H1&gt;
&lt;H2&gt;1. Maximum Lifetime (maxLifetime)&lt;/H2&gt;
&lt;P&gt;The maxLifetime property controls how long a connection can remain in the pool before HikariCP retires it and creates a new one.&lt;/P&gt;
&lt;H3&gt;Why It Matters&lt;/H3&gt;
&lt;P&gt;Connections can become stale over time due to:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Network interruptions&lt;/LI&gt;
&lt;LI&gt;Infrastructure updates&lt;/LI&gt;
&lt;LI&gt;Connection state changes&lt;/LI&gt;
&lt;LI&gt;TCP idle behavior&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Recycling connections periodically helps prevent applications from using long-lived connections that may no longer be healthy.&lt;/P&gt;
&lt;H3&gt;Recommended Practice&lt;/H3&gt;
&lt;P&gt;Avoid configuring the value too low.&lt;/P&gt;
&lt;P&gt;When maxLifetime is set aggressively, HikariCP continuously destroys and recreates connections, resulting in:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Additional authentication overhead&lt;/LI&gt;
&lt;LI&gt;Increased connection establishment latency&lt;/LI&gt;
&lt;LI&gt;Higher CPU utilization&lt;/LI&gt;
&lt;LI&gt;Reduced application throughput&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;A reasonable starting point is:&lt;/H3&gt;
&lt;LI-CODE lang=""&gt;spring.datasource.hikari.maxLifetime=1800000&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;30 minutes (1,800,000 ms)&lt;/STRONG&gt; is commonly used and aligns well with many production workloads. Depending on workload characteristics, values between &lt;STRONG&gt;30 minutes and 1 hour&lt;/STRONG&gt; are generally suitable&lt;/P&gt;
&lt;H3&gt;Avoid&lt;/H3&gt;
&lt;LI-CODE lang=""&gt;maxLifetime=300000&lt;/LI-CODE&gt;
&lt;P&gt;(5 minutes)&lt;/P&gt;
&lt;P&gt;This often causes unnecessary connection churn without providing additional benefits.&lt;/P&gt;
&lt;H2&gt;2. Minimum Idle Connections (minimumIdle)&lt;/H2&gt;
&lt;P&gt;The minimumIdle setting defines how many idle connections HikariCP should keep ready for immediate use.&lt;/P&gt;
&lt;H3&gt;Why It Matters&lt;/H3&gt;
&lt;P&gt;A pool with available idle connections can serve application requests immediately without waiting for new connections to be established.&lt;/P&gt;
&lt;P&gt;However, maintaining too many idle connections consumes unnecessary database resources.&lt;/P&gt;
&lt;H3&gt;Recommended Practice&lt;/H3&gt;
&lt;P&gt;For most workloads:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;minimumIdle = maximumPoolSize&lt;/LI-CODE&gt;
&lt;P&gt;Or&lt;/P&gt;
&lt;LI-CODE lang=""&gt;minimumIdle slightly lower than maximumPoolSize&lt;/LI-CODE&gt;
&lt;P&gt;This ensures sufficient connections are already available during traffic spikes while avoiding excessive connection creation delays.&lt;/P&gt;
&lt;H3&gt;Example&lt;/H3&gt;
&lt;LI-CODE lang=""&gt;maximumPoolSize=20
minimumIdle=15
&lt;/LI-CODE&gt;
&lt;H3&gt;Avoid&lt;/H3&gt;
&lt;LI-CODE lang=""&gt;maximumPoolSize=20
minimumIdle=20&lt;/LI-CODE&gt;
&lt;P&gt;only when the application experiences long periods of inactivity and conserving resources is more important than immediate responsiveness.&lt;/P&gt;
&lt;H2&gt;3. Idle Timeout (idleTimeout)&lt;/H2&gt;
&lt;P&gt;The idleTimeout property determines how long an unused connection remains in the pool before being removed.&lt;/P&gt;
&lt;H3&gt;Why It Matters&lt;/H3&gt;
&lt;P&gt;Connections that sit idle for extended periods consume resources on both:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;The application server&lt;/LI&gt;
&lt;LI&gt;Azure Database for PostgreSQL&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;However, removing idle connections too quickly causes the application to repeatedly establish new connections.&lt;/P&gt;
&lt;H3&gt;Recommended Practice&lt;/H3&gt;
&lt;P&gt;Keep the default value unless there is a specific requirement.&lt;/P&gt;
&lt;LI-CODE lang=""&gt;spring.datasource.hikari.idleTimeout=600000&lt;/LI-CODE&gt;
&lt;P&gt;which equals:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;10 minutes (600,000 ms)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This setting provides a good balance between resource utilization and responsiveness. &lt;A href="https://outlook.office365.com/owa/?ItemID=AAMkADRjODQyNmEzLTIwNzEtNDdlYS05NzA3LTdkMjJiMmRhYWViZgBGAAAAAADXD8kqqM60QIcyt%2fhmrKq3BwA%2f7EuMbet6Qp8LYyRnUrzaAAAAAAEMAAD1cVSUcJQ0TpiatSE1Iv6IAAen4KcQAAA%3d&amp;amp;exvsurl=1&amp;amp;viewmodel=ReadMessageItem" target="_blank"&gt;[Re: EXT: R...0040002947 | Outlook]&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;The timeout should also be comfortably longer than any expected short application idle periods.&lt;/P&gt;
&lt;H3&gt;Avoid&lt;/H3&gt;
&lt;LI-CODE lang=""&gt;idleTimeout=10000&lt;/LI-CODE&gt;
&lt;P&gt;(10 seconds)&lt;/P&gt;
&lt;P&gt;Such aggressive settings often result in unnecessary connection creation cycles.&lt;/P&gt;
&lt;H2&gt;4. Maximum Pool Size (maximumPoolSize)&lt;/H2&gt;
&lt;P&gt;This parameter determines the maximum number of concurrent database connections the application can maintain.&lt;/P&gt;
&lt;H3&gt;Why It Matters&lt;/H3&gt;
&lt;P&gt;This is often the most important HikariCP setting.&lt;/P&gt;
&lt;H3&gt;If the Pool Is Too Small&lt;/H3&gt;
&lt;P&gt;Applications may experience:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Connection is not available, request timed out&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P&gt;because all available connections are already in use. Similar scenarios have been observed during customer investigations involving Hikari pool exhaustion.&lt;/P&gt;
&lt;H3&gt;If the Pool Is Too Large&lt;/H3&gt;
&lt;P&gt;Applications can overwhelm the database server with excessive concurrent sessions, resulting in:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Connection contention&lt;/LI&gt;
&lt;LI&gt;Increased context switching&lt;/LI&gt;
&lt;LI&gt;Higher memory consumption&lt;/LI&gt;
&lt;LI&gt;Reduced overall performance&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;Recommended Practice&lt;/H3&gt;
&lt;P&gt;Pool size should be based on:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Database compute configuration&lt;/LI&gt;
&lt;LI&gt;CPU core count&lt;/LI&gt;
&lt;LI&gt;Query execution duration&lt;/LI&gt;
&lt;LI&gt;Application concurrency requirements&lt;/LI&gt;
&lt;LI&gt;Workload characteristics&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;There is no universal value that fits every workload.&lt;/P&gt;
&lt;P&gt;Start conservatively:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;maximumPoolSize=10&lt;/LI-CODE&gt;
&lt;P&gt;or&lt;/P&gt;
&lt;P&gt;maximumPoolSize=20&lt;/P&gt;
&lt;LI-CODE lang=""&gt;maximumPoolSize=20&lt;/LI-CODE&gt;
&lt;P&gt;and increase only after load testing demonstrates a need for additional concurrency.&lt;/P&gt;
&lt;H1&gt;Fixed-Size Pool Recommendation&lt;/H1&gt;
&lt;P&gt;For many production workloads, a &lt;STRONG&gt;fixed-size pool&lt;/STRONG&gt; provides the simplest and most predictable behavior.&lt;/P&gt;
&lt;P&gt;Configure:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;maximumPoolSize=20
minimumIdle=20&lt;/LI-CODE&gt;
&lt;P&gt;or omit minimumIdle entirely so it defaults to maximumPoolSize. HikariCP commonly recommends maintaining a fixed-size pool for responsiveness during demand spikes.&lt;/P&gt;
&lt;H3&gt;Benefits&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;Faster connection acquisition&lt;/LI&gt;
&lt;LI&gt;Predictable performance&lt;/LI&gt;
&lt;LI&gt;Reduced connection creation latency&lt;/LI&gt;
&lt;LI&gt;Better handling of traffic spikes&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;When using a small fixed-size pool, there is often little need to aggressively tune:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;minimumIdle&lt;/LI&gt;
&lt;LI&gt;idleTimeout&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Instead, simply recycle connections using:&lt;/P&gt;
&lt;P&gt;maxLifetime&lt;/P&gt;
&lt;LI-CODE lang=""&gt;maxLifetime&lt;/LI-CODE&gt;
&lt;H1&gt;Additional Recommendations&lt;/H1&gt;
&lt;H2&gt;Enable TCP Keepalive&lt;/H2&gt;
&lt;P&gt;One common cause of stale connections is network devices silently dropping inactive TCP sessions.&lt;/P&gt;
&lt;P&gt;For PostgreSQL applications, consider enabling TCP keepalive:&lt;/P&gt;
&lt;P&gt;tcpKeepAlive=true&lt;/P&gt;
&lt;LI-CODE lang=""&gt;tcpKeepAlive=true&lt;/LI-CODE&gt;
&lt;P&gt;The HikariCP project specifically recommends enabling TCP keepalive to prevent rare situations where pools can lose valid connections.&lt;/P&gt;
&lt;H2&gt;Monitor Connection Usage&lt;/H2&gt;
&lt;P&gt;Track:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Active connections&lt;/LI&gt;
&lt;LI&gt;Idle connections&lt;/LI&gt;
&lt;LI&gt;Connection acquisition time&lt;/LI&gt;
&lt;LI&gt;Pool exhaustion events&lt;/LI&gt;
&lt;LI&gt;Database connection counts&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;These metrics help identify whether pool sizing is appropriate.&lt;/P&gt;
&lt;H2&gt;Investigate Long-Running Queries&lt;/H2&gt;
&lt;P&gt;Connection pool problems are often symptoms rather than root causes.&lt;/P&gt;
&lt;P&gt;A frequent scenario is:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;A query becomes slow.&lt;/LI&gt;
&lt;LI&gt;Connections remain occupied longer.&lt;/LI&gt;
&lt;LI&gt;The pool becomes exhausted.&lt;/LI&gt;
&lt;LI&gt;Applications start timing out.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;When analyzing HikariCP issues, always review:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Query performance&lt;/LI&gt;
&lt;LI&gt;Blocking situations&lt;/LI&gt;
&lt;LI&gt;Database resource utilization&lt;/LI&gt;
&lt;LI&gt;Application connection handling logic&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;Sample Production Configuration&lt;/H1&gt;
&lt;P&gt;spring.datasource.hikari.maximumPoolSize=20&lt;/P&gt;
&lt;P&gt;spring.datasource.hikari.minimumIdle=15&lt;/P&gt;
&lt;P&gt;spring.datasource.hikari.maxLifetime=1800000&lt;/P&gt;
&lt;P&gt;spring.datasource.hikari.idleTimeout=600000&lt;/P&gt;
&lt;P&gt;spring.datasource.hikari.connectionTimeout=30000&lt;/P&gt;
&lt;P&gt;spring.datasource.hikari.keepaliveTime=60000&lt;/P&gt;
&lt;LI-CODE lang=""&gt;spring.datasource.hikari.maximumPoolSize=20
spring.datasource.hikari.minimumIdle=15
spring.datasource.hikari.maxLifetime=1800000
spring.datasource.hikari.idleTimeout=600000
spring.datasource.hikari.connectionTimeout=30000
spring.datasource.hikari.keepaliveTime=60000&lt;/LI-CODE&gt;
&lt;P&gt;This configuration provides a solid starting point for many Azure Database for PostgreSQL workloads and can be adjusted based on application-specific requirements.&lt;/P&gt;
&lt;P&gt;a { text-decoration: none; color: #464feb; } tr th, tr td { border: 1px solid #e6e6e6; } tr th { background-color: #f5f5f5; }&lt;/P&gt;
&lt;H1&gt;Conclusion&lt;/H1&gt;
&lt;P&gt;HikariCP is extremely efficient when configured appropriately. The goal is not to maximize the number of connections, but rather to maintain a healthy balance between application responsiveness and database resource consumption.&lt;/P&gt;
&lt;P&gt;As a general rule:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Use a reasonable maxLifetime (30–60 minutes)&lt;/LI&gt;
&lt;LI&gt;Keep enough idle connections available for traffic spikes&lt;/LI&gt;
&lt;LI&gt;Avoid aggressive idleTimeout values&lt;/LI&gt;
&lt;LI&gt;Size the pool based on workload characteristics, not guesses&lt;/LI&gt;
&lt;LI&gt;Consider fixed-size pools for predictable performance&lt;/LI&gt;
&lt;LI&gt;Monitor connection usage and query performance regularly&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;By following these practices, applications connecting to Azure Database for PostgreSQL can achieve improved scalability, lower latency, and more reliable connectivity.&lt;/P&gt;
&lt;H2&gt;&lt;SPAN style="color: rgb(30, 30, 30);"&gt;References&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/postgresql/connectivity/concepts-connection-pooling-best-practices" target="_blank"&gt;Connection pooling best practices - Azure Database for PostgreSQL&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;A class="lia-external-url" href="https://azure.microsoft.com/en-us/blog/performance-best-practices-for-using-azure-database-for-postgresql-connection-pooling/" target="_blank"&gt;Performance best practices for using Azure Database for PostgreSQL – Connection Pooling&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;A class="lia-external-url" href="https://github.com/brettwooldridge/HikariCP" target="_blank"&gt;HikariCP Documentation and Pool Sizing Guidance&lt;/A&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 26 Jun 2026 22:05:48 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/generic-best-practices-for-hikaricp-with-azure-database-for/ba-p/4531059</guid>
      <dc:creator>Mohamed_Baioumy_MSFT</dc:creator>
      <dc:date>2026-06-26T22:05:48Z</dc:date>
    </item>
    <item>
      <title>Lessons Learned #541:Automatic Plan Correction vs External Tables: A Practical Lesson from the Field</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/lessons-learned-541-automatic-plan-correction-vs-external-tables/ba-p/4531400</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Automatic Plan Correction&lt;/STRONG&gt; is one of the most useful capabilities in Azure SQL Database when dealing with &lt;STRONG&gt;plan regressions&lt;/STRONG&gt;. It uses Query Store to identify when a query starts using a worse execution plan and, when appropriate, &lt;STRONG&gt;forces the last known good plan&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;However, during a recent troubleshooting scenario, I found that not all queries have the same execution characteristics. In particular, &lt;STRONG&gt;queries that reference external tables&lt;/STRONG&gt; may behave differently from fully local queries because part of their execution depends on remote data access.&lt;/P&gt;
&lt;P&gt;When Query Store is configured to capture all queries, we can use it to identify queries that reference external tables and review whether those query IDs should participate in FORCE_LAST_GOOD_PLAN.&lt;/P&gt;
&lt;P&gt;From a practical perspective, external-table queries may not always be the best candidates for Automatic Plan Correction, especially when the expected benefit of automatic plan forcing is not clear. For that reason, the goal of this article is simple: identify queries that reference external tables and, when appropriate, exclude selected query IDs from Automatic Plan Correction.&lt;/P&gt;
&lt;P&gt;If we review the execution plan for the following query:&amp;nbsp;&lt;STRONG&gt;&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;DECLARE @Region nvarchar(50) = N'EMEA' 
SELECT CustomerId, CustomerName, Region 
FROM dbo.ExternalCustomers 
WHERE Region = @Region;&lt;/LI-CODE&gt;
&lt;P&gt;We can see that the plan includes a&amp;nbsp;&lt;STRONG&gt;Remote Query operator&lt;/STRONG&gt;. This means that the query is not only accessing local data; part of the execution depends on remote data access through the external table.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;For this type of query, &lt;STRONG&gt;Automatic Plan Correction&lt;/STRONG&gt; may not provide the same clear benefit as it does for fully local queries. The performance may depend not only on the local execution plan, but also on the remote database, the external data source, network latency, and the amount of data returned from the remote side.&lt;/P&gt;
&lt;P&gt;For that reason, queries referencing external tables are good candidates for review before allowing them to participate in &lt;STRONG&gt;FORCE_LAST_GOOD_PLAN.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;In this scenario, the first step was to identify the Query Store query_id associated with the query referencing the external table. Since the query text was available in Query Store, we searched for the external table name in sys.query_store_query_text.&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;SELECT
    q.query_id,
    p.plan_id,
    p.is_forced_plan,
    p.plan_forcing_type_desc,
    p.force_failure_count,
    p.last_force_failure_reason_desc,
    p.last_execution_time,
    qt.query_sql_text
FROM sys.query_store_query_text AS qt
INNER JOIN sys.query_store_query AS q
    ON qt.query_text_id = q.query_text_id
INNER JOIN sys.query_store_plan AS p
    ON q.query_id = p.query_id
WHERE qt.query_sql_text LIKE N'%ExternalCustomers%'
ORDER BY
    p.last_execution_time DESC;
&lt;/LI-CODE&gt;
&lt;P&gt;Once the query_id was identified, the next step was to exclude that specific query from Automatic Plan Correction by setting FORCE_LAST_GOOD_PLAN to OFF for that query_id.&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;EXECUTE sys.sp_configure_automatic_tuning @option = 'FORCE_LAST_GOOD_PLAN', @type = 'QUERY', @type_value = N'&amp;lt;query_id&amp;gt;', @option_value = 'OFF';&lt;/LI-CODE&gt;
&lt;P&gt;For example:&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;EXECUTE sys.sp_configure_automatic_tuning @option = 'FORCE_LAST_GOOD_PLAN', @type = 'QUERY', @type_value = N'1574', @option_value = 'OFF';&lt;/LI-CODE&gt;
&lt;P&gt;This does not disable Automatic Plan Correction for the entire database. It only tells Automatic Plan Correction to ignore this specific Query Store query ID for FORCE_LAST_GOOD_PLAN.&lt;/P&gt;
&lt;P&gt;With this approach, Automatic Plan Correction can remain enabled for the rest of the database workload, while selected queries that depend on external or remote data access can be reviewed and excluded individually when automatic plan forcing is not expected to provide a clear benefit.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 26 Jun 2026 20:49:11 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/lessons-learned-541-automatic-plan-correction-vs-external-tables/ba-p/4531400</guid>
      <dc:creator>Jose_Manuel_Jurado</dc:creator>
      <dc:date>2026-06-26T20:49:11Z</dc:date>
    </item>
    <item>
      <title>Data sync fails with deadlock error</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/data-sync-fails-with-deadlock-error/ba-p/4526202</link>
      <description>&lt;P&gt;Recently I have worked on cases where it is observed that data sync fails with deadlock error.&lt;/P&gt;
&lt;P&gt;Error:&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Database re-provisioning failed with the exception 'Transaction (Process ID ##) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;To investigate deadlocks, you can enable Extended Events by following the guidance provided here:&lt;/P&gt;
&lt;P&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/azure-sql/database/analyze-prevent-deadlocks?view=azuresql&amp;amp;tabs=event-file#collect-deadlock-graphs-in-azure-sql-database-with-extended-events" target="_blank" rel="noopener"&gt;https://learn.microsoft.com/en-us/azure/azure-sql/database/analyze-prevent-deadlocks?view=azuresql&amp;amp;tabs=event-file#collect-deadlock-graphs-in-azure-sql-database-with-extended-events&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;U&gt;A Sample deadlock graph looks below:&lt;/U&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;
&lt;img /&gt;&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Running the Data Sync Health Checker report also results in the same error being observed.&lt;/P&gt;
&lt;P&gt;&lt;A href="https://github.com/microsoft/AzureSQLDataSyncHealthChecker" target="_blank" rel="noopener"&gt;https://github.com/microsoft/AzureSQLDataSyncHealthChecker&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Database re-provisioning failed with the exception 'Transaction (Process ID ##) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;U&gt;Explanation:&lt;/U&gt;&lt;/P&gt;
&lt;P&gt;When a deadlock occurs between a Data Sync operation and a customer transaction, the Data Sync operation is always selected as the victim.&lt;/P&gt;
&lt;P&gt;To mitigate this issue without removing and recreating the Data Sync configuration, please follow the below steps:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Remove the table referenced in the deadlock error from the Data Sync configuration and then restart the synchronization.&lt;/LI&gt;
&lt;LI&gt;If automatic synchronization is enabled, disable the schedule and run the sync process manually.&lt;/LI&gt;
&lt;LI&gt;Increase the frequency of the synchronization process to minimize overlapping operations and reduce the likelihood of deadlocks.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Additionally, running UPDATE STATISTICS and rebuilding indexes on the system tables involved in Data Sync may help improve performance. This can assist the SQL optimizer in selecting a more efficient execution plan, thereby allowing the synchronization process to complete faster and reducing the likelihood of deadlocks.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;U&gt;&lt;STRONG&gt;Please note that Azure SQL Data Sync will be retired on September 30, 2027.&lt;/STRONG&gt;&lt;/U&gt;&lt;/P&gt;
&lt;P&gt;For more details, refer to the official documentation:&lt;/P&gt;
&lt;P&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/azure-sql/database/sql-data-sync-data-sql-server-sql-database?view=azuresql" target="_blank" rel="noopener"&gt;https://learn.microsoft.com/en-us/azure/azure-sql/database/sql-data-sync-data-sql-server-sql-database?view=azuresql&lt;/A&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 22 Jun 2026 09:06:18 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/data-sync-fails-with-deadlock-error/ba-p/4526202</guid>
      <dc:creator>SmritiGupta</dc:creator>
      <dc:date>2026-06-22T09:06:18Z</dc:date>
    </item>
    <item>
      <title>Azure SQL DB Fabric Mirroring with Private Endpoint</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/azure-sql-db-fabric-mirroring-with-private-endpoint/ba-p/4529793</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Introduction&lt;BR /&gt;&lt;/STRONG&gt;Overview steps for configuration of Mirroring between Azure SQL Database to Fabric Mirrored Database over Private Endpoint and Public Connectivity Disabled on source.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;BR /&gt;Prerequisites&lt;BR /&gt;#1&lt;/STRONG&gt; - The minimum requirement for the source Azure SQL Database tier is - it is Standard Tier with DTUs equal or greater than 100.&lt;BR /&gt;Free, Basic Tier, or &amp;lt;100 DTUs are NOT supported.&lt;BR /&gt;All vCore model tiers supported.&lt;BR /&gt;&lt;BR /&gt;&lt;STRONG&gt;#2&lt;/STRONG&gt; - System Assigned Managed Identity (SAMI) must be enabled on the Azure SQL logical server.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&lt;STRONG&gt;#3&lt;/STRONG&gt;&amp;nbsp;- Microsoft.PowerPlatform should be registered as a source provider at the subscription level.&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;If this step is not completed, you'll face error in the next steps, while creating the 'Virtual Network Data Gateway', example below.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&lt;STRONG&gt;#4 &lt;/STRONG&gt;- The Virtual Network Subnet of the configured Private Endpoint should have the following selected.&lt;BR /&gt;Select Microsoft.PowerPlatform/netaccesslinks for the Subnet Delegation tab.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;This is a required step, otherwise the subnet is grayed out to select while configuration of the Virtual Network Data Gateway at Fabric level.&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;&lt;STRONG&gt;High Level Configuration Steps&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;#1&amp;nbsp;&lt;/STRONG&gt;- Go to Fabric Portal &amp;gt; Settings&lt;BR /&gt;Click on Settings button on top right &amp;gt; Click on Manage Connections and Gateways&lt;BR /&gt;Go to 'Virtual Network Data Gateway' tab &amp;gt; Click New&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;In the new page, Select your Capacity, Subscription, Resource Group, VNET and Subnet of the source Azure SQL DB and create it.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&lt;STRONG&gt;#2&lt;/STRONG&gt;&amp;nbsp;- Go back to your workspace, and click new item &amp;gt; Search 'Mirrored Azure SQL Database'&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&lt;STRONG&gt;#3&lt;/STRONG&gt;&amp;nbsp;- Here, in Data Gateway section, chose your new created gateway which we created in previous step, and fill the required source Azure SQL Database details and click connect.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&lt;STRONG&gt;#4&lt;/STRONG&gt; - Select the tables to be mirrored in the next steps and you will be able to successfully mirror from Azure SQL Database to Mirrored Azure SQL Database without Public Connectivity and using Private Endpoint.&lt;/P&gt;</description>
      <pubDate>Wed, 08 Jul 2026 10:52:35 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/azure-sql-db-fabric-mirroring-with-private-endpoint/ba-p/4529793</guid>
      <dc:creator>shaurya-singh</dc:creator>
      <dc:date>2026-07-08T10:52:35Z</dc:date>
    </item>
    <item>
      <title>Troubleshooting Azure SQL Data Sync Failures Caused by Large Change Tracking Backlogs</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-support-blog/troubleshooting-azure-sql-data-sync-failures-caused-by-large/ba-p/4529337</link>
      <description>&lt;H2&gt;Introduction&lt;/H2&gt;
&lt;P&gt;Azure SQL Data Sync is a popular solution for synchronizing data across multiple Azure SQL Database instances. It uses Change Tracking to identify and propagate data modifications between participating databases. While Data Sync can operate reliably for extended periods, environments with highly active tables may occasionally encounter synchronization failures that become increasingly difficult to recover from.&lt;/P&gt;
&lt;P&gt;In this article, we examine a real-world troubleshooting scenario in which Azure SQL Data Sync repeatedly failed while attempting to synchronize changes for a specific table. The investigation revealed that excessive synchronization metadata growth and a large change backlog were causing change enumeration operations to exceed Azure SQL Database resource governance thresholds, resulting in repeated synchronization failures.&lt;/P&gt;
&lt;P&gt;This post explains the symptoms, investigation process, troubleshooting scripts, root cause, mitigation strategy, and preventive measures that administrators can apply in their own Azure SQL Data Sync environments.&lt;/P&gt;
&lt;H1&gt;Symptoms&lt;/H1&gt;
&lt;P&gt;The issue manifested as repeated Azure SQL Data Sync failures for a single synchronized table while the sync group remained unhealthy.&lt;/P&gt;
&lt;P&gt;Administrators may encounter errors similar to:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Cannot enumerate changes at the RelationalSyncProvider.&lt;/P&gt;
&lt;P&gt;SqlError Number: 40197&lt;/P&gt;
&lt;P&gt;The service has encountered an error processing your request.&lt;/P&gt;
&lt;P&gt;Please try again.&lt;/P&gt;
&lt;P&gt;Error code 40549&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P&gt;These errors can occur when Data Sync attempts to enumerate pending changes through Change Tracking and synchronization metadata, but the operation becomes excessively resource intensive.&lt;/P&gt;
&lt;H3&gt;Additional Warning Signs&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;Synchronization runs taking significantly longer than usual&lt;/LI&gt;
&lt;LI&gt;Repeated synchronization retries&lt;/LI&gt;
&lt;LI&gt;Increasing synchronization latency&lt;/LI&gt;
&lt;LI&gt;Large Data Sync metadata growth&lt;/LI&gt;
&lt;LI&gt;Sync groups reporting warning or failed states&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;Understanding How Azure SQL Data Sync Uses Change Tracking&lt;/H1&gt;
&lt;P&gt;Azure SQL Data Sync relies on SQL Change Tracking to identify modifications occurring within synchronized tables.&lt;/P&gt;
&lt;P&gt;The synchronization architecture generally consists of:&lt;/P&gt;
&lt;H3&gt;Hub Database&lt;/H3&gt;
&lt;P&gt;The central synchronization endpoint responsible for orchestrating synchronization.&lt;/P&gt;
&lt;H3&gt;Member Databases&lt;/H3&gt;
&lt;P&gt;Databases that participate in synchronization and exchange data with the hub.&lt;/P&gt;
&lt;H3&gt;Change Tracking&lt;/H3&gt;
&lt;P&gt;Tracks data modifications and provides an efficient mechanism to identify rows that have changed since the last synchronization cycle.&lt;/P&gt;
&lt;H3&gt;Synchronization Metadata&lt;/H3&gt;
&lt;P&gt;Data Sync maintains internal metadata used to track synchronization state and determine which changes must be applied.&lt;/P&gt;
&lt;H3&gt;Change Enumeration&lt;/H3&gt;
&lt;P&gt;During synchronization, Azure SQL Data Sync enumerates tracked changes and applies them across participating databases.&lt;/P&gt;
&lt;P&gt;As synchronization backlog grows, the complexity and duration of enumeration operations increase accordingly.&lt;/P&gt;
&lt;H1&gt;Investigation Process&lt;/H1&gt;
&lt;P&gt;The troubleshooting effort focused on identifying where synchronization was failing and determining whether the underlying issue was related to Change Tracking, synchronization metadata, or Azure SQL resource limitations.&lt;/P&gt;
&lt;H3&gt;Step 1 – Identify the Failing Object&lt;/H3&gt;
&lt;P&gt;Review synchronization logs to determine which table repeatedly generates failures.&lt;/P&gt;
&lt;H3&gt;Step 2 – Determine Where the Failure Occurs&lt;/H3&gt;
&lt;P&gt;Determine whether the issue originates from:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Hub Database&lt;/LI&gt;
&lt;LI&gt;Member Database&lt;/LI&gt;
&lt;LI&gt;Synchronization Infrastructure&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;Step 3 – Evaluate Synchronization Backlog&lt;/H3&gt;
&lt;P&gt;Assess the volume of pending changes and synchronization metadata growth.&lt;/P&gt;
&lt;H3&gt;Step 4 – Assess Resource Governance Impact&lt;/H3&gt;
&lt;P&gt;Evaluate whether Azure SQL Database resource governance may be terminating synchronization-related operations.&lt;/P&gt;
&lt;H1&gt;Useful T-SQL Scripts for Azure SQL Data Sync Troubleshooting&lt;/H1&gt;
&lt;P&gt;During the investigation, several T-SQL queries were used to validate Change Tracking configuration, evaluate synchronization backlog size, identify governance-related interruptions, and assess the overall health of the Azure SQL environment.&lt;/P&gt;
&lt;P&gt;All scripts below have been sanitized and generalized for public use.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Note:&lt;/STRONG&gt; Replace dbo.SyncTable with the affected synchronized table in your environment.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H2&gt;1. Verify Whether Change Tracking Is Enabled&lt;/H2&gt;
&lt;P&gt;Azure SQL Data Sync requires Change Tracking to function correctly.&lt;/P&gt;
&lt;H3&gt;Check Database-Level Change Tracking&lt;/H3&gt;
&lt;LI-CODE lang="sql"&gt;-- Run to Master DB
SELECT
    DB_NAME(database_id) AS DatabaseName,
    is_auto_cleanup_on,
    retention_period,
    retention_period_units_desc
FROM sys.change_tracking_databases
WHERE database_id = DB_ID();&lt;/LI-CODE&gt;
&lt;H3&gt;Check Table-Level Change Tracking&lt;/H3&gt;
&lt;LI-CODE lang="sql"&gt;-- Run to UserDB
SELECT
    OBJECT_SCHEMA_NAME(object_id) AS SchemaName,
    OBJECT_NAME(object_id) AS TableName,
    begin_version,
    cleanup_version,
    min_valid_version
FROM sys.change_tracking_tables
WHERE object_id = OBJECT_ID('dbo.SyncTable');&lt;/LI-CODE&gt;
&lt;H3&gt;Why This Matters&lt;/H3&gt;
&lt;P&gt;If Change Tracking is disabled, Azure SQL Data Sync cannot enumerate changes successfully.&lt;/P&gt;
&lt;H2&gt;2. Estimate Synchronization Backlog Size&lt;/H2&gt;
&lt;P&gt;One of the most useful troubleshooting indicators is the volume of pending changes.&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;--Run to UserDb
SELECT COUNT(*) AS PendingChanges
FROM CHANGETABLE(CHANGES dbo.SyncTable, 0) AS CT;&lt;/LI-CODE&gt;
&lt;H3&gt;Why This Matters&lt;/H3&gt;
&lt;P&gt;A very large backlog may indicate:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Synchronization delays&lt;/LI&gt;
&lt;LI&gt;Metadata accumulation&lt;/LI&gt;
&lt;LI&gt;Enumeration pressure&lt;/LI&gt;
&lt;LI&gt;Increased risk of governance-related failures&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;3. Review Change Tracking Metadata&lt;/H2&gt;
&lt;LI-CODE lang="sql"&gt;--Run to UserDB
SELECT
  OBJECT_NAME(object_id) AS TableName,
    begin_version,
    min_valid_version,
    cleanup_version
FROM sys.change_tracking_tables
WHERE object_id = OBJECT_ID('dbo.SyncTable');&lt;/LI-CODE&gt;
&lt;H3&gt;Why This Matters&lt;/H3&gt;
&lt;P&gt;This information helps determine whether Change Tracking metadata is growing faster than cleanup processes can manage.&lt;/P&gt;
&lt;H2&gt;4. Validate Database Service Tier&lt;/H2&gt;
&lt;LI-CODE lang="sql"&gt;-- Run to UserDB
SELECT 
 database_id, 
 edition, 
 service_objective, 
 elastic_pool_name 
FROM sys.database_service_objectives;&lt;/LI-CODE&gt;
&lt;H3&gt;Why This Matters&lt;/H3&gt;
&lt;P&gt;Resource limitations associated with a database service tier may contribute to synchronization instability under heavy workloads.&lt;/P&gt;
&lt;H2&gt;5. Check for Resource Governance Events&lt;/H2&gt;
&lt;P&gt;Run the following query from the &lt;STRONG&gt;master database&lt;/STRONG&gt; of the Azure SQL logical server.&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;SELECT TOP 20 
	end_time, 
	event_type, 
	event_subtype_desc, 
	description 
FROM sys.event_log 
WHERE event_type = 'connection'   
	AND event_subtype_desc = 'killed_by_governance'   
	AND end_time &amp;gt; DATEADD(hour, -24, GETUTCDATE()) 
ORDER BY end_time DESC;&lt;/LI-CODE&gt;
&lt;H3&gt;Why This Matters&lt;/H3&gt;
&lt;P&gt;This query can reveal whether Azure SQL Database terminated operations because they exceeded governance thresholds.&lt;/P&gt;
&lt;P&gt;Examples include:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Long-running synchronization queries&lt;/LI&gt;
&lt;LI&gt;Excessive CPU consumption&lt;/LI&gt;
&lt;LI&gt;Excessive IO workload&lt;/LI&gt;
&lt;LI&gt;Large Change Tracking enumeration operations&lt;/LI&gt;
&lt;/UL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Note:&lt;/STRONG&gt; sys.event_log is available only from the master database.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H2&gt;6. Identify Large Tables&lt;/H2&gt;
&lt;LI-CODE lang="sql"&gt;SELECT
    t.name AS TableName,
    SUM(p.rows) AS RowCounts
FROM sys.tables t
INNER JOIN sys.partitions p
    ON t.object_id = p.object_id
WHERE p.index_id IN (0,1)
GROUP BY t.name
ORDER BY RowCounts DESC;&lt;/LI-CODE&gt;
&lt;H3&gt;Why This Matters&lt;/H3&gt;
&lt;P&gt;Large high-churn tables often generate substantial amounts of synchronization metadata and are frequently associated with Data Sync performance issues.&lt;/P&gt;
&lt;H2&gt;7. Review Change Tracking Across All Tables&lt;/H2&gt;
&lt;LI-CODE lang="sql"&gt;SELECT
    OBJECT_SCHEMA_NAME(object_id) AS SchemaName,
    OBJECT_NAME(object_id) AS TableName,
    begin_version,
    cleanup_version,
    min_valid_version
FROM sys.change_tracking_tables
ORDER BY TableName;&lt;/LI-CODE&gt;
&lt;H3&gt;Why This Matters&lt;/H3&gt;
&lt;P&gt;This query helps identify whether metadata growth is isolated to a single synchronized table or occurring across multiple tables.&lt;/P&gt;
&lt;H2&gt;Troubleshooting Checklist&lt;/H2&gt;
&lt;P&gt;When troubleshooting Azure SQL Data Sync failures:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Confirm Change Tracking is enabled.&lt;/LI&gt;
&lt;LI&gt;Identify the failing synchronized table.&lt;/LI&gt;
&lt;LI&gt;Measure synchronization backlog size.&lt;/LI&gt;
&lt;LI&gt;Review Change Tracking metadata.&lt;/LI&gt;
&lt;LI&gt;Check database service-tier configuration.&lt;/LI&gt;
&lt;LI&gt;Check Azure SQL governance events.&lt;/LI&gt;
&lt;LI&gt;Review table size and update patterns.&lt;/LI&gt;
&lt;LI&gt;Monitor resource utilization.&lt;/LI&gt;
&lt;LI&gt;Validate synchronization health following remediation.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;Root Cause Analysis&lt;/H1&gt;
&lt;P&gt;The investigation ultimately revealed several contributing factors:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;A large synchronization backlog accumulated over time.&lt;/LI&gt;
&lt;LI&gt;Change Tracking metadata continued to grow.&lt;/LI&gt;
&lt;LI&gt;Synchronization enumeration operations became increasingly resource intensive.&lt;/LI&gt;
&lt;LI&gt;Azure SQL Database resource governance began terminating long-running synchronization operations.&lt;/LI&gt;
&lt;LI&gt;Data Sync repeatedly retried synchronization and encountered the same failures.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;As a result, synchronization was unable to progress beyond the accumulated backlog and remained stuck in a failure cycle.&lt;/P&gt;
&lt;H1&gt;Resolution&lt;/H1&gt;
&lt;P&gt;The mitigation focused on reducing synchronization pressure and rebuilding synchronization state.&lt;/P&gt;
&lt;H3&gt;Recovery Approach&lt;/H3&gt;
&lt;OL&gt;
&lt;LI&gt;Remove the affected table from the Sync Group.&lt;/LI&gt;
&lt;LI&gt;Save synchronization configuration changes.&lt;/LI&gt;
&lt;LI&gt;Preserve business data through backups or archival.&lt;/LI&gt;
&lt;LI&gt;Reset or recreate the synchronized table when appropriate.&lt;/LI&gt;
&lt;LI&gt;Allow synchronization metadata cleanup.&lt;/LI&gt;
&lt;LI&gt;Re-add the table to the Sync Group.&lt;/LI&gt;
&lt;LI&gt;Trigger synchronization.&lt;/LI&gt;
&lt;LI&gt;Validate successful synchronization completion.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;Following this approach, synchronization resumed successfully without further failures.&lt;/P&gt;
&lt;H1&gt;Why the Resolution Works&lt;/H1&gt;
&lt;P&gt;This process addresses the underlying metadata problem rather than repeatedly retrying synchronization.&lt;/P&gt;
&lt;P&gt;Benefits include:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Cleanup of excessive synchronization metadata&lt;/LI&gt;
&lt;LI&gt;Elimination of accumulated backlog&lt;/LI&gt;
&lt;LI&gt;Reset of synchronization state&lt;/LI&gt;
&lt;LI&gt;Fresh synchronization initialization&lt;/LI&gt;
&lt;LI&gt;Reduced enumeration workload&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;Technical Recommendations&lt;/H1&gt;
&lt;OL&gt;
&lt;LI&gt;Monitor synchronization health regularly.&lt;/LI&gt;
&lt;LI&gt;Track synchronization latency.&lt;/LI&gt;
&lt;LI&gt;Observe Data Sync metadata growth.&lt;/LI&gt;
&lt;LI&gt;Investigate synchronization failures early.&lt;/LI&gt;
&lt;LI&gt;Monitor DTU or vCore utilization.&lt;/LI&gt;
&lt;LI&gt;Review high-volume synchronized tables.&lt;/LI&gt;
&lt;LI&gt;Validate Change Tracking health periodically.&lt;/LI&gt;
&lt;LI&gt;Monitor retries and failed sync operations.&lt;/LI&gt;
&lt;LI&gt;Establish proactive alerting.&lt;/LI&gt;
&lt;LI&gt;Review synchronization design for large-scale workloads.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&lt;SPAN style="color: rgb(30, 30, 30); font-size: 34px;"&gt;Common Error Messages&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;Error 40197&lt;/H2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;The service has encountered an error processing your request.&lt;/P&gt;
&lt;P&gt;Please try again.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H3&gt;Potential Causes&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;Transient platform interruption&lt;/LI&gt;
&lt;LI&gt;Resource-governance intervention&lt;/LI&gt;
&lt;LI&gt;Long-running synchronization operations&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Error 40549&lt;/H2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Error code 40549&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H3&gt;Potential Causes&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;Excessive resource consumption&lt;/LI&gt;
&lt;LI&gt;Long-running transactions&lt;/LI&gt;
&lt;LI&gt;Synchronization enumeration pressure&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Cannot Enumerate Changes at the RelationalSyncProvider&lt;/H2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Cannot enumerate changes at the RelationalSyncProvider.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H3&gt;Potential Causes&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;Change Tracking backlog growth&lt;/LI&gt;
&lt;LI&gt;Excessive synchronization metadata&lt;/LI&gt;
&lt;LI&gt;Resource-governance intervention&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;Lessons Learned&lt;/H1&gt;
&lt;UL&gt;
&lt;LI&gt;Monitor Data Sync metadata growth proactively.&lt;/LI&gt;
&lt;LI&gt;Investigate synchronization delays before backlog accumulates.&lt;/LI&gt;
&lt;LI&gt;High-volume transactional tables require closer monitoring.&lt;/LI&gt;
&lt;LI&gt;Resource governance can significantly impact synchronization workloads.&lt;/LI&gt;
&lt;LI&gt;Reinitializing synchronization state may be necessary when metadata growth becomes excessive.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;Key Takeaways&lt;/H1&gt;
&lt;UL&gt;
&lt;LI&gt;Azure SQL Data Sync depends heavily on Change Tracking metadata.&lt;/LI&gt;
&lt;LI&gt;Large synchronization backlogs can cause expensive enumeration operations.&lt;/LI&gt;
&lt;LI&gt;Errors 40197 and 40549 may indicate resource-governance interruptions.&lt;/LI&gt;
&lt;LI&gt;Large metadata accumulation can trigger synchronization failures.&lt;/LI&gt;
&lt;LI&gt;Monitoring synchronization health is essential.&lt;/LI&gt;
&lt;LI&gt;High-volume tables require ongoing review.&lt;/LI&gt;
&lt;LI&gt;Resetting synchronization state can be an effective recovery mechanism.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;Conclusion&lt;/H1&gt;
&lt;P&gt;Azure SQL Data Sync remains a powerful solution for synchronizing data across Azure SQL Database environments. However, synchronization metadata and Change Tracking backlog growth can gradually evolve into serious operational challenges when left unchecked.&lt;/P&gt;
&lt;P&gt;In this troubleshooting scenario, synchronization failures were ultimately traced to a combination of excessive Change Tracking backlog growth and Azure SQL Database resource-governance limits. By identifying the affected table, measuring backlog pressure using targeted T-SQL queries, evaluating governance events, and reinitializing synchronization state, synchronization was successfully restored and stabilized.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The key lesson is simple: proactive monitoring of Change Tracking metadata, synchronization backlog size, and Azure SQL workload health can prevent many Data Sync outages before they become business-impacting incidents.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 18 Jun 2026 21:01:11 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-support-blog/troubleshooting-azure-sql-data-sync-failures-caused-by-large/ba-p/4529337</guid>
      <dc:creator>Mohamed_Baioumy_MSFT</dc:creator>
      <dc:date>2026-06-18T21:01:11Z</dc:date>
    </item>
    <item>
      <title>Generally Available: Microsoft Entra Server Principals and Server Roles for Azure SQL Database</title>
      <link>https://techcommunity.microsoft.com/t5/azure-sql-blog/generally-available-microsoft-entra-server-principals-and-server/ba-p/4529326</link>
      <description>&lt;H1&gt;&lt;STRONG&gt;The problem we're solving&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P&gt;Previously, Microsoft Entra identities in Azure SQL Database could only be created as &lt;STRONG&gt;contained&lt;/STRONG&gt;&lt;STRONG&gt; database users&lt;/STRONG&gt; - principals scoped to a single database with no server-level presence. That meant:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;No granular server-level delegation. &lt;/STRONG&gt;You couldn't assign a server role such as ##MS_ServerStateReader## (to query DMVs across databases) or ##MS_LoginManager## (to manage logins) to an Entra principal. Only the Entra admin or a SQL login could perform these server-scoped tasks.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Per-database provisioning overhead. &lt;/STRONG&gt;Each Entra principal had to be created separately as a contained database user in every database that required access, with no way to inherit server-scoped permissions.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;No centralized “disable” switch. &lt;/STRONG&gt;Offboarding meant tracking down a contained database user in every database - there was no server-level login to disable.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;These gaps forced many teams to keep SQL authentication for administrative tasks, even when they wanted to go password-less with Entra.&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;What changes with GA&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P&gt;Microsoft Entra logins become&amp;nbsp;first-class server principals&amp;nbsp;in the logical&amp;nbsp;master&amp;nbsp;database, just like SQL logins. This capability has been in&amp;nbsp;public preview&amp;nbsp;on Azure SQL Database (and is already generally available on Azure SQL Managed Instance and SQL Server 2022+); with this release it reaches&amp;nbsp;&lt;STRONG&gt;general availability &lt;/STRONG&gt;on&lt;STRONG&gt; Azure SQL Database&lt;/STRONG&gt;, unlocking three things for&lt;STRONG&gt; production use&lt;/STRONG&gt;:&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;1. Server role assignment for Entra identities&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;Azure SQL Database's &lt;A href="https://learn.microsoft.com/azure/azure-sql/database/security-server-roles?view=azuresql" target="_blank"&gt;seven fixed server-level roles&lt;/A&gt; can be assigned to Entra server principals(logins). These roles cover database connectivity, database management, definition and security-definition reads, login management, and server-state read/manage.&lt;/P&gt;
&lt;P&gt;This means you can give your monitoring service principal read-only DMV access across all databases (##MS_ServerStateReader##), delegate login management to a security team member (##MS_LoginManager##), or let a DevOps app create databases (##MS_DatabaseManager##). All without SQL auth, all with Entra identities.&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;2. Server-wide login model&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;Instead of provisioning contained users independently in every database, you can create database users mapped to a server login (CREATE USER ... FROM LOGIN). These users inherit server-scoped permissions automatically. One login, many databases — managed from a single place.&lt;/P&gt;
&lt;P&gt;For the T-SQL syntax, see &lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-azure-ad-logins-tutorial?view=azuresql" target="_blank"&gt;Create and utilize Microsoft Entra server logins&lt;/A&gt;.&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;3. Centralized logins enable/disable&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;ALTER LOGIN [&lt;A href="mailto:user@contoso.com" target="_blank"&gt;user@contoso.com&lt;/A&gt;] DISABLE - one command blocks that identity from connecting to every database on the server. No more hunting down per-database users during an offboarding or incident response. When you re-enable the login, access is restored everywhere.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Note: &lt;/STRONG&gt;ALTER LOGIN ... DISABLE applies only to login-based users, not contained database users. It blocks &lt;STRONG&gt;new&lt;/STRONG&gt; connections only; existing sessions remain active until terminated with &lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-azure-ad-logins?view=azuresql" target="_blank"&gt;KILL&lt;/A&gt; if needed. For immediate effect, see &lt;A href="https://learn.microsoft.com/en-us/azure/azure-sql/database/authentication-azure-ad-logins?view=azuresql#disable-or-enable-a-login-using-alter-login" target="_blank"&gt;cache propagation&lt;/A&gt;. Microsoft Entra group logins are not supported; see the &lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-azure-ad-logins?view=azuresql" target="_blank"&gt;server principals documentation&lt;/A&gt; for alternatives.&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;What does this unlock for your organization&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P&gt;&lt;STRONG&gt;Ability to go password-less. &lt;/STRONG&gt;With server principals and roles now generally available, organizations can adopt &lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-azure-ad-only-authentication?view=azuresql" target="_blank"&gt;Entra-only authentication&lt;/A&gt; without a remaining server-level functionality gap. Entra logins bring parity with SQL logins closer, making it practical to disable SQL authentication entirely and using Entra as the sole authentication path.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Least-privilege administration.&lt;/STRONG&gt; Server-level roles simplify permission management by enabling customers to delegate common management and monitoring responsibilities without requiring admin privileges, enabling adherence to least privilege and separation of duties at scale, while making administration across databases on the same logical server much easier.&lt;STRONG&gt; &lt;/STRONG&gt;Server roles let you scope access precisely, previously, the only server-wide option for an Entra identity was the all-powerful Entra admin. Give your security auditors ##MS_SecurityDefinitionReader## role instead of 'db_owner'. Give your monitoring tools ##MS_ServerStateReader## instead of an over-privileged administrator role.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Zero-touch DevOps. &lt;/STRONG&gt;A service principal with ##MS_DatabaseManager## and ##MS_LoginManager## can automate database and user provisioning end-to-end. After the initial Entra admin bootstrap, no human needs to be in the loop for routine operations.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Faster incident response. &lt;/STRONG&gt;When a principal is compromised,&lt;A href="https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-login-transact-sql?view=azuresqldb-current#enable--disable-1" target="_blank"&gt; disable the login&lt;/A&gt; at the server level. New connections are blocked across all databases immediately - without needing to know which databases the user had access to. To cut off active sessions immediately, &lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-azure-ad-logins?view=azuresql#disable-or-enable-a-login-using-alter-login" target="_blank"&gt;flush the authentication caches&lt;/A&gt; and &lt;A href="https://learn.microsoft.com/sql/t-sql/language-elements/kill-transact-sql?view=azuresqldb-current" target="_blank"&gt;KILL existing sessions&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Geo-replica support. &lt;/STRONG&gt;Entra logins created on the primary server are automatically available on geo-replicas, with read-only access to replicated databases.&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;Key things to know&lt;/STRONG&gt;&lt;/H1&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Bootstrap requirements. &lt;/STRONG&gt;The &lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-aad-configure?view=azuresql" target="_blank"&gt;Microsoft Entra admin&lt;/A&gt; must create the first Entra login. After that, any Entra principal with ALTER ANY LOGIN or ##MS_LoginManager## membership can create additional logins.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Entra admin takes precedence. &lt;/STRONG&gt;If a principal is both the Entra admin and has a login, the admin permissions win. The login permissions have no additional effect.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Cache propagation. &lt;/STRONG&gt;Role membership and permission changes take effect on the next connection. For immediate effect, clear the auth cache with DBCC FLUSHAUTHCACHE and DBCC FREESYSTEMCACHE('TokenAndPermUserStore').&lt;/LI&gt;
&lt;LI&gt;EXECUTE AS LOGIN is not supported for Entra logins on Azure SQL Database (it is supported on &lt;A href="https://learn.microsoft.com/azure/azure-sql/managed-instance/aad-security-configure-tutorial?view=azuresql" target="_blank"&gt;Managed Instance&lt;/A&gt;).&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;&lt;STRONG&gt;Get started&lt;/STRONG&gt;&lt;/H1&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-aad-configure?view=azuresql" target="_blank"&gt;Configure a Microsoft Entra admin&lt;/A&gt; on your logical server&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-azure-ad-logins-tutorial?view=azuresql" target="_blank"&gt;Create your first Entra login and assign server roles&lt;/A&gt; (step-by-step tutorial)&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/azure/azure-sql/database/security-server-roles?view=azuresql" target="_blank"&gt;Understand the server roles and their permissions&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Consider enabling &lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-azure-ad-only-authentication?view=azuresql" target="_blank"&gt;Entra-only authentication&lt;/A&gt; to eliminate SQL auth entirely&lt;/LI&gt;
&lt;/OL&gt;
&lt;H1&gt;&lt;STRONG&gt;Ready to migrate from SQL Authentication?&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P&gt;If you're looking to move your existing SQL logins to Entra, check out &lt;A href="https://techcommunity.microsoft.com/blog/azuresqlblog/securing-azure-sql-database-with-microsoft-entra-password-less-authentication-mi/4470734/replies/4491908" target="_blank"&gt;Securing Azure SQL Database with Microsoft Entra password-less authentication - migration guide&lt;/A&gt;. It walks through the end-to-end journey from SQL auth to Entra, including how to identify SQL login dependencies, convert them to Entra principals, and enable Entra-only mode.&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;Learn more&lt;/STRONG&gt;&lt;/H1&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-azure-ad-logins?view=azuresql" target="_blank"&gt;Microsoft Entra server principals (logins)&lt;/A&gt; - full reference: syntax, permissions, limitations.&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/azure/azure-sql/database/security-server-roles?view=azuresql" target="_blank"&gt;Azure SQL Database server roles&lt;/A&gt; - role descriptions, permission matrix, examples.&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/azure/azure-sql/database/authentication-aad-overview?view=azuresql" target="_blank"&gt;Microsoft Entra authentication overview&lt;/A&gt; - how Entra auth works with Azure SQL.&lt;/LI&gt;
&lt;LI&gt;&lt;A href="https://learn.microsoft.com/azure/azure-sql/database/logins-create-manage?view=azuresql" target="_blank"&gt;Manage logins and users&lt;/A&gt; - login lifecycle management.&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Thu, 18 Jun 2026 20:27:39 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-sql-blog/generally-available-microsoft-entra-server-principals-and-server/ba-p/4529326</guid>
      <dc:creator>PDasgupta</dc:creator>
      <dc:date>2026-06-18T20:27:39Z</dc:date>
    </item>
    <item>
      <title>Scaling Write Throughput in Azure Database for MySQL Using Application-Level Sharding</title>
      <link>https://techcommunity.microsoft.com/t5/azure-database-for-mysql-blog/scaling-write-throughput-in-azure-database-for-mysql-using/ba-p/4527305</link>
      <description>&lt;P&gt;This blog post walks through scaling write throughput in Azure Database for MySQL using application level sharding. It starts with the why behind sharding and then builds a complete C# implementation that spreads writes across three Azure Database for MySQL Flexible Servers.&lt;/P&gt;
&lt;H4&gt;Why Shard in the First Place?&lt;/H4&gt;
&lt;P&gt;This post focuses specifically on scaling write throughput. A well-tuned single primary node can take you remarkably far, and techniques such as indexing strategies, write batching, redo log optimization, and vertical compute scaling each deliver real, lasting value. For many workloads, these optimizations are all you will ever need. That said, as write volume continues to grow, a single primary eventually approaches its practical capacity, and at that point the most durable way to keep scaling is to distribute the write workload across multiple primary instances. This architecture is what we call sharding.&lt;/P&gt;
&lt;P&gt;When you reach this inflection point, there are two primary patterns for managing multiple write nodes:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Proxy or Middleware Layer Sharding:&lt;/STRONG&gt; A sharding aware proxy sits between the application and a pool of Azure Database for MySQL instances, routing queries based on a shard key. While this abstracts the underlying topology from the application layer, it introduces an additional, complex component to operate, secure, scale, and patch.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Application Layer Sharding:&lt;/STRONG&gt; The application itself resolves the destination shard key and determines which of the N Azure Database for MySQL instances should receive a write before ever opening a database connection. Each backend target remains a completely standard, independent Azure Database for MySQL instance&lt;SPAN style="color: rgb(30, 30, 30);"&gt;.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;This post explores the second approach. The core appeal of application layer sharding is architectural simplicity: it introduces zero infrastructure overhead and eliminates an extra network hop. Every shard behaves exactly like a standalone instance, meaning your existing backup, restore, monitoring pipelines, and the Azure portal function seamlessly without modification. The explicit tradeoff is that you forgo cross shard joins and distributed transactions in exchange for absolute predictability and control over data access patterns.&amp;nbsp;&lt;/P&gt;
&lt;H4&gt;The Plan&lt;/H4&gt;
&lt;P&gt;We will build a small order management service that distributes its data across three Azure Database for MySQL instances that already exist. The application, written in C# on .NET 8, owns the partitioning logic.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The premise:&lt;/STRONG&gt; the three servers are already provisioned, the firewalls are configured, the network paths are established, and each server has its own administrative credentials. We are not provisioning infrastructure in this post. we are writing the application code that consumes it.&lt;/P&gt;
&lt;LI-CODE lang="powershell"&gt;mysql-shard-0.mysql.database.azure.com user: shard0_admin pwd: &amp;lt;secret-0&amp;gt;
mysql-shard-1.mysql.database.azure.com user: shard1_admin pwd: &amp;lt;secret-1&amp;gt;
mysql-shard-2.mysql.database.azure.com user: shard2_admin pwd: &amp;lt;secret-2&amp;gt;&lt;/LI-CODE&gt;
&lt;P&gt;Each server hosts an identical appdb database with the same schema:&lt;/P&gt;
&lt;LI-CODE lang="sql"&gt;CREATE TABLE users (
  user_id     BIGINT       NOT NULL PRIMARY KEY,
  email       VARCHAR(255) NOT NULL,
  created_at  DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
  UNIQUE KEY uq_email (email)
);

CREATE TABLE orders (
  order_id     BIGINT      NOT NULL PRIMARY KEY,
  user_id      BIGINT      NOT NULL,
  amount_cents INT         NOT NULL,
  created_at   DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP,
  KEY ix_user (user_id)
);&lt;/LI-CODE&gt;
&lt;P&gt;Two design decisions in this schema warrant explanation:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;No AUTO_INCREMENT for user_id or order_id. Two shards would otherwise generate the same value 42 independently. Instead, we assign identifiers in the application, using a scheme such as Snowflake, ULID, or UUIDv7.&lt;/LI&gt;
&lt;LI&gt;orders carries user_id, and we route by it. This is the single most important rule of sharding: choose a shard key that keeps related data colocated, so that the common queries remain on a single shard.&lt;/LI&gt;
&lt;/UL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;A note on UNIQUE KEY uq_email. A unique index enforces uniqueness only within a single physical shard. Because we route by user_id, two users with different IDs and the same email may land on different shards, and both inserts will succeed. If you require globally unique emails, two options exist: (a) maintain a separate email → user_id lookup table on a single "directory" server and write to it first within an idempotent flow, or (b) shard the users table by a hash of email instead. We retain user_id routing throughout this post because it is the correct choice for orders, and we treat per shard email uniqueness as a best effort guard rather than a hard global invariant.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H4&gt;How the Partitioning Works&lt;/H4&gt;
&lt;P&gt;The naive approach to sharding is shard = hash(key) % N. This works until you need to add a fourth server, at which point roughly 75% of your data must move. In any system of meaningful size, that is prohibitively expensive.&lt;/P&gt;
&lt;P&gt;The established solution is virtual buckets. You hash the key into a large, fixed bucket space (here, 1024), then map buckets to physical shards. When you add capacity, you relocate only buckets; you never rehash the entire dataset.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;In production, the bucket_to_shard_map typically resides in a system such as Azure App Configuration or etcd, so that you can rebalance without redeploying. For this post, we keep it as an in-memory array seeded at startup, which is straightforward to replace later.&lt;/P&gt;
&lt;H4&gt;The Project&lt;/H4&gt;
&lt;LI-CODE lang="bash"&gt;ShardingDemo/
├── ShardingDemo.csproj
├── appsettings.json
├── Models.cs
├── ShardRouter.cs
├── UserRepository.cs
└── Program.cs&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;ShardingDemo.csproj&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang="xml"&gt;&amp;lt;Project Sdk="Microsoft.NET.Sdk"&amp;gt;
  &amp;lt;PropertyGroup&amp;gt;
    &amp;lt;OutputType&amp;gt;Exe&amp;lt;/OutputType&amp;gt;
    &amp;lt;TargetFramework&amp;gt;net8.0&amp;lt;/TargetFramework&amp;gt;
    &amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;
    &amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;
  &amp;lt;/PropertyGroup&amp;gt;
  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;PackageReference Include="MySqlConnector" Version="2.6.0" /&amp;gt;
    &amp;lt;PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /&amp;gt;
    &amp;lt;PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0" /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;
  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;Content Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;
&amp;lt;/Project&amp;gt;&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;appsettings.json&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Shards is an ordered list, and a shard's position in the array is its logical ID.&lt;/P&gt;
&lt;LI-CODE lang="json"&gt;{
  "Shards": [
    {
      "Host": "mysql-shard-0.mysql.database.azure.com",
      "Database": "appdb",
      "User": "shard0_admin",
      "Password": "REPLACE_ME_0"
    },
    {
      "Host": "mysql-shard-1.mysql.database.azure.com",
      "Database": "appdb",
      "User": "shard1_admin",
      "Password": "REPLACE_ME_1"
    },
    {
      "Host": "mysql-shard-2.mysql.database.azure.com",
      "Database": "appdb",
      "User": "shard2_admin",
      "Password": "REPLACE_ME_2"
    }
  ]
}&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Models.cs&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;namespace ShardingDemo;

public sealed record User(long UserId, string Email, DateTime CreatedAt);

public sealed record Order(long OrderId, long UserId, int AmountCents, DateTime CreatedAt);

public sealed class ShardConfig
{
    public required string Host { get; init; }
    public required string Database { get; init; }
    public required string User { get; init; }
    public required string Password { get; init; }
}&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;ShardRouter.cs&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;using System.Security.Cryptography;
using System.Text;
using MySqlConnector;

namespace ShardingDemo;

public sealed class Shard : IAsyncDisposable
{
    public int Id { get; }
    public MySqlDataSource DataSource { get; }

    public Shard(int id, ShardConfig cfg)
    {
        Id = id;

        var csb = new MySqlConnectionStringBuilder
        {
            Server                = cfg.Host,
            Port                  = 3306,
            Database              = cfg.Database,
            UserID                = cfg.User,
            Password              = cfg.Password,
            SslMode               = MySqlSslMode.Required, 
            Pooling               = true,
            MinimumPoolSize       = 2,
            MaximumPoolSize       = 100,
            ConnectionTimeout     = 10,
            DefaultCommandTimeout = 30,
        };

        DataSource = new MySqlDataSourceBuilder(csb.ConnectionString).Build();
    }

    public ValueTask DisposeAsync() =&amp;gt; DataSource.DisposeAsync();
}

public sealed class ShardRouter : IAsyncDisposable
{
    private const int VirtualBuckets = 1024;
    private readonly IReadOnlyList&amp;lt;Shard&amp;gt; _shards;
    private readonly int[] _bucketToShardId;

    public ShardRouter(IEnumerable&amp;lt;ShardConfig&amp;gt; configs)
    {
        _shards = configs.Select((c, i) =&amp;gt; new Shard(i, c)).ToList();

        // Even distribution. Replace with a map loaded from your control plane for live rebalancing.
        _bucketToShardId = new int[VirtualBuckets];
        for (int i = 0; i &amp;lt; VirtualBuckets; i++)
            _bucketToShardId[i] = i % _shards.Count;
    }

    public IReadOnlyList&amp;lt;Shard&amp;gt; AllShards =&amp;gt; _shards;

    private static int BucketFor(long shardKey)
    {
        byte[] hash = MD5.HashData(Encoding.ASCII.GetBytes(shardKey.ToString()));
        // Use the first byte pair as an unsigned value, then map it into the bucket space.
        int value = (hash[0] &amp;lt;&amp;lt; 8) | hash[1];
        return value % VirtualBuckets;
    }

    public Shard ShardForKey(long shardKey)
    {
        int bucket = BucketFor(shardKey);
        return _shards[_bucketToShardId[bucket]];
    }

    public async ValueTask DisposeAsync()
    {
        foreach (var s in _shards) await s.DisposeAsync();
    }
}&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;UserRepository.cs&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Observe that every per user method calls ShardForKey(userId), even when inserting an order. This is the colocation rule at work. An order and its owning user always reside on the same shard, so queries for a single user only ever reach one shard. Only the cross-shard aggregate (TotalRevenueCentsAsync) must fan out.&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;using MySqlConnector;

namespace ShardingDemo;

public sealed class UserRepository
{
    private readonly ShardRouter _router;

    public UserRepository(ShardRouter router)
    {
        _router = router;
    }

    public async Task CreateUserAsync(long userId, string email, CancellationToken ct = default)
    {
        var shard = _router.ShardForKey(userId);
        await using var conn = await shard.DataSource.OpenConnectionAsync(ct);
        await using var cmd = conn.CreateCommand();
        cmd.CommandText = "INSERT INTO users (user_id, email) VALUES (@id, &lt;a href="javascript:void(0)" data-lia-user-mentions="" data-lia-user-uid="2770480" data-lia-user-login="Email" class="lia-mention lia-mention-user"&gt;Email&lt;/a&gt;)";
        cmd.Parameters.AddWithValue("@id", userId);
        cmd.Parameters.AddWithValue("@email", email);
        await cmd.ExecuteNonQueryAsync(ct);
    }

    public async Task&amp;lt;User?&amp;gt; GetUserAsync(long userId, CancellationToken ct = default)
    {
        var shard = _router.ShardForKey(userId);
        await using var conn = await shard.DataSource.OpenConnectionAsync(ct);
        await using var cmd = conn.CreateCommand();
        cmd.CommandText = "SELECT user_id, email, created_at FROM users WHERE user_id = &lt;a href="javascript:void(0)" data-lia-user-mentions="" data-lia-user-uid="3207388" data-lia-user-login="ID" class="lia-mention lia-mention-user"&gt;ID&lt;/a&gt;";
        cmd.Parameters.AddWithValue("@id", userId);

        await using var reader = await cmd.ExecuteReaderAsync(ct);
        if (!await reader.ReadAsync(ct)) return null;
        return new User(reader.GetInt64(0), reader.GetString(1), reader.GetDateTime(2));
    }

    public async Task AddOrderAsync(long orderId, long userId, int amountCents, CancellationToken ct = default)
    {
        // Routed by user_id, so orders colocate with their owning user.
        var shard = _router.ShardForKey(userId);
        await using var conn = await shard.DataSource.OpenConnectionAsync(ct);
        await using var cmd = conn.CreateCommand();
        cmd.CommandText = """
            INSERT INTO orders (order_id, user_id, amount_cents)
            VALUES (@oid, @uid, &lt;a href="javascript:void(0)" data-lia-user-mentions="" data-lia-user-uid="3301378" data-lia-user-login="amt" class="lia-mention lia-mention-user"&gt;amt&lt;/a&gt;)
            """;
        cmd.Parameters.AddWithValue("@oid", orderId);
        cmd.Parameters.AddWithValue("@uid", userId);
        cmd.Parameters.AddWithValue("@amt", amountCents);
        await cmd.ExecuteNonQueryAsync(ct);
    }

    public async Task&amp;lt;IReadOnlyList&amp;lt;Order&amp;gt;&amp;gt; GetOrdersForUserAsync(long userId, CancellationToken ct = default)
    {
        var shard = _router.ShardForKey(userId);
        await using var conn = await shard.DataSource.OpenConnectionAsync(ct);
        await using var cmd = conn.CreateCommand();
        cmd.CommandText = """
            SELECT order_id, user_id, amount_cents, created_at
            FROM orders WHERE user_id = @uid
            """;
        cmd.Parameters.AddWithValue("@uid", userId);

        var list = new List&amp;lt;Order&amp;gt;();
        await using var reader = await cmd.ExecuteReaderAsync(ct);
        while (await reader.ReadAsync(ct))
        {
            list.Add(new Order(
                reader.GetInt64(0), reader.GetInt64(1),
                reader.GetInt32(2), reader.GetDateTime(3)));
        }
        return list;
    }

    /// &amp;lt;summary&amp;gt;Cross shard fanout.&amp;lt;/summary&amp;gt;
    public async Task&amp;lt;long&amp;gt; TotalRevenueCentsAsync(CancellationToken ct = default)
    {
        var tasks = _router.AllShards.Select(async shard =&amp;gt;
        {
            await using var conn = await shard.DataSource.OpenConnectionAsync(ct);
            await using var cmd = conn.CreateCommand();
            cmd.CommandText = "SELECT COALESCE(SUM(amount_cents), 0) FROM orders";
            var result = await cmd.ExecuteScalarAsync(ct);
            return Convert.ToInt64(result);
        });

        var perShard = await Task.WhenAll(tasks);
        return perShard.Sum();
    }
}&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;BR /&gt;Program.cs&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ShardingDemo;

var builder = Host.CreateApplicationBuilder(args);

// Bind Shards:[] from appsettings.json (override with user-secrets / env vars / Key Vault)
var shardConfigs = builder.Configuration
    .GetSection("Shards")
    .Get&amp;lt;List&amp;lt;ShardConfig&amp;gt;&amp;gt;()
    ?? throw new InvalidOperationException("No 'Shards' section configured.");

if (shardConfigs.Count == 0)
    throw new InvalidOperationException("At least one shard must be configured.");

builder.Services.AddSingleton(_ =&amp;gt; new ShardRouter(shardConfigs));
builder.Services.AddSingleton&amp;lt;UserRepository&amp;gt;();

using var host = builder.Build();

var repo   = host.Services.GetRequiredService&amp;lt;UserRepository&amp;gt;();
var router = host.Services.GetRequiredService&amp;lt;ShardRouter&amp;gt;();

(long Id, string Email)[] users =
{
    (1001, "ada@example.com"),
    (2002, "linus@example.com"),
    (3003, "grace@example.com"),
    (4004, "alan@example.com"),
};

foreach (var (id, email) in users)
{
    await repo.CreateUserAsync(id, email);
    Console.WriteLine($"user {id} -&amp;gt; shard {router.ShardForKey(id).Id}");
}

await repo.AddOrderAsync(orderId: 9001, userId: 1001, amountCents: 4999);
await repo.AddOrderAsync(orderId: 9002, userId: 1001, amountCents: 1299);
await repo.AddOrderAsync(orderId: 9003, userId: 2002, amountCents: 8800);

Console.WriteLine($"\nAda: {await repo.GetUserAsync(1001)}");
Console.WriteLine($"Ada's orders: {(await repo.GetOrdersForUserAsync(1001)).Count}");
Console.WriteLine($"\nTotal revenue across 3 shards: " +
                  $"${await repo.TotalRevenueCentsAsync() / 100m:F2}");

await router.DisposeAsync();&lt;/LI-CODE&gt;
&lt;H4&gt;Tracing One Request End to End&lt;/H4&gt;
&lt;P&gt;Consider GetOrdersForUserAsync(1001):&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;ShardForKey(1001) → MD5("1001") → first two bytes as a number → % 1024 → a bucket in the range 0..1023.&lt;/LI&gt;
&lt;LI&gt;bucket % 3 → a physical shard → for example mysql-shard-2.mysql.database.azure.com.&lt;/LI&gt;
&lt;LI&gt;The MySqlDataSource provides a pooled, TLS encrypted connection authenticated as shard2_admin.&lt;/LI&gt;
&lt;LI&gt;The query runs against shard 2's local ix_user index, with no fan out and at single server speed.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;Every call with userId = 1001, whether GetUser, AddOrder, or GetOrdersForUser, lands on the same shard. That is why orders JOIN users ON orders.user_id = users.user_id WHERE user_id = 1001 executes within a single shard, with no cross-shard traffic.&lt;/P&gt;
&lt;H4&gt;Conclusion&lt;/H4&gt;
&lt;P data-line="418"&gt;The essential point is this. Once a single primary can no longer absorb your write load, sharding becomes a durable answer, and implementing it at the application layer keeps every part of the system explicit and comprehensible.&lt;/P&gt;
&lt;P data-line="420"&gt;When write volume or dataset size outgrows a single primary, application layer sharding provides several benefits.&lt;/P&gt;
&lt;UL data-line="422"&gt;
&lt;LI data-line="422"&gt;N independent Azure Database for MySQL instances, each absorbing 1/N of the write traffic.&lt;/LI&gt;
&lt;LI data-line="423"&gt;Queries by user that remain on a single shard and behave like an ordinary, modestly sized database.&lt;/LI&gt;
&lt;LI data-line="424"&gt;A bucket map approach that allows you to add a fourth, fifth, or Nth shard later by relocating slices of data rather than rehashing the entire dataset.&lt;/LI&gt;
&lt;LI data-line="425"&gt;A failure of one shard that affects&amp;nbsp;1/N&amp;nbsp;of your users rather than all of them.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-line="427"&gt;These benefits come at a genuine cost. You must generate identifiers in the application, global uniqueness requires a secondary lookup table, and aggregate queries fan out across shards. A cross shard write, one that must atomically update data on two different shards, can no longer rely on a single database transaction. Instead it needs an orchestrated sequence of local transactions, where each step carries a compensating action that undoes its effect if a later step fails. None of these are insurmountable. They are simply responsibilities you now assume.&lt;/P&gt;
&lt;P data-line="429"&gt;Sharding is a deliberate step to take only once a single primary has genuinely exhausted its write headroom. When you reach that point, the implementation in this post is a representative blueprint.&lt;/P&gt;
&lt;H4&gt;Stay Connected&lt;/H4&gt;
&lt;P&gt;We welcome your feedback and invite you to share your experiences or suggestions at&amp;nbsp;&lt;A href="mailto:AskAzureDBforMySQL@service.microsoft.com" target="_blank"&gt;AskAzureDBforMySQL@service.microsoft.com&lt;/A&gt;&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thank you for choosing Azure Database for MySQL!&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 18 Jun 2026 16:16:06 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-database-for-mysql-blog/scaling-write-throughput-in-azure-database-for-mysql-using/ba-p/4527305</guid>
      <dc:creator>ramkumarchan</dc:creator>
      <dc:date>2026-06-18T16:16:06Z</dc:date>
    </item>
  </channel>
</rss>

