<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Striim - Medium]]></title>
        <description><![CDATA[Intelligent Integration with data streaming, change data capture, and AI pipelines - Medium]]></description>
        <link>https://medium.com/striim?source=rss----833deda32774---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Striim - Medium</title>
            <link>https://medium.com/striim?source=rss----833deda32774---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 22 May 2026 06:59:25 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/striim" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Beyond Materialized Views: Using DuckDB for In-Process Columnar Caching]]></title>
            <link>https://medium.com/striim/beyond-materialized-views-using-duckdb-for-in-process-columnar-caching-98b8387b8568?source=rss----833deda32774---4</link>
            <guid isPermaLink="false">https://medium.com/p/98b8387b8568</guid>
            <category><![CDATA[duckdb]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[database]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[sql]]></category>
            <dc:creator><![CDATA[John Kutay]]></dc:creator>
            <pubDate>Wed, 02 Apr 2025 17:35:33 GMT</pubDate>
            <atom:updated>2025-04-02T17:38:27.830Z</atom:updated>
            <content:encoded><![CDATA[<p>Written by John Kutay (Director of Product &amp; Engineering at Striim) and <a href="https://medium.com/u/4135b41f7166">Kim</a> Dang (Senior Software Engineer at Striim)</p><p><strong>In this post we will talk about using DuckDB as the operational analytics store for the control plane of </strong><a href="https://signup-developer.striim.com/"><strong>Striim Developer</strong></a><strong> — a serverless Stream Processing and Change Data Capture service. By moving analytical queries from PostgreSQL to an in-process cache in DuckDB, we measured 5–10x performance improvement with zero additional infrastructure or cost.</strong></p><p>In this post, we explore how DuckDB was integrated as the analytical backend for the control plane of <strong>Striim Developer</strong> — a serverless Stream Processing and Change Data Capture (CDC) service. The Striim Developer Control Plane handles critical tasks such as managing tenant assignments, monitoring free-tier usage thresholds, orchestrating asynchronous jobs, and triggering operational alerts. Initially, this control plane relied on direct queries to PostgreSQL, which serves as the metadata repository. However, this design presented challenges in maintaining performance and meeting SLAs without inflating the cost of offering a free-tier service.</p><p>For example, when usage exceeds capacity for an individual tenant, we need to alert and orchestrate a response immediately. Yet, our previous implementation — based on periodic analytical jobs — was constrained to 15–20-minute intervals, requiring PostgreSQL query optimization and materialized views to perform better. This latency posed a significant bottleneck for operational analytics in a serverless platform that necessitates near real-time responses.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/766/1*fJvaZS9pM95Vy_3GzTyT5A.png" /></figure><p>After evaluating alternatives, we adopted DuckDB as an in-process, columnar caching layer. This decision was driven by DuckDB’s balance of performance, simplicity, and minimal overhead, addressing our need for high-frequency analytics while offloading PostgreSQL. In this post, we detail the challenges, implementation, and benefits of this architecture and discuss whether this approach qualifies as Hybrid Transactional Analytical Processing (spoiler: it’s not, and I’ll explain why).</p><h3>The Challenge: Optimizing Operational Analytical Workloads</h3><p>The Striim Developer control plane frequently queries PostgreSQL to perform:</p><ul><li>Aggregated usage calculations</li><li>Threshold monitoring for user and tenant consumption.</li><li>Operational alerting</li><li>Asynchronous calls to cloud services that trigger workflows (in-product messages, cloud resource management)</li></ul><p>These queries are analytical and involve scanning and joining usage data normalized across many tables, leading to slower execution times and increased load on our PostgreSQL instance. However our ability to frequently run this operation was bottlenecked by disk-bound operations to query PostgreSQL. We require these analytical jobs to run as frequently as possible to execute to respond to scenarios like resource over-utilization or exceeding usage thresholds.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ueyRs2vJFJZF81yvasskJg.png" /><figcaption>Database Application Behind Striim Developer</figcaption></figure><h3>A Word About Buffer Caches</h3><p>Before we went down this rabbit hole, we of course considered the stark reality that database buffer caches exist. And our AWS-managed database has some higher level interfaces to manage the buffer cache that adds some convenience for DBAs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*dj90ujb16hE0ESsN" /></figure><p>PostgreSQL’s buffer cache can improve query performance by storing frequently accessed data pages in memory, minimizing disk I/O. While tuning shared_buffers and leveraging tools like pg_prewarm could help keep critical data in cache, this approach is inherently reactive. The cache is populated dynamically based on usage patterns, which means frequent refreshes or large scans may still involve costly disk reads. Additionally, tuning buffer sizes in a multi-tenant environment adds complexity and can strain memory resources shared with other PostgreSQL processes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dG0Gq1TYfMXLRygU" /></figure><p>It’s also important to note that the Striim application is the software most frequently accessing the PostgreSQL metadata repository with frequent, write-heavy operations that naturally dominate the PostgreSQL buffer cache. It handles critical transactional operations like updating metering metrics and managing the Striim component DDL as streaming applications are implemented by users. This competition for cache space means analytical queries, such as aggregations on usage data, are less likely to benefit from cached pages, resulting in increased disk I/O and slower performance. Given this dynamic, relying solely on PostgreSQL’s buffer cache to optimize both OLTP and OLAP workloads would have been inefficient, reinforcing our decision to offload analytical queries to DuckDB. By decoupling these workloads, we ensured that transactional operations in PostgreSQL remain fast while analytical workloads benefit from DuckDB’s optimized in-memory columnar engine.</p><p>Materialized views provide precomputed query results and might seem like a fit for aggregating our usage data. However, refreshing MVs frequently (e.g., every minute for usage data) imposes significant write overhead on the database. Even with REFRESH CONCURRENTLY, the performance cost grows as data scales. Managing MVs for our multi-tenant architecture, with differing refresh cadences for namespaces, applications, and usage data, would have added operational burden.</p><h3>Why Not Materialized Views?</h3><p>Materialized views in PostgreSQL were an option we considered for caching precomputed results. However we had to address the following variables:</p><ol><li>Analytical Queries: Our queries involve dynamic aggregations, joins and filters on frequently changing usage data, which are cumbersome to maintain with materialized views. Our team prefers working with imperative languages for cache maintenance logic, thus maintaining the views in PostgreSQL was not ideal.</li><li>Infrastructure Overhead: Refreshing materialized views for frequently updated data (e.g., usage metrics) every minute would increase PostgreSQL’s load rather than alleviate it. PostgreSQL read replicas would add more complexity and infrastructure overhead without obvious performance benefits.</li><li>Limited Flexibility: PostgreSQL materialized views speed up complex queries but require manual refreshes, lacking incremental updates for frequent changes.</li></ol><p>The ideal solution for us would require no additional infrastructure (replicas, database cores, storage) at the current size of the workload while allowing us to tightly control the cache maintenance logic in Python — the language we use in our Control Plane.</p><h3>Our Solution: DuckDB as a OLAP Cache with PostgreSQL Extension</h3><p>DuckDB, a lightweight, in-process SQL analytics engine, provided the perfect middle ground between raw PostgreSQL queries and materialized views. Here’s why:</p><ul><li>High Performance for Analytical Workloads: DuckDB is automatically optimized for analytical and columnar processing, offering built-in performance gains for our use case.</li><li>Simple Integration with Python: Its seamless embedded Python API made it easy to implement into our existing control logic without additional infrastructure.</li><li>Dynamic Caching: We cache infrequently changing data (e.g., users, tenants) every 24 hours and refresh frequently changing data (e.g., usage metrics) every minute. DuckDB makes this easy to manage with minimal code.</li><li><a href="https://duckdb.org/docs/extensions/postgres.html">PostgreSQL Extension</a>: DuckDB’s native extension lets us execute PostgreSQL queries to fetch data within the DuckDB runtime</li></ul><p>DuckDB’s in-process instantiation made this insanely easy to implement in the control plane application…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qyloqlETWyWF_IDmTVTVOQ.png" /><figcaption>Instantiating DuckDB In-Memory</figcaption></figure><h3>Implementation Overview</h3><p><strong>Data Refresh Pipeline:</strong></p><ul><li>Daily Refresh: Less frequently updated metadata loaded into DuckDB every 24 hours.</li><li>Minute-Level Refresh: Frequently queried usage metrics are updated every minute.</li></ul><p><strong>Query Execution:</strong></p><ul><li>Operational tasks and alerts query the DuckDB cache for aggregated results.</li><li>Async cloud operations work with fresh, fast data.</li><li>PostgreSQL remains the source of truth, used only for updates and less frequent transactional queries.</li></ul><p>The architecture ensures that DuckDB serves as a high-speed cache for read-heavy operations, while PostgreSQL is offloaded from expensive analytical workloads.</p><h3>Performance Benchmarks</h3><p>Our performance benchmarks highlight the substantial improvements gained by integrating DuckDB into our architecture. A Striim Controller instance operates on 4 vCPUs and 7 GB of RAM, emphasizing efficiency in constrained environments. Below are the results from the latest test runs:</p><h4>Results with DuckDB Caching:</h4><ul><li>Throughput of jobs: Improved from 3.95 to 11.71 tasks/sec (cached + PostgreSQL replication) and up to 11.71 tasks/sec (full analytical query caching).</li><li>Average Latency: Consistent at 0.19–0.2 seconds per task.</li><li>Memory Usage: Stabilized at ~141 MB (cached namespace scenario) and ~120 MB (full analytical query caching).</li><li>Execution Time: Reduced to as low as .8 seconds per job.</li></ul><p>To ensure the accuracy and consistency of our benchmarks, we conducted multiple runs for each configuration — No Caching, Caching data with <a href="https://www.sqlalchemy.org/">SQLAlchemy</a> into native python data structures, and Caching with DuckDB — with explicit cache warming captured by mocking multiple runs from cold to hot cache scenarios. By allowing the cache to warm up, we ensured that frequently accessed data was preloaded, highlighting the true impact of caching mechanisms on throughput, execution time, and memory stabilization under high-concurrency workloads. This approach provided a clear view of how caching progressively improves performance in real-world scenarios and DuckDB provides built-in high performance analytical queries.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GpY_NJlbxZXggi9DpH9tQg.png" /></figure><p>Key Takeaways:</p><ol><li>5–10x Execution Time Reduction: Analytical workloads experienced dramatic speed-ups without impacting transactional performance.</li><li>High-Throughput Performance: Throughput improved significantly for tasks, maintaining low latency.</li><li>Zero Additional Infrastructure Costs: DuckDB runs in-process, avoiding the need for more servers or storage.</li><li>DuckDB-based caching with PostgreSQL extension was faster than native python solution</li></ol><p>This setup is designed for the price-performance balance that makes our Striim Developer offering scalable while remaining cost-effective. While scaling CPU and RAM might have solved the problem, this approach aligns with our mission to deliver generous free-tier usage without compromising on performance.</p><h3>Memory management</h3><p>While performance improved by 5–10x, we need to account for the increased memory usage and how that may scale over time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2aK-cKyF_uaJA3-6hxpXOw.png" /><figcaption>Memory Management &amp; Cache Eviction Strategy</figcaption></figure><p>We will monitor and log our cache hit rate over time while managing a simple heuristic based memory management process. Rather than using fixed memory limits, we designed a percentage-based approach where the cache can use up to 75% of system RAM total, with individual caches limited to 25%. This provides flexibility across different deployment environments while preventing memory exhaustion. We designed an LRU (Least Recently Used) eviction strategy that automatically removes older entries when memory limits are approached, along with a fallback mechanism to persist data to disk if needed. The cache monitors system memory usage and can trigger eviction or disk fallback (DuckDB PG extension queries) automatically.</p><h3>Why DuckDB Cache is Superior</h3><p>Compared to materialized views or other caching alternatives (e.g., Redis, Native Python Data Structures), DuckDB offers:</p><p><strong>Performance Gains Without Complexity:</strong></p><ul><li>No additional servers, clusters, or infrastructure were required.</li><li>No need to change or provision additional components in PostgreSQL.</li><li>All cache maintenance logic implemented in python</li></ul><p><strong>Flexibility and Simplicity:</strong></p><ul><li>Easy to define and refresh datasets based on different refresh cadences (e.g., 24 hours for static data, 1 minute for dynamic data).</li><li>Dynamic and on-the-fly SQL queries supported without materialized view limitations.</li><li>SQL interface for aggregations and analytical queries</li></ul><p><strong>Cost-Effective Scaling:</strong></p><ul><li>DuckDB runs within the existing Python application with optimized query execution and memory management, avoiding the need for external caching systems or compute resources at the size of the current workload.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zkd1CHwAR5kIVYZS-TZJqg.png" /></figure><h3>So… is this HTAP?</h3><p>While this approach leverages DuckDB’s fast analytical performance and offers many benefits that you would get from an HTAP system, it doesn’t qualify as full HTAP in my mind. HTAP systems unify OLTP and OLAP workloads within a single platform, providing real-time analytics on live transactional data, an example being <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/inmem/in-memory-column-store-architecture.html#GUID-EEA265EE-8FBA-4457-8C3F-315B9EEA2224">Oracle’s embedded column store</a>. In our case, PostgreSQL handles transactions, while DuckDB serves as a pluggable, in-memory column store for read-heavy analytical queries. DuckDB PostgreSQL Extension and our controller logic glues OLTP and OLAP together by copying the data. This separation allows us to periodically refresh cached data without adding complexity or infrastructure.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JxtR8iz7dFMVNtdXgkNIhw.png" /></figure><p><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/inmem/in-memory-column-store-architecture.html#GUID-93893C03-EEBD-46E5-8C08-7E120EB643A6">Source: Oracle</a></p><p>Hybrid transactional/analytical processing (HTAP) architectures integrate OLTP (transactional) and OLAP (analytical) workloads in a single system, eliminating the need for ETL pipelines, reducing data duplication, and offering real-time consistency. Oracle’s In-Memory Column Store is a sophisticated example of HTAP, maintaining dual-format storage — data resides simultaneously in a row format (optimized for OLTP) in the buffer cache and in a columnar format (optimized for OLAP) in memory. Oracle ensures transactional consistency by synchronizing updates between the row and column formats using metadata and transaction journals. This allows analytic and transactional queries to run on the same dataset seamlessly, without duplication or delays.</p><p>Our DuckDB PostgreSQL extension approach, while not HTAP, delivers basic hybrid OLAP functionality by enabling analytical queries to run in a high-performance columnar format, separate from the OLTP workload in PostgreSQL. Unlike Oracle’s dual-format architecture, this solution doesn’t maintain real-time consistency or simultaneous access to row and columnar data. However, it provides us with a lightweight, pluggable option for analytical workloads with minimal setup. Given these are analytical operational queries, we can live without transactional consistency. DuckDB’s columnar processing and in-memory execution make it ideal for scenarios where transactional workloads can tolerate slightly delayed analytics without requiring a full HTAP system.</p><p><strong>DuckDB works great as a modular, lightweight columnar engine that complements any database, delivering OLAP-like performance without needing a full HTAP database.</strong></p><h3>Scaling Considerations</h3><p>While our DuckDB caching layer delivers excellent performance for individual clusters, you might wonder how we’ll scale as Striim Developer adoption grows. The answer lies in horizontal partitioning — we’ll distribute users across multiple independent Striim clusters, each with its own PostgreSQL database and controller instance running our DuckDB cache.</p><p>We leverage <a href="https://www.striim.com/docs/en/managing-deployment-groups.html">Striim Deployment Groups</a> (DG) to create separation between logical and physical resources. A Deployment Group represents some unit of compute that a Striim pipeline can be deployed to on one or multiple nodes. That unit can be a single server, a shared pool, or a dedicated multi-node cluster of EC2 instances in AWS. Each user has an assigned DG that maps to some physical resource. The physical resources can be scaled up vertically or horizontally, but the DG’s association to these resources remains the same. When a Striim app is deployed to a DG, it will take whatever compute is associated with it.</p><p>A global routing layer using consistent hashing will direct users to their assigned cluster based on their tenant ID, with the ability to dynamically add new clusters as needed. This approach is particularly clean because Striim Developer users operate independently, meaning there’s no cross-user data sharing or multi-tenant querying that would complicate the architecture. The beauty of this design is that our DuckDB caching layer requires no modifications — it continues to work as designed within each cluster’s scope, while we achieve horizontal scale through simple user partitioning.</p><h3>Conclusion</h3><p>By adopting DuckDB as a caching layer for our PostgreSQL database, we achieved a substantial improvement in performance while simplifying our architecture. This approach highlights the power of embedding lightweight, high-performance solutions like DuckDB into existing systems. For anyone dealing with analytical workloads on operational data, DuckDB offers an elegant, cost-effective alternative to materialized views or external caching systems.</p><p>The best part of this? It was easy to implement thanks to DuckDB’s simplicity. Zero infrastructure changes. Zero additional spend. Just some well-written Python and DuckDB PostgreSQL Extension.</p><p>These types of performance improvements allow us to provide <a href="https://signup-developer.striim.com/">Striim Developer</a> as a free, serverless experience for data engineers to explore Striim’s data movement and stream processing capabilities.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=98b8387b8568" width="1" height="1" alt=""><hr><p><a href="https://medium.com/striim/beyond-materialized-views-using-duckdb-for-in-process-columnar-caching-98b8387b8568">Beyond Materialized Views: Using DuckDB for In-Process Columnar Caching</a> was originally published in <a href="https://medium.com/striim">Striim</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Microsoft Fabric Open Mirroring — Mirror once query anywhere — Striim]]></title>
            <link>https://medium.com/striim/microsoft-fabric-open-mirroring-mirror-once-query-anywhere-striim-29bfc7f2c01e?source=rss----833deda32774---4</link>
            <guid isPermaLink="false">https://medium.com/p/29bfc7f2c01e</guid>
            <category><![CDATA[data-lakehouse]]></category>
            <category><![CDATA[mirroring]]></category>
            <category><![CDATA[fabric]]></category>
            <category><![CDATA[delta-lake]]></category>
            <category><![CDATA[onelake]]></category>
            <dc:creator><![CDATA[karthikeyan G]]></dc:creator>
            <pubDate>Sun, 30 Mar 2025 23:58:19 GMT</pubDate>
            <atom:updated>2025-03-30T23:58:18.920Z</atom:updated>
            <content:encoded><![CDATA[<h3>Open Mirroring with Microsoft Fabric: Mirror Once, Query Anywhere with Striim</h3><h4>Exploring Microsoft Fabric Open Mirroring: Striim’s SQL2Fabric-Mirroring Integration, Use Cases, and Data Access and Interoperability across DuckDB, Databricks, Snowflake, Spark Engines, and More</h4><h4>Table Of Contents</h4><p>∘ <a href="#9709">Audience </a><br>∘ <a href="#1358">How Microsoft Fabric Open Mirroring Works</a><br>∘ <a href="#b63f">What is the Cost Structure?</a><br>∘ <a href="#5380">What Are the Pain Points?</a><br>∘ <a href="#9cb1">Open mirroring — powered by Striim</a><br>∘ <a href="#3288">Use Cases after mirroring</a><br> ∘ <a href="#51b4">Access data within fabric ecosystem</a><br> ∘ <a href="#e947">Access from Snowflake</a><br> ∘ <a href="#a82d">Access from Databricks</a><br> ∘ <a href="#13b2">Access from Spark Engines </a><br> ∘ <a href="#bc5c">Access from DuckDB</a><br> ∘ <a href="#aefc">Access from Google BigQuery </a><br>∘ <a href="#5870">Conclusion :</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6qwzdOmHz-j3dki-" /></figure><h4>Audience</h4><ul><li>This blog is aimed at individuals with interest in the <strong>Microsoft Fabric ecosystem and general Data Engineering experience.</strong></li></ul><h4>How Microsoft Fabric Open Mirroring Works</h4><p><a href="https://learn.microsoft.com/en-us/fabric/database/mirrored-database/open-mirroring"><strong>Microsoft Fabric Open Mirroring</strong></a> is a powerful feature that allows organizations to seamlessly replicate change data from multiple sources into <strong>OneLake</strong>. This functionality enables client applications to write both change data and initial load data from various source systems — such as databases, data warehouses, or files — directly into a designated <strong>Landing Zone</strong> in <strong>Parquet</strong> file format. Once the data is stored in Parquet, the <strong>Fabric Replicator Service</strong> processes the files and converts them into <strong>DeltaLake</strong> format within <strong>OneLake</strong>. These Delta tables are then readily accessible by applications such as <strong>Power BI</strong>, <strong>SQL Analytics</strong>, and other query engines that work with OneLake.</p><p>Designed with interoperability and scalability in mind, <strong>Open Mirroring</strong> supports data replication from a wide range of source types, including:</p><ul><li><strong>OLTP sources</strong> (e.g., Oracle, PostgreSQL)</li><li><strong>OLAP sources</strong> (e.g., Snowflake, BigQuery, Databricks)</li><li><strong>NoSQL sources</strong> (e.g., MongoDB, CosmosDB, Couchbase)</li><li><strong>Files and other unstructured data sources</strong></li></ul><p>Additionally, <strong>Open Mirroring</strong> includes features to handle <strong>schema evolution</strong>, which is essential for maintaining data integrity and consistency. However, managing certain types of schema changes can be complex.</p><p>For detailed specifications on handling <strong>Change Data</strong> and <strong>Schema Evolution</strong>, please refer to the documentation [<a href="https://learn.microsoft.com/en-us/fabric/database/mirrored-database/open-mirroring-landing-zone-format">here</a>].</p><h4>What is the Cost Structure?</h4><p><strong>Microsoft Fabric</strong> offers free storage for mirrored data in <strong>OneLake</strong> based on the capacity units in use. For example, with an <strong>F2</strong>capacity, users receive <strong>2 TB</strong> of free storage in <strong>OneLake</strong>. If data usage exceeds this limit, additional charges will apply for the excess storage.</p><p>The compute resources involved in replicating data from the <strong>Landing Zone</strong> to <strong>Delta tables</strong> are provided by <strong>Fabric</strong>, and the compute is separate from any user-purchased resources. As a result, Mirroring is generally a low-cost approach to replication.</p><h4>What Are the Pain Points?</h4><p>Organizations often operate multiple storage systems for different use cases. For instance, they may have one system for live applications (often an OLTP or NoSQL system) and another for storing historical data used in analytics and reporting (such as data warehouses, data lakes, or lakehouse architectures). Streaming <strong>Change Data Capture (CDC)</strong> and initial load data from these diverse storage systems can be challenging.</p><p>Furthermore, managing <strong>schema evolution</strong> and propagating schema changes to the <strong>Landing Zone</strong> can be particularly complex for certain types of schema changes.</p><p>Another key challenge is maintaining <strong>data type integrity</strong> between source and target systems. The source data types must be compatible with <strong>Avro</strong> and <strong>Parquet</strong> format’s data types, as the <strong>Fabric Replicator Service</strong> uses the schema of Parquet files to create <strong>Delta Tables</strong>.</p><p>Finally, handling <strong>data recovery</strong> and <strong>deduplication</strong> in the event of a pipeline failure is a critical concern and can be complex to address.</p><p>To resolve the above challenges and make the users sit back and relax while the pipeline runs , we need a reliable and robust system that takes care of the above challenges.</p><h4>Open mirroring — powered by Striim</h4><p><strong>Striim’s SQL2Fabric — Mirroring solution </strong>offers automated data pipelines that enable the seamless streaming of real-time changes from various data sources to <strong>OneLake’s Landing Zone,</strong>. The platform efficiently handles:</p><ul><li><strong>Initial load replication</strong></li><li><strong>Change Data Capture</strong></li><li><strong>Schema evolution and changes</strong></li><li><strong>Data type integrity</strong></li><li><strong>Pipeline failure recovery</strong></li></ul><p>Through its partnership with <strong>Microsoft (</strong><a href="https://learn.microsoft.com/en-us/fabric/database/mirrored-database/open-mirroring-partners-ecosystem#striim">check here</a><strong>)</strong>, <strong>Striim</strong> has introduced <strong>SQL2Fabric X— Mirroring</strong>, a fully managed SaaS solution that provides automated data pipelines to mirror both <strong>initial load</strong> and <strong>Change Data Capture (CDC)</strong> streaming from <strong>SQL Server</strong>(whether on-premises, RDS, or hosted on MS Azure and GCP instances) to <strong>Fabric OneLake and Azure Databricks</strong></p><p>The pipeline is engineered to handle large data loads, manage schema evolution, and ensure robust recovery in the event of pipeline failures.</p><p>SQL2Fabric X can also be launched directly from the Fabric UI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*q7H55VIRpngR4Y6S5hQiAw.png" /><figcaption>Striim Automated Pipelines in Microsoft Fabric</figcaption></figure><p><strong>Now let us setup a pipeline in minutes</strong></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F1033206094%3Fapp_id%3D122963&amp;dntp=1&amp;display_name=Vimeo&amp;url=https%3A%2F%2Fvimeo.com%2F1033206094&amp;image=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F1954279913-9d04b62cc862834f41e2a3aeaaf7ef191c69e24df455d2076fb9600af3e35d32-d_1280&amp;type=text%2Fhtml&amp;schema=vimeo" width="1732" height="974" frameborder="0" scrolling="no"><a href="https://medium.com/media/1863ca0ba16bee7b3778f04ab6637324/href">https://medium.com/media/1863ca0ba16bee7b3778f04ab6637324/href</a></iframe><p><strong>Azure Marketplace</strong> : <a href="https://azuremarketplace.microsoft.com/en-us/marketplace/apps/striim.sql2fabric-mirroring?tab=Overview">https://azuremarketplace.microsoft.com/en-us/marketplace/apps/striim.sql2fabric-mirroring?tab=Overview</a></p><p><strong>Microsoft — Striim document</strong> : <a href="https://learn.microsoft.com/en-us/fabric/database/mirrored-database/open-mirroring-partners-ecosystem#striim">https://learn.microsoft.com/en-us/fabric/database/mirrored-database/open-mirroring-partners-ecosystem#striim</a></p><h4>Use Cases after mirroring</h4><p>One of the most exciting benefits of <strong>OneLake</strong> is its ability to mitigate <strong>vendor lock-in</strong>, especially in the context of <strong>data access</strong> and <strong>integration</strong>. The <strong>Delta tables</strong> stored within the <strong>Lakehouse container</strong> are now accessible across multiple query engines that support the <strong>Delta Lake format</strong>. This cross-vendor accessibility not only enables greater flexibility but also empowers organizations to leverage the strengths of different platforms without the need to duplicate data.</p><p>By eliminating the need to copy data between systems, <strong>organizations</strong> can significantly reduce both <strong>storage</strong> and <strong>reverse ETL</strong> costs. This seamless interoperability facilitates more efficient data workflows, enhances scalability, and allows businesses to implement <strong>vendor-specific features</strong> without being constrained by the limitations of any single provider.</p><p>Below are few <strong>POCs</strong> that demonstrate the accessibility of mirrored <strong>Delta Tables </strong>across popular querying engines:</p><h4>Access data within fabric ecosystem</h4><p>Data mirrored in OneLake is seamlessly accessible by applications and query engines within the Fabric ecosystem. This enables users to leverage a wide range of powerful tools for <strong>Business Intelligence</strong>, <strong>Reporting</strong>, <strong>Data Science</strong>, <strong>Machine Learning</strong>, and <strong>Monitoring</strong> to gain insights and drive decision-making using the data.</p><h4>Access from Snowflake</h4><p>Snowflake has introduced a public preview feature that allows users to create <strong>Iceberg tables</strong> from <strong>Delta Lake</strong> files stored in external storage. This enables users to access <strong>Delta tables</strong> in <strong>OneLake</strong> as <strong>Iceberg tables</strong> in Snowflake, though these tables are <strong>read-only</strong>.</p><p>To integrate Delta Lake tables with Snowflake, follow these steps:</p><p><strong>Step 1: Create a shortcut in Fabric LakeHouse.</strong></p><ul><li><strong>Navigate to Fabric LakeHouse</strong><br>Go to the <strong>LakeHouse</strong> page in the <strong>Fabric UI</strong>, right-click the <strong>Files</strong> section, and select <strong>New Shortcut</strong>.</li><li><strong>Choose Onelake as the Source</strong><br>Under the <strong>Internal Sources</strong> category, click <strong>Onelake</strong>. This will display a list of available data entities in your Fabric ecosystem.</li><li><strong>Select the Mirrored Delta Tables</strong><br>Pick the mirrored database created by <strong>Striim</strong> and click <strong>Next</strong>.</li><li><strong>Choose the Tables for Snowflake Access</strong><br>In the <strong>Tables</strong> section, select the specific <strong>Delta tables</strong> you wish to access in Snowflake and click <strong>Next</strong>.</li><li><strong>Create the Shortcut</strong><br>Review the selections and click <strong>Create</strong> to establish the shortcut.</li></ul><p>This will create a shortcut in the <strong>Files</strong> section of your <strong>Fabric LakeHouse</strong>, allowing Snowflake to access the Delta tables. It’s important to note that this process does not copy the data; it simply references the original Delta files.</p><p><strong>Step 2 : Configure access requirements for Snowflake</strong></p><ul><li>Create an external volume pointing to the onelake container.</li></ul><pre>CREATE OR REPLACE EXTERNAL VOLUME FabricExVol4<br>STORAGE_LOCATIONS =<br>(<br>  (<br>    NAME = &#39;Name your volume&#39;<br>    STORAGE_PROVIDER = &#39;AZURE&#39;<br>    STORAGE_BASE_URL = &#39;azure://onelake.dfs.fabric.microsoft.com/&lt;workspaceName/&lt;LakeHouseName&gt;.Lakehouse/Files/&#39;<br>    AZURE_TENANT_ID = &#39;&lt;tenant id&gt;&#39;<br>  )<br>);</pre><ul><li>Follow this <a href="https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-external-volume-azure#step-2-grant-snowflake-access-to-the-storage-location">document</a> from Step 2 — till point number 3 . (until providing the consent)</li><li>Navigate to your workspace in fabric portal where you have created the lakehouse, click manage access and add the AZURE_MULTI_TENANT_APP_NAME as contributor to the workspace.</li><li>Now you have configured the access requirements for Snowflake.</li></ul><p><strong>Step 3 : create a catalog integration</strong></p><pre>CREATE OR REPLACE CATALOG INTEGRATION &lt;Name&gt;<br>  CATALOG_SOURCE = OBJECT_STORE<br>  TABLE_FORMAT = DELTA<br>  ENABLED=true;</pre><p><strong>Step 4 : Create a Table</strong></p><ul><li>BaseLocationPath is the relative path for Files folder in lakehouse. In my case the complete path of the shortcut is “https://onelake.dfs.fabric.microsoft.com/eastusspace/DLH.Lakehouse/Files/dbo_ORDER_LIST” , So the BaseLocationPath is “dbo_ORDER_LIST”</li></ul><pre>CREATE OR REPLACE ICEBERG TABLE my_delta_iceberg_table<br>CATALOG = &lt;catalogIntegrationName&gt;<br>EXTERNAL_VOLUME = &lt;ExternalVolumeName&gt;<br>BASE_LOCATION = &lt;BaseLocationPath&gt;;</pre><p><strong>Step 5 : Query and refresh the table.</strong></p><ul><li>The table has to be refreshed for getting the latest snapshot as the data resides outside snowflake.</li><li>Or schedule a task to refresh tables automatically.</li></ul><pre>select count(*) from my_delta_iceberg_table;<br><br>alter iceberg table  my_delta_iceberg_table refresh</pre><pre>CREATE OR REPLACE TASK refresh_delta_tables<br>  USER_TASK_MANAGED_INITIAL_WAREHOUSE_SIZE = &#39;XSMALL&#39;<br>  SCHEDULE = &#39;USING CRON  0 * * * * America/Los_Angeles&#39;<br>  AS<br>    BEGIN<br>        alter iceberg table  my_delta_iceberg_table refresh;<br>    END;<br><br>ALTER TASK refresh_delta_tables resume;</pre><h4>Access from Databricks</h4><p>Databricks enables you to create <strong>external tables</strong> that refer directly to <strong>OneLake paths</strong>, allowing seamless access to your data. This process is straightforward and can be achieved with the support of <strong>Spark compute</strong> in <strong>Databricks</strong>.</p><p><strong>Step 1: Create a Shortcut in Fabric LakeHouse</strong></p><ul><li><strong>Create a LakeHouse</strong> or use an existing one to set up a shortcut in the <strong>Files</strong> section pointing to the mirrored <strong>Delta tables</strong>.</li><li>In the <strong>Fabric UI</strong>, navigate to the <strong>LakeHouse</strong> page, right-click the <strong>Files</strong> section, and select <strong>New Shortcut</strong>.</li><li>Under the <strong>Internal Sources</strong> category, choose <strong>Onelake</strong>.</li><li>You’ll now see a list of data entities within your Fabric ecosystem. Select the mirrored database created by <strong>Striim </strong>and click <strong>Next</strong>.</li><li>In the <strong>Tables</strong> section, choose the specific <strong>Delta tables</strong> you wish to access from Databricks and click <strong>Next</strong>.</li><li>Review your selections and click <strong>Create</strong>. This will create a shortcut in the <strong>Files</strong> section of your <strong>Fabric LakeHouse</strong>.</li><li><strong>Note:</strong> This action does not copy any data; it simply creates a reference to the original <strong>Delta files</strong>.</li><li>Right-click the shortcut folder, click <strong>Properties</strong>, and note the <strong>ABFSS path</strong> for future use.</li></ul><p><strong>Step 2: Set Up Authentication</strong></p><ul><li><strong>Register an Azure Entra ID app</strong> in the <strong>Azure portal</strong>. Provide a name for the app; no additional configurations are required.</li><li><strong>Create a client secret</strong> for the app and save the value.</li><li>In the <strong>Fabric portal</strong>, go to your workspace, click <strong>Manage Access</strong>, and add the <strong>Entra app</strong> (created earlier) as a <strong>Contributor</strong> to the workspace.</li></ul><p><strong>Step 3 : Open notebook and create a Spark Session with the below configs.</strong></p><ul><li>Replace &lt;ClientID&gt; with Client ID (ApplicationID) of the Entra App. Replace &lt;tenantID&gt; with the tenant ID of your Fabric account . Replace &lt;ClientSecret&gt; with the secret value noted previously.</li></ul><pre> <br>from pyspark.sql import SparkSession<br><br>spark.conf.set(&quot;fs.azure.account.auth.type&quot;, &quot;OAuth&quot;)<br>spark.conf.set(&quot;fs.azure.account.oauth.provider.type&quot;, &quot;org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider&quot;)<br>spark.conf.set(&quot;fs.azure.account.oauth2.client.id&quot;, &quot;&lt;ClientID&gt;&quot;)<br>spark.conf.set(&quot;fs.azure.account.oauth2.client.secret&quot;, &quot;&lt;ClientSecret&gt;&quot;)<br>spark.conf.set(&quot;fs.azure.account.oauth2.client.endpoint&quot;, &quot;https://login.microsoftonline.com/&lt;tenantID&gt;/oauth2/token&quot;)<br></pre><p><strong>Step 4 : Create an external table in databricks.</strong></p><ul><li>Replace &lt;abfss Path&gt; with the path copied earlier</li></ul><pre>spark.sql(f&quot;&quot;&quot;<br>    CREATE TABLE default.my_delta_table<br>    USING DELTA<br>    LOCATION &#39;&lt;abfss Path&gt;&#39;<br>&quot;&quot;&quot;)</pre><pre>refresh table default.my_delta_table;<br><br>SELECT * FROM default.my_delta_table;</pre><ul><li>Table has to be refreshed for getting the latest snapshot.</li></ul><h4>Access from Spark Engines</h4><p>Spark engines from Local machine, AWS EMR, Azure HDInsight and Google DataProc can be used to effectively query and compute the mirrored tables inside OneLake.</p><p><strong>Step 1: Create a Shortcut in Fabric LakeHouse</strong></p><ul><li><strong>Create a LakeHouse</strong> or use an existing one to set up a shortcut in the <strong>Files</strong> section pointing to the mirrored <strong>Delta tables</strong>.</li><li>In the <strong>Fabric UI</strong>, navigate to the <strong>LakeHouse</strong> page, right-click the <strong>Files</strong> section, and select <strong>New Shortcut</strong>.</li><li>Under the <strong>Internal Sources</strong> category, choose <strong>Onelake</strong>.</li><li>You’ll now see a list of data entities within your Fabric ecosystem. Select the mirrored database created by <strong>Striim </strong>and click <strong>Next</strong>.</li><li>In the <strong>Tables</strong> section, choose the specific <strong>Delta tables</strong> you wish to access from Databricks and click <strong>Next</strong>.</li><li>Review your selections and click <strong>Create</strong>. This will create a shortcut in the <strong>Files</strong> section of your <strong>Fabric LakeHouse</strong>.</li><li><strong>Note:</strong> This action does not copy any data; it simply creates a reference to the original <strong>Delta files</strong>.</li><li>Right-click the shortcut folder, click <strong>Properties</strong>, and note the <strong>ABFSS path</strong> for future use.</li></ul><p><strong>Step 2: Set Up Authentication</strong></p><ul><li><strong>Register an Azure Entra ID app</strong> in the <strong>Azure portal</strong>. Provide a name for the app; no additional configurations are required.</li><li><strong>Create a client secret</strong> for the app and save the value.</li><li>In the <strong>Fabric portal</strong>, go to your workspace, click <strong>Manage Access</strong>, and add the <strong>Entra app</strong> (created earlier) as a <strong>Contributor</strong> to the workspace.</li></ul><p><strong>Step 3 : Prepare the code</strong></p><ul><li>Replace &lt;ClientID&gt; with Client ID (ApplicationID) of the Entra App. Replace &lt;tenantID&gt; with the tenant ID of your Fabric account . Replace &lt;ClientSecret&gt; with the secret value noted previously.</li></ul><p><strong>Maven dependencies :</strong></p><pre>   &lt;dependency&gt;<br>      &lt;groupId&gt;io.delta&lt;/groupId&gt;<br>      &lt;artifactId&gt;delta-core_2.12&lt;/artifactId&gt;<br>      &lt;version&gt;2.4.0&lt;/version&gt;<br>    &lt;/dependency&gt;<br>  <br>    &lt;dependency&gt;<br>      &lt;groupId&gt;org.apache.hadoop&lt;/groupId&gt;<br>      &lt;artifactId&gt;hadoop-azure&lt;/artifactId&gt;<br>      &lt;version&gt;3.4.1&lt;/version&gt;<br>    &lt;/dependency&gt;</pre><pre>public class Onelake {<br>    public static void main(String[] args) {<br>        SparkSession session = getSession();<br>        session.read().format(&quot;delta&quot;).load(&quot;ABFSS Path&quot;).show();<br>    }<br><br>    public static SparkSession getSession() {<br>        Map&lt;String, Object&gt; sparkConfigMap = new HashMap&lt;&gt;();<br>        sparkConfigMap.put(&quot;spark.sql.extensions&quot;, &quot;io.delta.sql.DeltaSparkSessionExtension&quot;);<br>        sparkConfigMap.put(&quot;spark.packages&quot;,&quot;io.delta:delta-core_2.12:1.0.0&quot;);<br>        sparkConfigMap.put(&quot;spark.sql.catalog.spark_catalog&quot;, &quot;org.apache.spark.sql.delta.catalog.DeltaCatalog&quot;);<br>        sparkConfigMap.put(&quot;fs.azure.account.auth.type&quot;, &quot;OAuth&quot;);<br>        sparkConfigMap.put(&quot;fs.azure.account.oauth.provider.type&quot;, &quot;org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider&quot;);<br>        sparkConfigMap.put(&quot;fs.azure.account.oauth2.client.id&quot;, &quot;&lt;ClientID&gt;&quot;);<br>        sparkConfigMap.put(&quot;fs.azure.account.oauth2.client.secret&quot;, &quot;&lt;ClientSecret&quot;&quot;);<br>        sparkConfigMap.put(&quot;fs.azure.account.oauth2.client.endpoint&quot;, &quot;https://login.microsoftonline.com/&lt;tenantID/oauth2/token&quot;);<br><br>        SparkSession session =  SparkSession.builder()<br>                .master(&quot;local[*]&quot;)<br>                .config(sparkConfigMap)<br>                .getOrCreate();<br><br>        return session;<br>    }<br><br>}</pre><p>This piece of code can be run on local machine , or can be submitted to spark engines in any of the CSPs using the CSP’s native job submission APIs or using Apache Livy (Rest Gateway for Spark engine in CSPs).</p><h4>Analytics with DuckDB</h4><p>Mimoune Djouallah’s <a href="https://datamonkeysite.com/2024/12/31/tpc-ds-100gb-with-only-2-cores-and-16-gb-of-ram/">exploration of DuckDB and OneLake in running the TPC-DS benchmark demonstrates the robustness and adaptability of DuckDB combined with the openness of OneLake</a>. The integration with Python notebooks highlights its efficiency for analytical tasks. Using OneLake for scalable Delta table storage underscores its strong performance, comparable to local SSDs in specific setups. This experiment effectively showcases the openness, versatility, and potential of both tools for lightweight and cost-effective analytical workflows.</p><p>How to run DuckDB with Fabric LakeHouse.</p><p><strong>Step 1: Create a Shortcut in Fabric LakeHouse</strong></p><ul><li><strong>Create a LakeHouse</strong> or use an existing one to set up a shortcut in the <strong>Files</strong> section pointing to the mirrored <strong>Delta tables</strong>.</li><li>In the <strong>Fabric UI</strong>, navigate to the <strong>LakeHouse</strong> page, right-click the <strong>Files</strong> section, and select <strong>New Shortcut</strong>.</li><li>Under the <strong>Internal Sources</strong> category, choose <strong>Onelake</strong>.</li><li>You’ll now see a list of data entities within your Fabric ecosystem. Select the mirrored database created by <strong>Striim </strong>and click <strong>Next</strong>.</li><li>In the <strong>Tables</strong> section, choose the specific <strong>Delta tables</strong> you wish to access from Databricks and click <strong>Next</strong>.</li><li>Review your selections and click <strong>Create</strong>. This will create a shortcut in the <strong>Files</strong> section of your <strong>Fabric LakeHouse</strong>.</li><li><strong>Note:</strong> This action does not copy any data; it simply creates a reference to the original <strong>Delta files</strong>.</li><li>Right-click the shortcut folder, click <strong>Properties</strong>, and note the <strong>ABFSS path</strong> for future use.</li></ul><p><strong>Step 2 : Setup Authentication in OneLake</strong></p><ul><li><strong>Register an Azure Entra ID app</strong> in the <strong>Azure portal</strong>. Provide a name for the app; no additional configurations are required.</li><li><strong>Create a client secret</strong> for the app and save the value.</li><li>In the <strong>Fabric portal</strong>, go to your workspace, click <strong>Manage Access</strong>, and add the <strong>Entra app</strong> (created earlier) as a <strong>Contributor</strong> to the workspace.</li></ul><p><strong>Step 3 : Setup Authentication in DuckDB</strong></p><ul><li>Before setting up authentication , we need to import delta and azure extensions</li></ul><pre>install azure;<br>load azure;<br><br>install delta;<br>install delta;</pre><ul><li>Create secret</li></ul><pre>CREATE SECRET azure_spn (<br>      TYPE AZURE,<br>      PROVIDER SERVICE_PRINCIPAL,<br>      TENANT_ID &#39;&lt;Tenant ID&gt;&#39;,<br>      CLIENT_ID &#39;&lt;ClientID&gt;&#39;,<br>      CLIENT_SECRET &#39;&lt;ClientSecret&gt;&#39;<br>  );</pre><ul><li>Start querying</li></ul><pre>SELECT * FROM <br>delta_scan(&#39;&lt;ABFSS path copied in shortcut creation step&gt;&#39;)</pre><p><a href="https://duckdb.org/">DuckDB</a> is an extremely fast, user-friendly, and feature-packed system that excels at processing complex analytical queries on massive datasets. It’s widely appreciated by users and definitely worth trying out</p><h4>Access from Google BigQuery</h4><p>This is not possible for now, Google BigQuery doesn’t accept Onelake endpoints for creating Biglake external tables referencing DeltaLake on Onelake.</p><h4>Conclusion :</h4><p>Open Mirroring has significantly empowered organizations to efficiently stream data from a variety of sources to <strong>Fabric OneLake</strong>, addressing critical aspects such as <strong>Change Data Capture (CDC)</strong> and <strong>Schema Evolution</strong>. By mirroring data and leveraging <strong>DeltaLake</strong> format, it ensures a high level of cross-vendor compatibility, thus enabling seamless access and improved interoperability across different systems.</p><p>This approach, however, introduces engineering challenges related to building a <strong>reliable data pipeline</strong> .</p><p>A leader in this space, <strong>Striim</strong> provides a robust solution that addresses these challenges. By focusing on critical aspects of <strong>data integration</strong>, Striim ensures that organizations can rely on a stable, scalable pipeline that facilitates smooth, continuous data replication, synchronization, and transformation across a diverse range of storage systems and platforms.</p><p>In conclusion, <strong>open mirroring</strong> provides organizations with the scalability, flexibility, and reliability needed to manage complex data ecosystems while optimizing costs and accelerating time-to-insight.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=29bfc7f2c01e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/striim/microsoft-fabric-open-mirroring-mirror-once-query-anywhere-striim-29bfc7f2c01e">Microsoft Fabric Open Mirroring — Mirror once query anywhere — Striim</a> was originally published in <a href="https://medium.com/striim">Striim</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Change Data Capture Works: Understanding the Impact on Databases]]></title>
            <link>https://medium.com/striim/how-change-data-capture-works-understanding-the-impact-on-databases-346f83e64693?source=rss----833deda32774---4</link>
            <guid isPermaLink="false">https://medium.com/p/346f83e64693</guid>
            <category><![CDATA[change-data-capture]]></category>
            <category><![CDATA[data-streaming]]></category>
            <category><![CDATA[database]]></category>
            <dc:creator><![CDATA[John Kutay]]></dc:creator>
            <pubDate>Sat, 11 May 2024 06:52:28 GMT</pubDate>
            <atom:updated>2025-07-23T06:58:31.884Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bFtr0MytXcpSEm0d" /></figure><p>Change Data Capture (CDC) is a process that extracts database transactional data in real-time. Data Engineers and Analytics Engineers adopt CDC platforms like Striim, Oracle GoldenGate, Debezium, IBM Infosphere or Qlik Replicate to replicate operational data from Databases to event busses — like Kafka, PubSub and EventHubs — or Data Warehouses such as BigQuery, Databricks, Snowflake, Fabric and others. Change Data Capture enables businesses to process real-time data without impacting production operational systems, which is crucial for event-driven architectures and analytics. This post examines the impact of CDC on Operational Databases from minimal to significant levels, analyzing techniques such as redo log mining to the maintenance of shadow tables.</p><p>Based on some in-person discussions I had in the data community, I observed there’s a perception that Change Data Capture is viewed exclusively as a requirement for real-time analytics.</p><p>While CDC certainly enables real-time analytics if downstream consumers are not a bottleneck, the main value proposition of Change Data Capture is providing the most performant, least impactful way of replicating data from an operational database, regardless of the downstream latency requirements for analytics.</p><p>In a practical sense for data engineers, the beginning of a database replication project should not alarm DBAs and software engineers with potentially disruptive requests like polling the production database or adding triggers. Instead, data engineers need to present themselves as knowledgeable, considerate of potential concerns, and proactive in their collaboration to ensure efficient replication.</p><h4>Why we care about database performance</h4><p>Databases are critical for both business operations and customer-facing applications, where performance directly influences user experience, operational efficiency, and ultimately, business outcomes. High-performance databases ensure that applications run smoothly, data retrieval is swift, and transactions are processed quickly, which is vital for maintaining customer satisfaction and competitive advantage. For instance, in e-commerce, faster database responses can lead to quicker page loads and transaction processing, directly affecting sales conversions and customer retention. This is why we don’t want internal analytics workloads competing for database resources.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9jHbIiL26XAnCOo8" /></figure><p>Implementing Change Data Capture using direct queries or maintaining shadow tables, can significantly influence the management of the database’s cache, particularly the Least Recently Used (LRU) cache objects. The database query cache is designed to keep frequently accessed data in memory, optimizing the performance for repetitive queries. However, the operations involved in CDC like frequent querying or updating shadow tables can disrupt this optimization.</p><p>These CDC methods might populate the cache with data that is less frequently accessed by operational applications, potentially evicting more critical data from the cache and degrading overall application performance. This scenario underscores why minimal impact CDC methods, such as log mining, are often preferable from a performance optimization perspective. These methods are less likely to interfere with the normal operation of the database’s query cache, maintaining a better balance between data capture and operational efficiency.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*8M95FA8RCoF8opLP" /></figure><p>Long story short, we want the database to be tuned for application purposes, not for the convenience of internal analytics workloads.</p><h4>Varying Degrees of Impact on Databases</h4><p>I ran a poll on both LinkedIn and Twitter to gauge the data community’s assumptions about the impact of Log-Based Change Data Capture, and the results were polarizing to say the least!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/894/0*VNEK30P5QFjVF7RX" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4s_K5t1oE2cuUL6j" /></figure><p>To answer my respective polls on Twitter and Linkedin, the correct answer is YES. There’s always memory overhead of performing Change Data Capture on an operational Database. However, impact can vary from minimal — such as the memory for a thread to tail a disk on-file to extreme — such as periodically running queries on your database. That can be the difference between some minor memory tuning to your database to support Change Data Capture versus doubling the size and cost of your database to support batch queries.</p><p>To help visualize this, I created a matrix of performance impact from various methods of Change Data Capture.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*sk9fc-3Bvq8Cyi7B" /></figure><p>Here we show how Striim performs Change Data Capture from Oracle. You can see some of the memory usage on the database is ‘house money’ so to speak: Oracle’s Program Global Area will actually maintain a redo log buffer regardless of external Change Data Capture consumers for downstream analytics. Striim will simply subscribe to the changes published in the online redo log, and buffer them in-memory and on-disk. We’ve added extensive work to support long running transactions off-heap in Striim’s system layer, which also offloads processing from the operational database.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bFtr0MytXcpSEm0d" /></figure><h4>Minimal Impact: Redo or Write Ahead Log Mining</h4><p>At the minimal end of the spectrum is log mining. Database systems like Oracle use the redo log files for log mining, which is a relatively low-impact method of implementing CDC. The Oracle database maintains a redo log to record all changes made to the database. This log is essential for data recovery and is also used in log mining to track changes.</p><p>The actual memory impact here is primarily on the Shared Global Area (SGA) in Oracle. The SGA is a memory region that contains data and control information for a server process. It is used to process SQL statements and to manage the data as it moves through the system. In the context of CDC, when Oracle’s log mining feature (LogMiner) is used, it reads from the redo logs and uses the SGA to store the session’s private SQL area for processing the mined data. <a href="https://forums.oracle.com/ords/apexds/post/ora-04030-during-logminer-2004">Oracle’s native logmining can cause out of memory errors</a>.</p><p>The SGA size can vary based on the workload and the specific configuration of the Oracle instance. However, since log mining processes only read the redo logs and do not require maintaining a separate physical structure for the changes, the memory overhead is relatively controlled. The key to minimizing impact in such configurations is to ensure that SGA memory is sized adequately to handle the peak workload without causing significant performance degradation.</p><p>Oracle also supports Archive Logs, which can serve as a backup of the redo log for long term storage and recovery purposes. You can also mine data from the Archive Logs with minimal impact, given the work of generating the redo log was already done by the database, and you’re just spinning some threads to tail a file from the database’s operating system.</p><h4>Low Impact: Binary Log CDC in MySQL and Logical Replication in PostgreSQL</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*C0ubXCbax4E8bhPV.png" /><figcaption>MySQL BinLog</figcaption></figure><p>MySQL’s binary log-based CDC is a low impact method to extract changes from a database. MySQL’s binary log records all changes to the database, both data and structure, as a series of events. This method is similar to Oracle’s log mining but includes some operational differences that may influence memory usage.</p><p>The binary log itself is a file-based log, not directly impacting the database’s memory under typical operations. However, reading these logs for CDC purposes, especially when using external tools or custom scripts, can increase memory usage depending on how the changes are processed and staged before they are consumed or replicated.</p><p>PostgreSQL’s logical replication offers a balance between performance impact and real-time data synchronization capabilities. Logical replication in PostgreSQL involves streaming changes at the logical level, rather than copying physical data blocks, allowing for more selective replication and lower overhead compared to physical replication methods. This method captures changes to the database schema and data in the form of logical change records, which are then transmitted to subscriber databases.</p><p>The impact on memory and overall database performance with logical replication is generally low-to-moderate. Unlike methods that require frequent direct queries or the maintenance of shadow tables, logical replication leverages a publish-subscribe model, which minimizes the disruption to the main database operations. This approach allows PostgreSQL to maintain high performance by not overly taxing the database’s cache or CPU resources, making it particularly suitable for applications that require real-time or near-real-time data updates without a significant performance trade-off. Logical replication is highly configurable and can be tuned to replicate entire databases, specific tables, or even specific rows, offering flexibility that is valuable for maintaining efficient database operations and ensuring data consistency across distributed systems.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*WDcbi2AGlIRBtkRF.png" /><figcaption>PostgreSQL Write-Ahead Logic with Logical Replication</figcaption></figure><p>Mining the PostgreSQL Write-Ahead Log (WAL) can be an intensive operation, especially when done frequently or on large databases. Here are some of the disk-related issues that can occur from this process:</p><p>Increased Disk I/O: The WAL records every change made to the database, so mining it means reading through these records. This can lead to increased disk I/O, which might strain the storage system, especially if it’s not equipped with high-performance drives like SSDs.</p><p>Disk Space Consumption: The WAL can grow significantly in size, especially in a busy database system with lots of transactions. If the WAL files are not managed properly (e.g., archived or cleaned up regularly), they can consume a substantial amount of disk space, potentially filling up the disk.</p><p>Performance Degradation: As the disk begins to fill up, or as I/O operations increase, you might notice a degradation in overall system performance. This can affect not just database operations but other applications that rely on the same disk resources.</p><p>Fragmentation: Over time, continuous writing and deleting of WAL files can lead to disk fragmentation. This can degrade the performance of the disk as it requires more time to read scattered pieces of data.</p><p>Risk of Data Loss: In extreme cases, such as when the disk is full or nearly full, new transactions might fail or the system might not be able to write new WAL entries. This could lead to transaction failures or, in worst cases, data corruption if the system behaves unexpectedly due to disk space issues.</p><p>To mitigate these issues, it’s important to:</p><ul><li>Regularly monitor disk space and I/O metrics.</li><li>Implement proper WAL archiving and cleanup strategies.</li><li>Use high-performance disks for databases that require intensive I/O operations.</li><li>Consider scaling out your storage or using a dedicated storage system for WAL files to isolate the impact from other operations.</li></ul><h4>Moderate Impact: Maintaining Shadow Tables and Change Stream Implementations</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/0*qM9PuUKY0qPdKEqa.png" /><figcaption>SQLServer Change Data Capture with Shadow Tables</figcaption></figure><p>On the more significant end of the spectrum is the use of shadow tables for CDC, such as implemented by SQL Server’s Change Data Capture feature. This method involves creating and maintaining additional tables (shadow tables) that mirror the structure of the monitored tables and hold all changes made to the data. Each insert, update, or delete operation on the target table is reflected in the shadow table, capturing the old and new values of the affected rows.</p><p>This approach has a more pronounced impact on memory usage for several reasons:</p><ol><li>Increased Storage Requirements: Shadow tables increase the storage requirement as they duplicate a significant amount of data.</li><li>Increased I/O Operations: Manipulating shadow tables requires additional read and write operations, which can lead to increased memory usage as data pages are loaded into and evicted from the cache.</li><li>Overhead of Trigger-Based Tracking: In some implementations, triggers are used to populate shadow tables. Triggers themselves consume memory and CPU resources, further adding to the overhead.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KnmZ-CmfLtMqdf-Q.png" /></figure><p>MongoDB Change Streams is another Change Data Capture (CDC) implementation that generally has a minimal to moderate impact on database performance, depending on the scale and configuration of the deployment. Change Streams allow applications to access real-time data changes without the complexity of tailing the oplog (operations log) directly. They provide a more streamlined and scalable approach to reacting to database changes, making them particularly useful for applications that need to trigger actions or update external systems in response to data modifications within MongoDB.</p><p><strong>Performance Impact of MongoDB Change Streams</strong></p><ul><li>Moderate Overhead: Change Streams utilize MongoDB’s built-in replication capabilities. They operate by listening to changes in the oplog, a special capped collection that logs all operations that modify the data stored in databases. Since the oplog is already an integral part of MongoDB’s replication infrastructure, tapping into this system adds only little overhead. However, the oplog listener does consume resources from the database.</li><li>Scalability: MongoDB’s horizontal scalability through sharding means that Change Streams can also scale by distributing the load across multiple servers. This scalability helps in maintaining performance even as the volume of changes increases.</li><li>Selective Listening: One of the key features of Change Streams is their ability to filter and only listen to specific changes, which can significantly reduce the amount of data that needs to be processed and transmitted. This selective approach minimizes the memory and network bandwidth used, thereby mitigating the impact on the overall database performance.</li></ul><p><strong>Optimizing Performance with Change Streams</strong></p><p>To optimize the performance when using MongoDB Change Streams, it’s crucial to:</p><ul><li>Filter Changes: Apply filters to only subscribe to the relevant changes needed by the application, reducing unnecessary data processing.</li><li>Monitor Load: Keep an eye on the replication window and the impact of Change Streams on the primary database operations, especially in high-throughput environments.</li><li>Adjust Oplog Size: Ensure the oplog is appropriately sized to handle the volume of changes without frequent rollovers, which could lead to missed changes or higher latency in Change Streams.</li></ul><h4>Highest Impact: Periodic Batch Jobs with Query-Based CDC</h4><p>The highest memory impact in CDC operations often occurs when CDC is implemented through periodic queries against the database. This approach involves running full or incremental queries at regular intervals to detect changes in the data. This method can be highly resource-intensive, particularly for large databases or databases with high transaction volumes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9jHbIiL26XAnCOo8" /></figure><p>The main challenges with batch query-based CDC include:</p><ul><li>High Resource Utilization: Running complex queries to detect changes can consume significant CPU and memory resources, as these queries often involve scanning large portions of tables or joining multiple tables.</li><li>Impact on Database Performance: Frequent and resource-intensive queries can degrade the performance of the primary database operations, potentially leading to slower response times for other applications using the same database.</li><li>Data Freshness Issues: Since this method captures changes at intervals, there is a latency in data capture, which may not be suitable for scenarios requiring real-time or near-real-time data syncing.</li></ul><h4>How we designed Striim</h4><p>Change Data Capture is a powerful technique for enabling real-time data processing and synchronization. The choice of CDC method should consider not only the operational requirements but also the impact on database performance, especially memory usage. From minimal impact techniques like Oracle’s log mining to more intensive methods like SQL Server’s shadow tables, and the highest impact method of periodic query-based CDC, each approach has its trade-offs that need to be managed to maintain overall system efficiency and performance.</p><p>At Striim, we’ve optimized CDC to offer both high performance and ease-of-use, supporting log-based CDC and CDC from change tracking tables, thus simplifying data movement and reducing total cost of ownership as highlighted by our <a href="https://www.striim.com/case-study/how-american-airlines-powers-global-techops-with-a-real-time-data-hub/">clients like American Airlines: “Striim is a fully managed service that reduces our total cost of ownership while providing a simple drag and drop UI. There’s no maintenance overhead for American Airlines to maintain the infrastructure.”</a></p><p>By optimizing Change Data Capture for low impact data capture and low latency delivery to consumers, <a href="https://www.striim.com/case-study/ups/">enterprises like UPS are able to build real-time AI applications to battle porch pirates</a>.</p><p>You can learn more about Striim’s leading performance in Change Data Capture here with our respective partner endorse blogs:</p><p><a href="https://cloud.google.com/blog/products/data-analytics/data-integration-from-oracle-to-google-bigquery-using-striim/">Striim Oracle to BigQuery Benchmark</a></p><p><a href="https://medium.com/snowflake/optimizing-continuous-data-pipelines-for-low-latency-using-snowpipe-streaming-api-in-striim-507a7798b0fc">Striim Oracle to Snowflake Benchmark</a></p><p>If you want to start developing real-time, low impact Change Data Capture pipelines you can try <a href="https://go2.striim.com/aws-trial">Striim’s free trial </a>and <a href="https://signup-developer.striim.com/">free community version.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=346f83e64693" width="1" height="1" alt=""><hr><p><a href="https://medium.com/striim/how-change-data-capture-works-understanding-the-impact-on-databases-346f83e64693">How Change Data Capture Works: Understanding the Impact on Databases</a> was originally published in <a href="https://medium.com/striim">Striim</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>