<?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"><channel><title><![CDATA[DBConvert]]></title><description><![CDATA[DBConvert blog shares database management insights, data migration tutorials, and integration strategies. We help businesses optimize database operations with p]]></description><link>https://dbconvert.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 06 Sep 2026 03:37:07 GMT</lastBuildDate><atom:link href="https://dbconvert.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[📚 The Smart Way to Talk to Your Database: Why Hybrid API + NL2SQL Wins?]]></title><description><![CDATA[title: 📚 The Smart Way to Talk to Your Database: Why Hybrid API + NL2SQL Wins?
published: true
date: 2025-05-07 21:45:19 UTC
tags: ai,database,sql,api
canonical_url: https://dbconvert.com/blog/hybrid-nl2sql-vs-full-ai/
 

Hybrid is not a fallback — ...]]></description><link>https://dbconvert.hashnode.dev/the-smart-way-to-talk-to-your-database-why-hybrid-api-nl2sql-wins</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/the-smart-way-to-talk-to-your-database-why-hybrid-api-nl2sql-wins</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Wed, 07 May 2025 21:45:19 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: 📚 The Smart Way to Talk to Your Database: Why Hybrid API + NL2SQL Wins?
published: true
date: 2025-05-07 21:45:19 UTC
tags: ai,database,sql,api</p>
<h2 id="heading-canonicalurl-httpsdbconvertcombloghybrid-nl2sql-vs-full-ai">canonical_url: https://dbconvert.com/blog/hybrid-nl2sql-vs-full-ai/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056651513/eaecdeae-3a4c-43d7-9ae5-b7dbb605fa02.png" alt="📚 The Smart Way to Talk to Your Database: Why Hybrid API + NL2SQL Wins?" /></p>
<blockquote>
<p><strong>Hybrid is not a fallback — it's the real strategy.</strong></p>
<p>Why Pure AI Isn't Enough — And How Combining Bulletproof APIs with Smart NL2SQL Creates the Future of Database Interaction</p>
</blockquote>
<hr />
<h2 id="heading-1-introduction">1. Introduction</h2>
<p><em>Databases weren't designed to "listen" — meaning understand flexible human intentions. They were designed to "obey" — meaning strictly execute SQL commands. Now it's time to teach them both.</em></p>
<p>For decades, database systems have been built on strict, predictable APIs: list your <code>/tables</code>, fetch <code>/meta</code>, run <code>SELECT</code> queries — and everything just works.</p>
<p>But today, with AI evolving rapidly, a powerful new dream is emerging:</p>
<blockquote>
<p>"Can users finally <em>talk</em> to databases in natural language — no SQL textbooks, no syntax memorization, just questions?"</p>
</blockquote>
<p>Yet reality bites: AI alone can't replace strong backend architecture.</p>
<p><strong>The real solution?</strong> A <strong>Hybrid Approach</strong> — traditional bulletproof APIs + an AI-powered NL2SQL layer <em>(Natural Language to SQL)</em> that acts as an optional bonus.</p>
<p>Let's break it down — pragmatically, not dreamily.</p>
<hr />
<h2 id="heading-2-why-pure-ai-wont-cut-it-yet">2. Why Pure AI Won't Cut It (Yet)</h2>

<div class="hn-table">
<table>
<thead>
<tr>
<td>Traditional API</td><td>AI/NL2SQL</td></tr>
</thead>
<tbody>
<tr>
<td>Fast</td><td>Sometimes slow (LLM call latency)</td></tr>
<tr>
<td>Reliable</td><td>Probabilistic, can hallucinate</td></tr>
<tr>
<td>Predictable</td><td>Needs extra validation</td></tr>
<tr>
<td>Secure</td><td>Needs SQL safety checks</td></tr>
<tr>
<td>Easy to debug</td><td>Almost impossible to trace logic</td></tr>
</tbody>
</table>
</div>
<p><strong>Reality check:</strong></p>
<ul>
<li>You don't want critical operations depending only on AI "best guesses."</li>
<li>You DO want natural language as a bonus layer — not just for non-technical users, but for anyone who values saving time and riding the new wave of 'vibe coding' that's spreading fast.</li>
</ul>
<p>Thus: <strong>Hybrid wins. It's smarter, faster, and cooler — because it actually works. And as a result, it's way sexier than blind "AI magic."</strong></p>
<blockquote>
<p><strong>Even the most advanced AI database tools today rely on strong traditional APIs underneath. There are no magic shortcuts — robust backend foundations are non-negotiable.</strong></p>
</blockquote>
<hr />
<h2 id="heading-3-hybrid-architecture-blueprint">3. Hybrid Architecture Blueprint</h2>
<pre><code>Frontend (UI)
   ↓
Backend (Traditional APIs)
   ↓
• /meta (List tables, views)
• /tables (Detailed table info)
• /views (View info)
• /execute (Safe SELECT/SHOW only)
   ↓
NL2SQL Layer (Optional, AI-assisted)
   ↓
Smart prompt ➔ OpenAI (or local LLM)
   ↓
Return generated SQL
   ↓
Safe validate SQL
   ↓
Execute via /execute
   ↓
Results to User
</code></pre><p><em>hybrid architecture</em></p>
<hr />
<h2 id="heading-4-traditional-responsibilities">4. Traditional Responsibilities</h2>
<p>Your backend should ALWAYS handle:</p>
<ul>
<li><strong>Schema serving:</strong> <code>/meta</code>, <code>/tables</code>, <code>/views</code></li>
<li><strong>Safe query execution:</strong> <code>/execute</code> (read-only enforced)</li>
<li><strong>Connection pooling and auth</strong></li>
<li><strong>Error handling and logging</strong></li>
</ul>
<p>These parts <strong>MUST NOT depend</strong> on any LLM.</p>
<p><strong>Treat LLM as optional bonus.</strong></p>
<hr />
<h2 id="heading-5-ainl2sql-responsibilities">5. AI/NL2SQL Responsibilities</h2>
<p>AI should ONLY help:</p>
<ul>
<li>Translate user intent into SQL.</li>
<li>Suggest queries based on partial language.</li>
<li>Explore data more flexibly.</li>
</ul>
<p><strong>BUT:</strong></p>
<ul>
<li>Validate generated SQL strictly.</li>
<li>Never allow unsafe commands (e.g., <code>DROP</code>, <code>DELETE</code>).</li>
<li>Rate-limit AI usage if needed to avoid abuse.</li>
</ul>
<hr />
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056653136/caa4dbe3-079b-46ca-815b-fcb57600f701.png" alt="📚 The Smart Way to Talk to Your Database: Why Hybrid API + NL2SQL Wins?" /></p>
<h2 id="heading-6-prompt-engineering-example">6. Prompt Engineering Example</h2>
<pre><code>You are an expert SQL assistant <span class="hljs-keyword">for</span> a PostgreSQL database.
Here are the available tables:

- users (id, name, email)
- orders (id, user_id, total_amount, created_at)

<span class="hljs-attr">Instructions</span>:
- Generate a single-line SQL query (PostgreSQL syntax).
- Use only the provided tables and columns.
- Format output like <span class="hljs-built_in">this</span>:

<span class="hljs-string">``</span><span class="hljs-string">`sql
SELECT * FROM users;</span>
</code></pre><p>User Question: List all users who placed an order over $500.</p>
<pre><code>
Example SQL generated:

<span class="hljs-string">``</span><span class="hljs-string">`sql
SELECT users.*
FROM users
JOIN orders ON users.id = orders.user_id
WHERE orders.total_amount &gt; 500;</span>
</code></pre><p>Result: Clean, focused, safe query generation.</p>
<hr />
<h2 id="heading-7-conclusion-brains-over-buzzwords">7. Conclusion: Brains Over Buzzwords</h2>
<p>✅ Backend: solid, predictable, safe.</p>
<p>✅ AI layer: flexible, optional, user-friendly.</p>
<p>Don't throw away proven API design. Don't fear adding smart, lightweight AI layers.</p>
<p><strong>Be pragmatic. Combine them.</strong></p>
<p>That's how real production systems win.</p>
<h2 id="heading-75-why-hybrid-saves-you-from-catastrophes">7.5 Why Hybrid Saves You from Catastrophes</h2>
<p>Some dreamers imagine this:</p>
<blockquote>
<p>"I'll just send the <em>entire</em> multi-million-row table to the AI and let it figure things out."</p>
</blockquote>
<p><strong>Reality check:</strong></p>
<ul>
<li>🚫 LLMs can't handle massive raw data ingestion (token limits, timeouts, costs skyrocket).</li>
<li>🚫 It's dumb to flood AI with 100+MB payloads.</li>
<li>🚫 You destroy speed, efficiency, and security in the process.</li>
</ul>
<p>**Hybrid solves it differently:</p>
<ul>
<li>✅ Use traditional APIs (<code>/meta</code>, <code>/sample</code>, <code>/aggregate</code>, <code>/data</code>) to <strong>pre-filter, slice, and intelligently fetch only needed records</strong>.</li>
<li>✅ Only send <strong>small, smart prompts</strong> to AI — let it generate <em>smart queries</em>, not drown in raw data.</li>
</ul>
<p>Even when building AI-driven systems, never let your LLM blindly query raw data. Always use traditional API endpoints (<code>/meta</code>, <code>/sample</code>, <code>/aggregate</code>, <code>/data</code>) to <strong>prepare clean, small context</strong> before AI gets involved.</p>
<p><strong>Small context = Smart answers. Big chaos = Dumb crashes.</strong></p>
<blockquote>
<p><strong>In short:</strong> AI thinks better when you feed it knowledge — not raw chaos.</p>
</blockquote>
<hr />
<h2 id="heading-dbconvert-streams-real-tools-for-real-builders">🧪 DBConvert Streams: Real Tools for Real Builders</h2>
<p>As of version 1.3, <a target="_blank" href="https://streams.dbconvert.com/database-explorer">DBConvert Streams</a> already provides everything you need to power the hybrid approach:</p>
<ul>
<li>✅ View full database structure</li>
<li>✅ Fetch table data cleanly</li>
<li>✅ Inspect DDL for tables and views via API</li>
</ul>
<p>And yes — we're not stopping there. NL2SQL is coming <strong>very soon</strong> in the next release.</p>
<p>Stay tuned.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056654900/32ea0502-0162-4ffb-9107-f212db7270d2.png" alt="📚 The Smart Way to Talk to Your Database: Why Hybrid API + NL2SQL Wins?" /></p>
<h2 id="heading-build-smarter-connect-deeper-and-leave-the-ai-noise-merchants-behind">Build smarter, connect deeper — and leave the AI noise merchants behind.</h2>
<blockquote>
<p><strong>Final thought:</strong> In a world chasing AI hype, it's those who blend power with precision who build systems that truly last.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Stop Using pgloader: This No-Code Tool Migrates to Neon Faster]]></title><description><![CDATA[title: Stop Using pgloader: This No-Code Tool Migrates to Neon Faster
published: true
date: 2025-04-15 22:21:45 UTC
tags: Neon,postgresql,postgres,mysql
canonical_url: https://dbconvert.com/blog/stop-using-pgloader-this-no-code-tool-migrates-to-neon-...]]></description><link>https://dbconvert.hashnode.dev/stop-using-pgloader-this-no-code-tool-migrates-to-neon-faster</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/stop-using-pgloader-this-no-code-tool-migrates-to-neon-faster</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Tue, 15 Apr 2025 22:21:45 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: Stop Using pgloader: This No-Code Tool Migrates to Neon Faster
published: true
date: 2025-04-15 22:21:45 UTC
tags: Neon,postgresql,postgres,mysql</p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogstop-using-pgloader-this-no-code-tool-migrates-to-neon-faster">canonical_url: https://dbconvert.com/blog/stop-using-pgloader-this-no-code-tool-migrates-to-neon-faster/</h2>
<p># 
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056659314/80ee7d3d-fd93-4645-95e6-15c5a7e90846.png" alt="Stop Using pgloader: This No-Code Tool Migrates to Neon Faster" /></p>
<p>As developers and teams look for scalable, flexible database infrastructure, <strong>Neon</strong> emerges as a modern serverless PostgreSQL platform. It offers features like autoscaling, branching, and separation of storage and compute—making it ideal for cloud-native apps.</p>
<p>While Neon's <a target="_blank" href="https://neon.tech/docs/import/migrate-mysql?ref=dbconvert.com">official documentation</a> suggests using <code>pgloader</code> for migration from MySQL, that approach requires scripting and command-line tools.</p>
<p>For those looking for a no-code, streamlined experience, <a target="_blank" href="https://streams.dbconvert.com/?ref=dbconvert.com"><strong>DBConvert Streams</strong></a> provides a powerful, real-time migration solution with a friendly web interface.</p>
<hr />
<h2 id="heading-why-neon">Why Neon?</h2>
<p>Neon provides a cloud-native PostgreSQL environment with:</p>
<ul>
<li><strong>Autoscaling</strong> — scales compute resources automatically based on demand.</li>
<li><strong>Branching</strong> — spin up isolated database branches instantly for dev/test.</li>
<li><strong>Separation of compute and storage</strong> — optimized for elasticity and performance.</li>
<li><strong>Pay-as-you-go</strong> pricing — ideal for startups and scaling workloads.</li>
</ul>
<hr />
<h2 id="heading-what-is-dbconvert-streams">🔄 What Is DBConvert Streams?</h2>
<p><strong>DBConvert Streams</strong> is a no-code, real-time database migration and replication tool. It supports migrating <strong>from MySQL to PostgreSQL</strong> - perfect for transferring data to Neon from any MySQL source, whether it's hosted locally, self-hosted on your own servers, running on cloud platforms (AWS, GCP, Azure), or on managed database services like Amazon RDS or Google Cloud SQL.</p>
<h3 id="heading-key-features">Key Features</h3>
<ul>
<li>✅ Web UI — no CLI or code needed.</li>
<li>✅ Real-time CDC (Change Data Capture) sync.</li>
<li>✅ Automated schema mapping and transformation.</li>
<li>✅ Deployable locally or to the cloud (DigitalOcean, AWS, etc.).</li>
</ul>
<hr />
<h2 id="heading-prerequisites">🛠️ Prerequisites</h2>
<p>Before starting the migration, make sure you have:</p>
<ol>
<li><strong>Local MySQL database</strong> :<ul>
<li>Host: <code>localhost</code></li>
<li>Port: <code>3306</code> (default)</li>
<li>Credentials (user, password)</li>
<li>Database name</li>
</ul>
</li>
<li><strong>Neon PostgreSQL instance</strong> :<ul>
<li>Sign up at <a target="_blank" href="https://neon.tech/?ref=dbconvert.com">neon.tech</a></li>
<li>Create a database project</li>
<li>Copy the PostgreSQL connection string from the Neon Console</li>
</ul>
</li>
<li><strong>Deployment of DBConvert Streams</strong> :<ul>
<li>Go to: <a target="_blank" href="https://streams.dbconvert.com/deploy?ref=dbconvert.com">https://streams.dbconvert.com/deploy</a></li>
<li>Choose your preferred deployment (Docker, local binary, or cloud)</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-step-by-step-migration-process">🔧 Step-by-Step Migration Process</h2>
<h3 id="heading-1-launch-dbconvert-streams">1. Launch DBConvert Streams</h3>
<p>After deployment:</p>
<ul>
<li>Open the web interface at:<br /><strong><code>http://localhost</code></strong> (for local)<br />or<br /><strong><code>http://&lt;your_server_ip&gt;</code></strong> (for cloud-hosted)</li>
</ul>
<h3 id="heading-2-set-up-source-and-target">2. Set Up Source and Target</h3>
<ul>
<li><strong>Source</strong> :<br />Choose <strong>MySQL</strong> , and enter your local database details:<br /><code>host=localhost</code>, <code>port=3306</code>, <code>username=root</code>, <code>password=yourpassword</code>, <code>database=mydb</code></li>
<li><strong>Target</strong> :<br />Choose <strong>PostgreSQL</strong> , and paste your <strong>Neon connection string</strong>.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056660777/2fa8e64f-22bd-493b-a6e9-885697e36e54.png" alt="Stop Using pgloader: This No-Code Tool Migrates to Neon Faster" /></p>
<h3 id="heading-3-create-a-migration-stream">3. Create a Migration Stream</h3>
<ul>
<li>Select the tables you want to migrate.</li>
<li>Choose "One-time migration" for transferring data to Neon.</li>
<li>Start the stream.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056662129/716ceba5-5196-4e29-ac66-38d2699bdd9e.png" alt="Stop Using pgloader: This No-Code Tool Migrates to Neon Faster" />
<em>stream to migrate data from local MySQL to Neon</em></p>
<h3 id="heading-4-monitor-progress">4. Monitor Progress</h3>
<ul>
<li>Use the dashboard to track row-level sync.</li>
<li>Logs and statistics are available in real time.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056663286/d1907f1f-bc26-476a-a560-ffd622f3e893.png" alt="Stop Using pgloader: This No-Code Tool Migrates to Neon Faster" /></p>
<h3 id="heading-5-verify-in-neon">5. Verify in Neon</h3>
<ul>
<li>Connect to your Neon database using <code>psql</code>, or Neon's Viewer.</li>
<li>Verify schema, data, and constraints.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056664471/e127eaaf-f6b3-4a91-b962-dd036ae1d744.png" alt="Stop Using pgloader: This No-Code Tool Migrates to Neon Faster" /></p>
<h2 id="heading-real-world-example-migrating-the-sakila-database">📊 Real-World Example: Migrating the Sakila Database</h2>
<p>To demonstrate the power and simplicity of DBConvert Streams, let's look at migrating the standard <strong>Sakila</strong> sample database (a widely-used sample database that models a DVD rental store).</p>
<h3 id="heading-the-pgloader-approach-command-line">The pgloader Approach (Command Line)</h3>
<p>Using pgloader requires creating a configuration file like this:</p>
<pre><code>LOAD DATABASE
    FROM mysql:<span class="hljs-comment">//root:password@mysql-source/sakila?useSSL=false</span>
    INTO pgsql:<span class="hljs-comment">//neondb_owner:endpoint=endpoint;PasSwOrD@addr.eu-central-1.aws.neon.tech/neondb?sslmode=allow</span>
WITH include drop, 
     create tables, 
     create indexes, 
     reset sequences,
     workers = <span class="hljs-number">4</span>, 
     concurrency = <span class="hljs-number">1</span>,
     multiple readers per thread, 
     rows per range = <span class="hljs-number">50000</span>,
     drop indexes
SET MySQL PARAMETERS
    net_read_timeout = <span class="hljs-string">'120'</span>,
    net_write_timeout = <span class="hljs-string">'120'</span>
CAST
    type datetime to timestamptz drop <span class="hljs-keyword">default</span> using zero-dates-to-<span class="hljs-literal">null</span>,
    type timestamp to timestamptz drop <span class="hljs-keyword">default</span> using zero-dates-to-<span class="hljs-literal">null</span>,
    type date to date drop <span class="hljs-keyword">default</span> using zero-dates-to-<span class="hljs-literal">null</span>,
    type tinyint to smallint drop typemod,
    <span class="hljs-comment">/* and many more type mappings... */</span>
</code></pre><p><em>pgloader load.config</em></p>
<p>This requires understanding data type mappings, SQL specifics, and executing commands via CLI.</p>
<h3 id="heading-the-dbconvert-streams-approach-no-code">The DBConvert Streams Approach (No-Code)</h3>
<p>With DBConvert Streams, the process is dramatically simplified:</p>
<ol>
<li>Select MySQL source and enter connection details for Sakila database</li>
<li>Select PostgreSQL target and enter Neon connection string</li>
<li>Click to select all tables</li>
<li>Start the migration</li>
</ol>
<p>💡</p>
<p><strong>The results?</strong><br /><strong>pgloader</strong> : ~13 seconds with manual configuration<br /><strong>DBConvert Streams</strong> : ~1 second with zero configuration</p>
<p>While both tools successfully migrated the data, DBConvert Streams did it:</p>
<ul>
<li>Without requiring coding knowledge</li>
<li>Without manual type mapping configuration</li>
<li>In a fraction of the time</li>
<li>Through an intuitive web interface</li>
</ul>
<p>This real-world test demonstrates how DBConvert Streams removes complexity while delivering superior performance for database migrations.</p>
<hr />
<h2 id="heading-why-not-use-pgloader">🧩 Why Not Use pgloader?</h2>
<p>While Neon's official docs recommend <a target="_blank" href="https://neon.tech/docs/import/migrate-mysql?ref=dbconvert.com">pgloader</a>, it's:</p>
<ul>
<li>CLI-based and less intuitive for non-technical users</li>
<li>Requires manual configuration of data type mappings</li>
<li>Lacks real-time sync support</li>
<li>Not ideal for visual monitoring or production replication</li>
<li>Generally slower for most migration scenarios</li>
</ul>
<p><strong>DBConvert Streams</strong> provides a visual, no-code, production-friendly alternative with CDC and web-based control.</p>
<blockquote>
<p>Need to migrate from AWS RDS, Google Cloud SQL, or DigitalOcean? Stay tuned — support’s just as easy.<br />🌐 Visit <a target="_blank" href="https://streams.dbconvert.com/deploy?ref=dbconvert.com">https://streams.dbconvert.com/deploy</a> to get started.</p>
</blockquote>
<p>Say goodbye to scripts and hello to seamless, serverless PostgreSQL with Neon.</p>
]]></content:encoded></item><item><title><![CDATA[Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)]]></title><description><![CDATA[title: "Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)"
published: true
date: 2025-04-13 20:18:08 UTC
tags: 
canonical_url: https://dbconvert.com/blog/migrate-mysql-postgresql-to-digitalocean/
# 
 
DigitalOc...]]></description><link>https://dbconvert.hashnode.dev/escape-google-cloud-sql-migrate-to-digitalocean-with-mysql-or-postgresql-no-code-guide</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/escape-google-cloud-sql-migrate-to-digitalocean-with-mysql-or-postgresql-no-code-guide</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Sun, 13 Apr 2025 20:18:08 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: "Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)"
published: true
date: 2025-04-13 20:18:08 UTC
tags: </p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogmigrate-mysql-postgresql-to-digitalocean">canonical_url: https://dbconvert.com/blog/migrate-mysql-postgresql-to-digitalocean/</h2>
<p># 
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056668611/340be0d8-04ec-43c2-b059-9f5788b9c41a.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<p>DigitalOcean is a favorite among developers, indie hackers, and growing startups for its clean developer experience, predictable pricing, and powerful managed services. It's especially appealing to those who want to <strong>escape the complexity and overhead</strong> of platforms like Google Cloud.</p>
<p>If you're currently hosting your database on Google Cloud SQL and find yourself overwhelmed by its enterprise-focused tooling or rising costs, moving your data to DigitalOcean is a smart move. With managed PostgreSQL and MySQL offerings, DigitalOcean makes it easy to offload operational tasks like backups, updates, and high availability—so you can focus on building your product.</p>
<p>In this guide, I'll show you how to transfer your database from <strong>Google Cloud SQL to DigitalOcean</strong> using <a target="_blank" href="https://streams.dbconvert.com/?ref=dbconvert.com"><strong>DBConvert Streams</strong></a> — a powerful no-code tool designed to simplify cross-database migrations across cloud environments. For this demo, we will extract data from a MySQL source database and transfer it to a PostgreSQL target database.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you begin, make sure you have the following ready:</p>
<ul>
<li>✅ A <strong>DigitalOcean account</strong> (needed to create both a Droplet for DBConvert Streams and a target Postgres managed database)</li>
<li>✅ Credentials for your <strong>Google Cloud SQL</strong> instance (host, port, username, password, database name)</li>
</ul>
<h2 id="heading-step-1-set-up-your-digitalocean-database">Step 1: Set Up Your DigitalOcean Database</h2>
<p>DigitalOcean offers fully managed MySQL and PostgreSQL databases that are perfect for production workloads.</p>
<ol>
<li>Log in to your DigitalOcean dashboard</li>
<li>Click on <strong>Databases</strong> in the left menu</li>
<li>Click <strong>Create Database Cluster</strong></li>
<li>Select your database engine (in our PostgreSQL)</li>
<li>Choose your preferred plan (start small - you can scale up later)</li>
<li>Select the datacenter region closest to your users</li>
<li>Give your database a name (e.g., "sakila-db")</li>
<li>Click <strong>Create Database Cluster</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056670196/488449be-60f1-4610-80e1-e084e95ace56.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<p>DigitalOcean will take a few minutes to provision your database. Once ready, you'll see connection details including hostname, port, username, password, and database name.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056671406/5c6fd27e-7183-4f7a-8925-7312334faa5b.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<h2 id="heading-step-2-deploy-dbconvert-streams-1-click-app">Step 2: Deploy DBConvert Streams 1-Click App</h2>
<p>The simplest way to deploy DBConvert Streams is through the DigitalOcean Marketplace:</p>
<ol>
<li>Visit <a target="_blank" href="https://marketplace.digitalocean.com/apps/dbconvert-streams?ref=dbconvert.com"><strong>https://marketplace.digitalocean.com/apps/dbconvert-streams</strong></a></li>
<li>Click <strong>Create DBConvert Streams Droplet</strong></li>
<li>Choose your plan (Basic Droplet with 2GB RAM is sufficient for most migrations)</li>
<li>Select the same region as your database for optimal performance</li>
<li>Add your SSH key or create a password</li>
<li>Click <strong>Create Droplet</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056672582/f3dba498-7624-45cc-9e63-dd7a5a7e0188.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<p>Once your Droplet is provisioned (usually takes about a minute), you can access the DBConvert Streams web interface by navigating to <code>http://&lt;your-droplet-ip&gt;</code> in your browser.</p>
<h2 id="heading-step-3-configure-google-cloud-sql-for-external-access">Step 3: Configure Google Cloud SQL for External Access</h2>
<p>Before creating a connection in DBConvert Streams, you must configure your Google Cloud SQL instance to accept external connections:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056673674/4f3dbc33-bc52-4831-9be7-ddb03e6c13d1.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<ol>
<li>In the <a target="_blank" href="https://console.cloud.google.com/?ref=dbconvert.com">Google Cloud Console</a>, navigate to your Cloud SQL instance</li>
<li>Go to the <strong>Connections</strong> tab</li>
<li>Under <strong>Networking</strong> , select <strong>Add network</strong> in the <strong>Authorized networks</strong> section</li>
<li>Add your DigitalOcean Droplet's IP address with a name like "streams-migration"</li>
<li>Save your changes</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056674762/fe140378-fed6-4421-965b-fe283e7ef1f8.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<p>For detailed instructions on configuring Google Cloud SQL for external access, refer to the <a target="_blank" href="https://docs.dbconvert.com/connections/google-cloud-sql.html?ref=dbconvert.com">Google Cloud SQL Connection Guide</a> in the DBConvert Streams documentation.</p>
<p>### </p>
<h2 id="heading-step-4-obtain-and-configure-your-api-key">Step 4: Obtain and Configure Your API Key</h2>
<p>When you first open the DBConvert Streams web interface, you'll need to provide an API key:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056675990/edd3b218-b860-4adb-a982-0eec75dd134b.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<ol>
<li>Visit <a target="_blank" href="https://streams.dbconvert.com/account?ref=dbconvert.com">https://streams.dbconvert.com/account</a> in another tab</li>
<li>Sign up or log in with your preferred authentication method</li>
<li>Copy your API key from the account dashboard</li>
<li>Return to your DBConvert Streams interface on your Droplet</li>
<li>Paste the API key and click <strong>Continue</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056677123/3363aa62-200d-42b7-93d2-3e1f7634c185.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" />
<em>get your API Key</em></p>
<p>This activates your free trial with 5GB of data transfer - more than enough for most small to medium database migrations.</p>
<p>DBConvert Streams offers a generous free trial that includes:</p>
<ul>
<li><strong>5GB of data transfer</strong></li>
<li><strong>14 days of unlimited access to all features</strong></li>
<li><strong>No credit card required to start</strong></li>
</ul>
<p>This gives you ample opportunity to test the migration process before committing to a paid plan, making it risk-free to try for your DigitalOcean managed database migration project.</p>
<h2 id="heading-step-5-connect-your-source-database-google-cloud-sql">Step 5: Connect Your Source Database (Google Cloud SQL)</h2>
<p>Now that your environment is set up, it's time to connect to your Google Cloud SQL database:</p>
<ol>
<li>From the DBConvert Streams dashboard, click <strong>Create Connection</strong></li>
<li>Select MySQL database type</li>
<li>Enter a descriptive name like "Google Cloud SQL - Sakila"</li>
<li>Enter the connection details from Google Cloud SQL:<ul>
<li><strong>Server</strong> : Your instance's public IP address</li>
<li><strong>Port</strong> : 3306 for MySQL</li>
<li><strong>User ID</strong> : Your database username</li>
<li><strong>Password</strong> : Your database password</li>
<li><strong>Database</strong> : Your database name</li>
</ul>
</li>
<li>If using SSL (recommended), enable it and upload any certificates</li>
<li>Select Database.</li>
<li>Optionally click <strong>Test Connection</strong> to verify connectivity</li>
<li>Click <strong>Update</strong>  </li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056678323/1532e510-2fab-4eec-a361-24c9fb8eeaa0.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<h2 id="heading-step-6-connect-your-target-database-digitalocean">Step 6: Connect Your Target Database (DigitalOcean)</h2>
<p>Next, set up the connection to your new DigitalOcean database:</p>
<ol>
<li>Click <strong>Create Connection</strong> again</li>
<li>Select PostgreSQL database type</li>
<li>Enter a name like "DigitalOcean - Sakila"</li>
<li>Enter the DigitalOcean database connection details:<ul>
<li><strong>Server</strong> : The host shown in your DigitalOcean database connection details</li>
<li><strong>Port</strong> : 25060 (DigitalOcean's default port for managed databases)</li>
<li><strong>User ID</strong> : The default user (typically "doadmin")</li>
<li><strong>Password</strong> : The password shown in your connection details</li>
<li><strong>Database</strong> : Your database name</li>
</ul>
</li>
<li>Enable SSL and select "Require" or "Verify-CA" mode</li>
<li>For PostgreSQL, you may need to specify the schema (usually "public")</li>
<li>Click <strong>Test Connection</strong> to verify</li>
<li>Click <strong>Update</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056679060/69129693-f495-4cb5-bd7e-0f0f4c9d4b5c.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" />
<em>add target db</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056680215/fa80015b-45b8-4b22-ab03-7486a3efe99b.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" />
<em>two connections are available</em></p>
<h2 id="heading-step-7-configure-your-migration-stream">Step 7: Configure Your Migration Stream</h2>
<p>Now it's time to set up the actual migration process:</p>
<ul>
<li>Click <strong>Create Stream</strong> from the dashboard</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056681372/d6f2891a-6fc6-4fcf-8ae6-7e26f1056ad4.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" />
<em>Create New Stream</em></p>
<ul>
<li>Select your Google Cloud SQL connection as the source and click <strong>Next</strong></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056682495/0cbf28ac-3c79-4414-ab45-74cc5a90da27.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<ul>
<li>You'll see a list of tables from your database - select the ones you want to migrate (or Select All)</li>
<li>Choose the data transfer mode:</li>
</ul>
<p><strong>– Convert/Migrate</strong> : Best for one-time migrations (what we need now)</p>
<p><strong>– CDC/Stream</strong> : For continuous real-time replication (useful for zero-downtime migrations)</p>
<p>For our sample we choose Convert/Migrate mode</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056684051/d0d5e0ed-5212-4e7a-9004-741b593d7323.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<p>Select your DigitalOcean database as the target</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056685470/63e82a8d-fe6c-4f43-a6aa-142e738769d4.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<p>Review your configuration and click <strong>Save</strong></p>
<h2 id="heading-step-8-start-and-monitor-the-transfer">Step 8: Start and Monitor the Transfer</h2>
<ol>
<li>From the streams page, click <strong>Start</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056686319/afc88a49-dfc8-4d63-a176-2d37dcc83f8d.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<p>The dashboard will show real-time progress of your migration:</p>
<ul>
<li>Tables being processed</li>
<li>Number of records transferred</li>
<li>Transfer speed</li>
<li>Estimated completion time</li>
</ul>
<p>During the transfer, you can:</p>
<ul>
<li>View detailed logs to monitor the process</li>
<li>Pause the transfer if needed (and resume later)</li>
<li>Monitor system resources on your Droplet</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056687036/9ef3e4d4-2faf-4c49-b802-c15b18a298d7.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<p>For larger databases, you may want to set up Droplet monitoring in the DigitalOcean dashboard to ensure you have sufficient resources for the migration.</p>
<h2 id="heading-step-9-verify-your-data">Step 9: Verify Your Data</h2>
<p>Once the process completes, it's crucial to verify that your data has been transferred correctly:</p>
<ol>
<li>Connect to your DigitalOcean database using the command line or a GUI tool like TablePlus, DBeaver, or DigitalOcean's built-in console:</li>
</ol>
<pre><code>PGPASSWORD=&lt;password&gt; psql -h &lt;do-host&gt; -p 25060 -U doadmin defaultdb
</code></pre><ol>
<li>Run verification queries to check data integrity:</li>
</ol>
<pre><code>-- List all tables <span class="hljs-keyword">in</span> the database
\dt

-- Get row counts <span class="hljs-keyword">for</span> all tables
SELECT 
    schemaname <span class="hljs-keyword">as</span> schema,
    relname <span class="hljs-keyword">as</span> table_name,
    n_live_tup <span class="hljs-keyword">as</span> row_count
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;

-- Check table sizes including indexes
SELECT
    table_schema,
    table_name,
    pg_size_pretty(pg_total_relation_size(<span class="hljs-string">'"'</span> || table_schema || <span class="hljs-string">'"."'</span> || table_name || <span class="hljs-string">'"'</span>)) <span class="hljs-keyword">as</span> total_size
FROM information_schema.tables
WHERE table_schema = <span class="hljs-string">'public'</span>
ORDER BY pg_total_relation_size(<span class="hljs-string">'"'</span> || table_schema || <span class="hljs-string">'"."'</span> || table_name || <span class="hljs-string">'"'</span>) DESC;
</code></pre><ol>
<li>Compare these results with the same queries run on your Google Cloud SQL instance to ensure all data has been transferred correctly.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056688033/a443c22a-72f2-4119-9690-23946eb16cd4.png" alt="&quot;Escape Google Cloud SQL: Migrate to DigitalOcean with MySQL or PostgreSQL (No-Code Guide)&quot;" /></p>
<ol>
<li>Optionally run some more verification queries to make sure all data copied successfully. In your case, these queries will be according to your individual needs.</li>
</ol>
<pre><code>-- List all tables
\dt

-- Get row counts <span class="hljs-keyword">for</span> key tables <span class="hljs-keyword">with</span> sample data
SELECT <span class="hljs-string">'customers'</span> <span class="hljs-keyword">as</span> table_name, COUNT(*) <span class="hljs-keyword">as</span> row_count FROM customer
UNION ALL
SELECT <span class="hljs-string">'films'</span> <span class="hljs-keyword">as</span> table_name, COUNT(*) <span class="hljs-keyword">as</span> row_count FROM film
UNION ALL
SELECT <span class="hljs-string">'rentals'</span> <span class="hljs-keyword">as</span> table_name, COUNT(*) <span class="hljs-keyword">as</span> row_count FROM rental
UNION ALL
SELECT <span class="hljs-string">'payments'</span> <span class="hljs-keyword">as</span> table_name, COUNT(*) <span class="hljs-keyword">as</span> row_count FROM payment;

-- Verify data integrity <span class="hljs-keyword">with</span> sample queries
-- Check total revenue
SELECT SUM(amount) <span class="hljs-keyword">as</span> total_revenue FROM payment;

-- Check top <span class="hljs-number">5</span> rented films
SELECT f.title, COUNT(*) <span class="hljs-keyword">as</span> rental_count
FROM rental r
JOIN inventory i ON r.inventory_id = i.inventory_id
JOIN film f ON i.film_id = f.film_id
GROUP BY f.title
ORDER BY rental_count DESC
LIMIT <span class="hljs-number">5</span>;

-- Verify customer data
SELECT COUNT(*) <span class="hljs-keyword">as</span> active_customers
FROM customer
WHERE active = <span class="hljs-number">1</span>;
</code></pre><h2 id="heading-step-10-update-your-application">Step 10: Update Your Application</h2>
<p>Once you've verified your data, it's time to update your application to use the new DigitalOcean database:</p>
<ol>
<li>Update your application's database connection settings:<ul>
<li>Host: Your DigitalOcean database hostname</li>
<li>Port: 25060</li>
<li>Username: doadmin (or your custom user)</li>
<li>Password: Your database password</li>
<li>Database name: Your database name</li>
<li>SSL: Required (usually)</li>
</ul>
</li>
<li>If you're using managed app platforms like DigitalOcean App Platform, update your environment variables with the new database connection details.</li>
</ol>
<p>## </p>
<h2 id="heading-why-choose-dbconvert-streams-for-your-digitalocean-migration"><strong>Why Choose DBConvert Streams for Your DigitalOcean Migration?</strong></h2>
<ul>
<li>User-friendly interface that doesn't require deep database expertise</li>
<li>Automated schema conversion between different database types</li>
<li><strong>Cross-database conversion</strong> between PostgreSQL and MySQL</li>
<li>Real-time monitoring of the migration process</li>
<li>Flexible migration options including one-time transfers and continuous replication</li>
<li>Secure credential management with encrypted connections</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Migrating from Google Cloud SQL to DigitalOcean doesn't have to be complex or risky. With DBConvert Streams, you can perform the migration efficiently while maintaining data integrity. DigitalOcean's straightforward managed database offerings provide an excellent destination for your data, with predictable pricing and developer-friendly tools.</p>
<p>After completing this migration, you'll benefit from DigitalOcean's simplified database management, clear pricing structure, and performance optimized for developer workloads. Most importantly, you'll spend less time managing your database infrastructure and more time building your application.</p>
<p>Ready to start your migration? Visit <a target="_blank" href="https://marketplace.digitalocean.com/apps/dbconvert-streams?ref=dbconvert.com"><strong>https://marketplace.digitalocean.com/apps/dbconvert-streams</strong></a> to deploy the DBConvert Streams 1-Click App and experience the simplest way to move your database to DigitalOcean.</p>
]]></content:encoded></item><item><title><![CDATA[Announcing DBConvert Streams: First Public Release of Our Cloud-Native Database Migration Platform]]></title><description><![CDATA[title: Announcing DBConvert Streams: First Public Release of Our Cloud-Native Database Migration Platform
published: true
date: 2025-02-24 11:48:47 UTC
tags: database, replication, postgres, mysql
canonical_url: https://dbconvert.com/blog/dbconvert-s...]]></description><link>https://dbconvert.hashnode.dev/announcing-dbconvert-streams-first-public-release-of-our-cloud-native-database-migration-platform</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/announcing-dbconvert-streams-first-public-release-of-our-cloud-native-database-migration-platform</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Mon, 24 Feb 2025 11:48:47 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: Announcing DBConvert Streams: First Public Release of Our Cloud-Native Database Migration Platform
published: true
date: 2025-02-24 11:48:47 UTC
tags: database, replication, postgres, mysql</p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogdbconvert-streams-release">canonical_url: https://dbconvert.com/blog/dbconvert-streams-release/</h2>
<h2 id="heading-introduction">Introduction</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056692732/66e6654d-a85a-4665-89ab-a3440aff4d12.webp" alt="Announcing DBConvert Streams: First Public Release of Our Cloud-Native Database Migration Platform" /></p>
<p>Database migration and synchronization have long been critical challenges for organizations managing data across different platforms. Whether moving from MySQL to PostgreSQL, setting up real-time data replication, or maintaining synchronized databases across different regions, these operations often involve complex processes, potential downtime, and significant technical overhead.</p>
<p>While DBConvert's existing solutions at <a target="_blank" href="https://dbconvert.com/?ref=dbconvert.com">dbconvert.com</a> have served users well as Windows desktop applications, today's cloud-centric world demands a different approach. That's why we're excited to introduce <a target="_blank" href="https://streams.dbconvert.com/?ref=dbconvert.com">DBConvert Streams</a>, our newest addition to the DBConvert family of products. Built from the ground up as a cloud-native solution, DBConvert Streams runs natively on Linux environments - the dominant platform for modern hosting providers and cloud infrastructure. This first public release focuses on robust support for MySQL and PostgreSQL databases, delivering powerful capabilities for both one-time migrations and continuous real-time replication between these popular database platforms.</p>
<h2 id="heading-core-capabilities">Core Capabilities</h2>
<h3 id="heading-universal-database-compatibility">Universal Database Compatibility</h3>
<p>DBConvert Streams handles data transfer between MySQL and PostgreSQL databases, regardless of where they're hosted. Our intelligent schema mapping automatically handles the complexity of different database types and cloud platforms.</p>
<p><strong>Supported Databases:</strong></p>
<ul>
<li>MySQL and compatible databases (MariaDB, SingleStore)</li>
<li>PostgreSQL and compatible databases (CockroachDB)</li>
<li>Cloud-managed databases:<ul>
<li>Amazon RDS/Aurora (MySQL and PostgreSQL)</li>
<li>Google Cloud SQL</li>
<li>Azure Database</li>
<li>DigitalOcean Managed Databases</li>
</ul>
</li>
</ul>
<p>Whether you're migrating from MySQL to PostgreSQL, synchronizing between cloud providers, or replicating from cloud to on-premises, DBConvert Streams manages the entire process automatically.</p>
<h3 id="heading-two-powerful-operating-modes">Two Powerful Operating Modes</h3>
<h4 id="heading-real-time-change-data-capture-cdc">Real-time Change Data Capture (CDC)</h4>
<p>DBConvert Streams leverages native database capabilities - MySQL's binary logs and PostgreSQL's Write-Ahead Logs (WAL) - to capture and replicate changes in real-time with:</p>
<ul>
<li>Zero-downtime operation</li>
<li>Minimal source impact</li>
<li>Immediate change propagation</li>
<li>Complete capture of all data modifications</li>
</ul>
<h4 id="heading-fast-data-migration">Fast Data Migration</h4>
<p>For one-time transfers, DBConvert Streams employs intelligent chunking technology that:</p>
<ul>
<li>Optimizes large-scale transfers</li>
<li>Provides real-time monitoring</li>
<li>Ensures data consistency</li>
<li>Automatically handles schema conversion</li>
</ul>
<h3 id="heading-built-in-monitoring-and-security">Built-in Monitoring and Security</h3>
<p>Every aspect of data transfer is observable through comprehensive dashboards and metrics, while security is ensured through:</p>
<ul>
<li>SSL/TLS encryption for all database connections</li>
<li>Secure credential management via HashiCorp Vault</li>
<li>API key authentication</li>
<li>Detailed audit logging</li>
</ul>
<h2 id="heading-technical-architecture">Technical Architecture</h2>
<p>DBConvert Streams is built on a modern, distributed architecture designed for reliability and scalability. The platform consists of three main components:</p>
<ol>
<li><strong>API Server</strong> : Manages stream configurations and user interactions</li>
<li><strong>Source Reader</strong> : Handles data extraction from source databases</li>
<li><strong>Target Writer</strong> : Manages writing to destination databases</li>
</ol>
<p>This architecture is supported by enterprise-grade infrastructure:</p>
<ul>
<li>NATS for reliable message streaming</li>
<li>HashiCorp Vault for secure credential management</li>
<li>Consul for service discovery and configuration</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056694046/a833614e-d8fc-43bd-ae44-8d15c32a0554.png" alt="Announcing DBConvert Streams: First Public Release of Our Cloud-Native Database Migration Platform" />
<em>dbconvert streams architecture</em></p>
<h2 id="heading-practical-use-cases">Practical Use Cases</h2>
<h3 id="heading-real-time-analytics">Real-time Analytics</h3>
<ul>
<li>Replicate transaction data between OLTP and analytics platforms in any direction (MySQL to PostgreSQL or PostgreSQL to MySQL)</li>
<li>Maintain live reporting systems with minimal latency, regardless of source or target database type</li>
<li>Enable real-time business intelligence without impacting production databases</li>
</ul>
<h3 id="heading-cloud-migration">Cloud Migration</h3>
<ul>
<li>Transfer data freely between any combination of cloud and on-premises databases</li>
<li>Move data in any direction: cloud-to-cloud, cloud-to-on-premises, or on-premises-to-cloud</li>
<li>Switch between cloud providers with automated schema conversion (e.g., AWS Aurora to Azure Database or vice versa)</li>
<li>Create development environments with production data from any source to any target</li>
</ul>
<h3 id="heading-system-modernization">System Modernization</h3>
<ul>
<li>Transition from legacy MySQL systems to modern PostgreSQL platforms</li>
<li>Maintain synchronized systems during gradual migrations</li>
<li>Enable hybrid deployments during transition periods</li>
</ul>
<h2 id="heading-getting-started">Getting Started</h2>
<p>DBConvert Streams offers flexible deployment options to suit different environments. Visit our <a target="_blank" href="https://streams.dbconvert.com/deploy?ref=dbconvert.com">deployment guide</a> to choose between Docker containers or binary installation based on your needs.</p>
<p>After installation, the intuitive web interface guides you through:</p>
<ol>
<li>Creating database connections</li>
<li>Configuring your first stream</li>
<li>Monitoring transfer progress</li>
<li>Managing ongoing operations</li>
</ol>
<p>Visit our <a target="_blank" href="https://streams.dbconvert.com/get-started?ref=dbconvert.com">getting started guide</a> for detailed instructions.</p>
<h2 id="heading-modern-web-interface-benefits">Modern Web Interface Benefits</h2>
<p>The DBConvert Streams dashboard provides a modern web interface that offers:</p>
<ul>
<li>Real-time monitoring of data transfer progress and system metrics</li>
<li>Visual configuration of database connections with instant validation</li>
<li>Point-and-click stream setup without complex configuration files</li>
<li>Comprehensive overview of all your streams in one place</li>
<li>Access from any browser without installing desktop software</li>
<li>Team-friendly interface for collaborative database operations</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056695661/5ea1879c-851d-4454-ad80-89569c6ebf2f.png" alt="Announcing DBConvert Streams: First Public Release of Our Cloud-Native Database Migration Platform" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056696826/f7ed5d8b-ea49-4cd6-9838-e171581f929f.png" alt="Announcing DBConvert Streams: First Public Release of Our Cloud-Native Database Migration Platform" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056697981/d4a6a620-861f-4ade-a1db-3f75f5daa19f.png" alt="Announcing DBConvert Streams: First Public Release of Our Cloud-Native Database Migration Platform" /></p>
<h2 id="heading-ia"> </h2>
<p>Future Development</p>
<p>While this initial release focuses on MySQL and PostgreSQL support, DBConvert Streams is built for expansion. Our roadmap includes:</p>
<ul>
<li>Support for additional database platforms</li>
<li>Enhanced transformation capabilities</li>
<li>Advanced monitoring features</li>
<li>Expanded cloud integration options</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>DBConvert Streams represents a significant step forward in database migration and replication technology. By focusing initially on MySQL and PostgreSQL support, we've created a robust foundation that delivers immediate value while setting the stage for future expansion.</p>
<p>Start with a 10-day free trial that includes:</p>
<ul>
<li>5GB data transfer limit during the trial period</li>
<li>All features fully enabled</li>
<li>Option to upgrade to full data transfer limits by adding payment details during trial</li>
<li>No payment required during trial period</li>
</ul>
<p>Ready to transform your database operations? Visit <a target="_blank" href="https://streams.dbconvert.com/?ref=dbconvert.com">streams.dbconvert.com</a> to start your free trial, or explore our comprehensive documentation at <a target="_blank" href="https://docs.dbconvert.com/streams?ref=dbconvert.com">docs.dbconvert.com/streams</a> to learn more.</p>
]]></content:encoded></item><item><title><![CDATA[ChatGPT: Your Guide to SQL Query Translation between Databases.]]></title><description><![CDATA[title: ChatGPT: Your Guide to SQL Query Translation between Databases.
published: true
date: 2024-05-24 16:49:52 UTC
tags: chatgpt,ai,sql,database
canonical_url: https://dbconvert.com/blog/using-chatgpt-for-sql-query-translation/
 
Introduction
Every...]]></description><link>https://dbconvert.hashnode.dev/chatgpt-your-guide-to-sql-query-translation-between-databases</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/chatgpt-your-guide-to-sql-query-translation-between-databases</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Fri, 24 May 2024 16:49:52 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: ChatGPT: Your Guide to SQL Query Translation between Databases.
published: true
date: 2024-05-24 16:49:52 UTC
tags: chatgpt,ai,sql,database</p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogusing-chatgpt-for-sql-query-translation">canonical_url: https://dbconvert.com/blog/using-chatgpt-for-sql-query-translation/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056701645/0750e6c5-4892-4a7a-8623-117674c8a76d.jpeg" alt="ChatGPT: Your Guide to SQL Query Translation between Databases." /></p>
<h2 id="heading-introduction">Introduction</h2>
<p>Everyone knows that ChatGPT is perfect for translating between many human languages. But did you know that this powerful language model can also excel at converting SQL queries between various database dialects?</p>
<p>Whether you are transitioning from MySQL to PostgreSQL, SQL Server to Oracle, or any other combination, ChatGPT can assist in accurately translating your SQL queries. This capability extends beyond simple syntax changes, providing insights into how database systems handle data types, functions, and constraints. By leveraging ChatGPT for SQL translation, you can ensure a smoother and more efficient transition between database systems, maintaining data integrity and query performance.</p>
<h2 id="heading-understanding-the-challenge">Understanding the Challenge</h2>
<p>Translating SQL queries between different database systems takes a lot of work. Each database system, be it MySQL, PostgreSQL, SQL Server, or Oracle, has its own distinct SQL dialect, encompassing specific syntax, functions, data types, and constraints. These variations can present substantial hurdles during migration.</p>
<h3 id="heading-example1-auto-increment-columns">Example1: Auto-Increment Columns</h3>
<p><strong>MySQL:</strong></p>
<p>In MySQL, the AUTO_INCREMENT keyword defines an auto-incrementing primary key.</p>
<pre><code>CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(<span class="hljs-number">100</span>)
);
</code></pre><p><strong>PostgreSQL:</strong></p>
<p>In PostgreSQL, you use SERIAL to auto-increment fields.</p>
<pre><code>CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(<span class="hljs-number">100</span>)
);
</code></pre><p><strong>SQL Server:</strong></p>
<p>In SQL Server, the IDENTITY property defines an auto-incrementing primary key.</p>
<pre><code>CREATE TABLE users (
id INT IDENTITY(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) PRIMARY KEY,
name NVARCHAR(<span class="hljs-number">100</span>) NOT NULL
);
</code></pre><p><strong>Oracle:</strong></p>
<p>In Oracle, since version 12c, the IDENTITY Column method has been recommended.</p>
<pre><code>CREATE TABLE users ( 
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 
name VARCHAR2(<span class="hljs-number">100</span>) 
);
</code></pre><p>In versions below 12c, Oracle uses a complex sequence and trigger mechanism.</p>
<h3 id="heading-example-2-string-functions">Example 2: String Functions</h3>
<p><strong>MySQL:</strong></p>
<p>The CONCAT_WS function in MySQL concatenates strings with a specified separator.</p>
<pre><code>SELECT CONCAT_WS(<span class="hljs-string">'-'</span>, first_name, last_name)
FROM users;
</code></pre><p><strong>PostgreSQL:</strong></p>
<p>In PostgreSQL, you can use the CONCAT function along with the separator.</p>
<pre><code>SELECT CONCAT(first_name, <span class="hljs-string">'-'</span>, last_name)
FROM users;
</code></pre><p><strong>Oracle:</strong></p>
<p>You can achieve the same result in Oracle using the <code>||</code> operator for string concatenation.</p>
<pre><code>SELECT first_name || <span class="hljs-string">'-'</span> || last_name AS full_name
FROM users;
</code></pre><p>Additionally, there are variations in how each system handles transactions, error handling, and even indexing.</p>
<p>Moreover, some database systems include proprietary features that lack direct equivalents in other systems. This situation often makes straightforward translation impossible, requiring the development of alternative solutions or workarounds to achieve the same functionality.</p>
<p>Grasping these challenges is pivotal for a successful migration. It necessitates a profound understanding of the source and target database systems and the intricacies of their SQL dialects. This is where ChatGPT shines. With its extensive language model capabilities, it can help identify and tackle these differences, offering precise translations and guiding users through the intricacies of the transition process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056702424/7264080d-9fd0-4383-a3a8-c66859fabb4c.jpeg" alt="ChatGPT: Your Guide to SQL Query Translation between Databases." /></p>
<h2 id="heading-how-chatgpt-can-help">How ChatGPT Can Help</h2>
<p>ChatGPT can be an invaluable tool for developers and database administrators tasked with migrating SQL queries and database structures between different systems. Here's how ChatGPT can assist in this process:</p>
<h3 id="heading-accurate-query-translation">Accurate Query Translation.</h3>
<p>ChatGPT excels at understanding the nuances of various SQL dialects. It can accurately translate SQL queries from one database system to another, ensuring the syntax and functions are correctly adapted. For example, it can translate a MySQL <code>GROUP_CONCAT</code> function to PostgreSQL's <code>STRING_AGG</code> function or convert MySQL's <code>CURDATE()</code> to PostgreSQL's <code>CURRENT_DATE</code>. This ensures that the queries perform the desired operations in the target database system.</p>
<h3 id="heading-handling-data-types-and-constraints">Handling Data Types and Constraints.</h3>
<p>Different database systems have unique ways of defining data types and constraints. ChatGPT can help by identifying these differences and providing the correct translations, for instance, converting MySQL's <code>AUTO_INCREMENT</code> to PostgreSQL's <code>SERIAL</code>, or SQL Server's <code>IDENTITY</code> to Oracle's sequence and trigger mechanism. By doing so, ChatGPT helps maintain data integrity and consistency during the migration.</p>
<h3 id="heading-providing-alternative-solutions">Providing Alternative Solutions</h3>
<p>Some proprietary features in one database system may not have direct equivalents in another. ChatGPT can suggest alternative solutions or workarounds to achieve the same functionality in such cases. For example, if a specific function or feature in MySQL does not exist in PostgreSQL, ChatGPT can propose a combination of other functions or custom logic to replicate the behavior.</p>
<h3 id="heading-guiding-through-complex-transitions">Guiding Through Complex Transitions</h3>
<p>ChatGPT can guide users through complex transitions, highlighting potential changes in query execution or outcomes due to differences in how database systems interpret and handle SQL. This includes differences in transaction handling, error management, indexing, and case sensitivity. By providing insights and recommendations, ChatGPT helps ensure a smoother transition.</p>
<h3 id="heading-notifying-about-potential-differences">Notifying About Potential Differences</h3>
<p>Knowing any differences that might affect query results or performance in the target database system is crucial. ChatGPT can notify users of these potential discrepancies and suggest how to adapt queries to ensure consistent results. For example, it can highlight differences in date functions, string concatenation, or conditional logic and make appropriate adjustments.</p>
<hr />
<h2 id="heading-chatgpt-use-cases-for-sql-related-tasks">ChatGPT use cases for SQL-related tasks.</h2>
<p>Using ChatGPT for SQL tasks extends beyond simple query translation. Here are several practical use cases where ChatGPT can assist with SQL-related tasks:</p>
<p><a target="_blank" href="https://dbconvert.com/blog/chatgpt-sql-practices/">10 Ways ChatGPT is Revolutionizing SQL Practices.</a></p>
<p>It provides an in-depth look at how ChatGPT is successfully used in SQL practices.</p>
<h2 id="heading-common-pitfalls-amp-solutions">Common Pitfalls &amp; Solutions</h2>
<h3 id="heading-pitfall-1-misinterpretation-of-query-intent">Pitfall 1: Misinterpretation of Query Intent</h3>
<p>Sometimes, ChatGPT may not correctly interpret the intent of the SQL query, leading to incorrect translations between SQL dialects.</p>
<h3 id="heading-solution">Solution:</h3>
<p>Be clear and specific when inputting your SQL queries. If you notice a misinterpretation, try rephrasing your query or breaking it down into simpler parts.</p>
<h3 id="heading-pitfall-2-unfamiliarity-with-database-specific-features">Pitfall 2: Unfamiliarity with Database-specific Features.</h3>
<p>Some databases have proprietary features that others do not, which can lead to confusion or errors when translating queries.</p>
<h3 id="heading-solution-1">Solution:</h3>
<p>Before migrating to a new database, familiarize yourself with the specific features and syntax of that system. ChatGPT can provide alternative solutions for features that do not have direct equivalents.</p>
<h3 id="heading-pitfall-3-overlooking-data-types-and-constraints">Pitfall 3: Overlooking Data Types and Constraints.</h3>
<p>Different databases handle data types and constraints differently. Overlooking these differences can lead to data inconsistency.</p>
<h3 id="heading-solution-2">Solution:</h3>
<p>Always verify the translated queries and check for data type and constraint translations. ChatGPT can assist in identifying these differences and providing the correct translations.</p>
<h3 id="heading-pitfall-4-ignoring-potential-performance-differences">Pitfall 4: Ignoring Potential Performance Differences</h3>
<p>The performance of a query can vary between different database systems due to differences in how they handle SQL.</p>
<h3 id="heading-solution-3">Solution:</h3>
<p>Be aware of potential performance differences. Use ChatGPT to obtain insights into how different database systems handle SQL and adapt your queries accordingly.<br />Remember, while ChatGPT is an excellent tool for SQL tasks, it's crucial to double-check the translations and understand the nuances of different database systems.</p>
<h2 id="heading-future-developments">Future Developments:</h2>
<p>Given the dynamic nature of both AI and SQL development, we can expect several advancements:</p>
<ol>
<li><strong>Improved Accuracy:</strong> Future versions of ChatGPT are likely to offer even more accurate translations of SQL queries between different database dialects. This will make it easier for developers to switch between different SQL systems.</li>
<li><strong>Expanded Database Support:</strong> As new database systems and SQL dialects emerge, ChatGPT will likely expand its support to include these new technologies, making it even more versatile.</li>
<li><strong>Detailed Explanation of Queries:</strong> Future iterations may offer more detailed explanations of complex SQL queries, making it easier for developers to understand and optimize their database interactions.</li>
<li><strong>Integration with More Tools:</strong> We can anticipate tighter integration with various database management and development tools, providing developers with a more seamless and efficient workflow.</li>
<li><strong>Active Learning:</strong> Using AI, ChatGPT could learn from its interactions, improving its responses over time and providing even more value to developers.</li>
<li><strong>Enhanced Performance Optimizations:</strong> With advancements in AI, ChatGPT could provide suggestions for performance optimization in SQL queries, helping developers improve their databases' efficiency and speed.</li>
</ol>
<p><a target="_blank" href="https://chatgpt.com/g/g-4s4xPqO0B-sql-companion">SQL Companion in GPT Store. Try it now!</a></p>
<p><a target="_blank" href="https://t.me/dbconvert_bot">Free telegram bot streamlines SQL related tasks</a></p>
<h3 id="heading-dbconvert-tools-for-database-migration-and-synchronization">DBConvert Tools for Database Migration and Synchronization</h3>
<p>DBConvert offers powerful tools for automating database migration and synchronization across various systems, such as MySQL, PostgreSQL, SQL Server, and Oracle.</p>
<p><a target="_blank" href="https://dbconvert.com/dbconvert-studio/?ref=dbconvert.com"><strong>DBConvert Studio</strong></a>simplifies cross-database migration with features like automated schema conversion, data type mapping, and transformation. Its user-friendly interface allows easy setup of source and target connections, scheduled migrations, and thorough data transfer processes.</p>
<p><strong><a target="_blank" href="https://stream.dbconvert.com/?ref=dbconvert.com">DBConvert Streams</a></strong> integrates real-time data using Change Data Capture (CDC) technology. It ensures continuous, multidirectional synchronization, ideal for maintaining high data availability and consistency across multiple databases. Both tools provide robust error handling and logging, ensuring reliable and efficient database management.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the ever-evolving landscape of database management, transitioning between different SQL dialects can be daunting. Each database system, whether MySQL, PostgreSQL, SQL Server, or Oracle, has its unique set of syntax, functions, and constraints. Navigating these differences is crucial for maintaining data integrity and ensuring optimal performance during migrations.</p>
<p>ChatGPT emerges as a powerful ally in this process, offering accurate translations and insightful guidance. By leveraging its capabilities, developers and database administrators can overcome the complexities of SQL dialect variations. From translating queries and handling data types to suggesting alternative solutions and highlighting potential performance differences, ChatGPT provides comprehensive support throughout the migration journey.</p>
]]></content:encoded></item><item><title><![CDATA[Your Roadmap to Database Conversion Excellence.]]></title><description><![CDATA[title: Your Roadmap to Database Conversion Excellence.
published: true
date: 2023-09-14 14:46:02 UTC
tags: database,mysql,postgres
canonical_url: https://dbconvert.com/blog/a-comprehensive-guide-to-database-conversion/
 
Introduction:
Section 1: Plan...]]></description><link>https://dbconvert.hashnode.dev/your-roadmap-to-database-conversion-excellence</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/your-roadmap-to-database-conversion-excellence</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Thu, 14 Sep 2023 14:46:02 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: Your Roadmap to Database Conversion Excellence.
published: true
date: 2023-09-14 14:46:02 UTC
tags: database,mysql,postgres</p>
<h2 id="heading-canonicalurl-httpsdbconvertcombloga-comprehensive-guide-to-database-conversion">canonical_url: https://dbconvert.com/blog/a-comprehensive-guide-to-database-conversion/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056705661/7d43a5f8-8ea1-4bab-a3d4-1f9b02178b91.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p><strong>Introduction:</strong></p>
<p><strong>Section 1: Planning Your Database Migration</strong></p>
<p><strong>Section 2: Preparing for the Migration</strong></p>
<p><strong>Section 3: Performing the Database Conversion</strong></p>
<p><strong>Section 4: Handling Data and Application Code</strong></p>
<p><strong>Section 5: Post-Migration Testing and Verification</strong></p>
<p><strong>Section 6: Monitoring and Maintenance</strong></p>
<p><strong>Section 7: Best Practices and Tips</strong></p>
<p><strong>Conclusion</strong></p>
<hr />
<h2 id="heading-introduction">Introduction:</h2>
<p>Database management systems (DBMS) are the backbone of modern applications and are pivotal in storing and managing critical data. As applications evolve and expand, the necessity for migrating from one DBMS to another frequently arises. This comprehensive guide will delve into the intricate database conversion process, addressing common challenges encountered when transitioning between various DBMS platforms. Whether you're moving from MySQL to PostgreSQL, Oracle to SQL Server, or any other combination, this guide aims to provide valuable insights into seamless database migration.</p>
<h3 id="heading-the-significance-of-database-migration">The Significance of Database Migration:</h3>
<p>Database migration is a significant undertaking that various factors can drive. It's a strategic move to ensure your data infrastructure aligns with your application's evolving requirements. Common motivations for database migration include:</p>
<ol>
<li><strong>Performance Optimization:</strong> Over time, an application's performance requirements can change. Migrating to a different DBMS can provide better scalability and performance capabilities.</li>
<li><strong>Feature Set:</strong> For example, MySQL and PostgreSQL exhibit unique sets of features. The article <a target="_blank" href="https://dev.to/slotix/mysql-vs-postgresql-in-2023-2o53">"MySQL vs. PostgreSQL"</a> comprehensively analyzes the tangible differences that set MySQL and PostgreSQL apart.</li>
<li><strong>Cost Efficiency:</strong> Cost considerations often play a role. PostgreSQL is known for its robust open-source community, making it an attractive option for those seeking cost-effective solutions.</li>
<li><strong>Vendor Lock-In:</strong> Some organizations migrate to open-source alternatives like PostgreSQL from proprietary systems to avoid vendor lock-in.</li>
</ol>
<h3 id="heading-popular-databases"><strong>Popular Databases:</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056706984/ca7f44a2-ed40-4fe0-b188-7eeeba1412c2.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>MySQL, PostgreSQL, Oracle and MS SQL Server have earned their popularity in relational databases, each with unique strengths.</p>
<h4 id="heading-mysql">MySQL</h4>
<ul>
<li>Speed and performance</li>
<li>Ease of use</li>
<li>Strong community support</li>
</ul>
<p>Excellent for web applications, content management systems, and data-driven websites. Widely adopted by companies of all sizes.</p>
<h4 id="heading-postgresql">PostgreSQL</h4>
<ul>
<li>Custom functions and data types</li>
<li>Advanced JSON support</li>
<li>Full-text search</li>
<li>PostGIS for geospatial data</li>
<li>Extensive extension ecosystem</li>
</ul>
<p>Well-suited for complex data modeling, full-text search, geospatial data, and extensive customization.</p>
<h4 id="heading-oracle">Oracle</h4>
<ul>
<li>Scalability</li>
<li>Security</li>
<li>Comprehensive feature set</li>
</ul>
<p>The top choice for large enterprises and organizations requiring a reliable and robust database management system.</p>
<h4 id="heading-microsoft-sql-server">Microsoft SQL Server</h4>
<ul>
<li>Seamless integration with Microsoft's ecosystem</li>
<li>Ideal for businesses invested in Microsoft technologies</li>
<li>Support for critical data and enterprise-level applications</li>
</ul>
<h4 id="heading-microsoft-access">Microsoft Access</h4>
<ul>
<li>Simple desktop database solution</li>
<li>Good for small-scale projects</li>
<li>Easy to learn and use</li>
</ul>
<p>Commonly used for small businesses and individuals for lightweight database applications.</p>
<h4 id="heading-sqlite">SQLite</h4>
<ul>
<li>Embedded, serverless database</li>
<li>Minimal administration required</li>
<li>Lightweight and fast</li>
</ul>
<p>Ideal for mobile apps, embedded systems, and situations where a small, self-contained database is needed.</p>
<h4 id="heading-firebird">Firebird</h4>
<ul>
<li>Open-source relational database</li>
<li>High performance and scalability</li>
<li>Supports stored procedures and triggers</li>
</ul>
<p>Suitable for applications requiring high-performance data management and support for complex business logic.</p>
<h3 id="heading-the-need-for-migration">The Need for Migration:</h3>
<p>While both MySQL and PostgreSQL have their strengths, there are scenarios where migrating between them becomes essential. For example:</p>
<ul>
<li><strong>Application Growth:</strong> As your application grows and demands more complex features, you might find PostgreSQL's advanced capabilities more suitable.</li>
<li><strong>Data Compatibility:</strong> If your data schema evolves or requires better compatibility with specific data types, migrating to PostgreSQL can be advantageous.</li>
<li><strong>Vendor or Licensing Changes:</strong> MySQL licensing or support changes might prompt migrating to an open-source alternative like PostgreSQL.</li>
<li><strong>Performance Scaling:</strong> If your application experiences increased traffic and demands better performance scaling, PostgreSQL might offer a more robust solution.</li>
</ul>
<p><strong>Reasons for PostgreSQL to MySQL Migration:</strong></p>
<ul>
<li><strong>Application Compatibility:</strong> Transitioning to a MySQL-centric application ecosystem ensures seamless compatibility and minimizes potential issues.</li>
<li><strong>Feature Alignment:</strong> MySQL offers specific features and extensions that better suit your application's needs, especially if reliant on MySQL-specific functions or plugins.</li>
<li><strong>Ecosystem Standardization:</strong> Aligning with an existing MySQL-based database ecosystem simplifies management and maintenance.</li>
<li><strong>Performance Optimization:</strong> MySQL's performance characteristics may better match your application's workload and query patterns, delivering improved query response times and resource usage.</li>
<li><strong>Legacy Integration:</strong> Facilitate integration with legacy systems or third-party applications requiring MySQL compatibility.</li>
</ul>
<p><strong>Integration with Microsoft SQL Server (MSSQL) and Oracle:</strong></p>
<ul>
<li><strong>Microsoft SQL Server (MSSQL)</strong>: MSSQL is an ideal choice for organizations deeply integrated into Microsoft's ecosystem. Its compatibility with Microsoft technologies, including Windows Server and Azure, ensures a cohesive environment for managing and analyzing data. Migrating to MSSQL can strengthen the alignment with Microsoft's suite of tools and services.</li>
<li><strong>Oracle:</strong>  Migrating to Oracle may be warranted when your organization seeks the utmost data reliability and advanced database capabilities.  </li>
</ul>
<p>These considerations underscore the importance of evaluating your specific database requirements and ecosystem when making migration decisions. Whether moving from PostgreSQL to MySQL, integrating with MSSQL, or adopting Oracle, each choice should align with your application's needs and strategic objectives.</p>
<p>As we embark on this guide, we will delve into the intricacies of planning, executing, and optimizing a successful database migration between different database management systems (DBMS). Whether you're a developer, a database administrator, or an IT decision-maker, this guide will equip you with the knowledge and best practices to navigate the complex terrain of database conversion among these powerful DBMSs.</p>
<h2 id="heading-section-1-planning-your-database-migration">Section 1: Planning Your Database Migration</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056707985/882a61e8-843c-4888-8e02-72e427bfab8e.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>Database migration is a complex endeavor that demands careful planning and execution. This section will explore the critical aspects of planning your database migration jobs.</p>
<h3 id="heading-importance-of-planning-and-assessing-your-current-database">Importance of Planning and Assessing Your Current Database:</h3>
<ul>
<li><strong>Understanding Your Current State:</strong> Before embarking on a migration, thoroughly understanding your existing database is crucial. It encompasses analyzing the schema, data types, indexes, and relationships.</li>
<li><strong>Data Volume and Complexity:</strong> Evaluate the volume and complexity of your data. Large datasets or intricate relationships may impact the migration process and require special attention.</li>
<li><strong>Data Integrity and Quality:</strong> Assess the integrity and quality of your data. Identify any inconsistencies, anomalies, or data quality issues that must be addressed during migration.</li>
<li><strong>Dependencies and Applications:</strong> Identify all dependencies on your database, including applications, scripts, and reporting tools. Understand how the migration will impact these dependencies.</li>
<li><strong>Performance Metrics:</strong> Collect performance metrics for your current database. This data will serve as a baseline for evaluating the performance of the migrated database.</li>
</ul>
<h3 id="heading-creating-a-migration-strategy-and-setting-clear-goals">Creating a Migration Strategy and Setting Clear Goals:</h3>
<ul>
<li><strong>Define Clear Objectives:</strong> Clearly articulate the objectives of your migration. Are you seeking improved performance, cost savings, or better compatibility with specific features?</li>
<li><strong>Choose the Right Migration Path:</strong> Decide whether you will perform a homogeneous migration (e.g., MySQL to MySQL) or a heterogeneous migration (e.g., Oracle to PostgreSQL). Your choice will impact the tools and processes you use.</li>
<li><strong>Select Migration Tools:</strong> Research and select the appropriate migration tools and scripts that align with your migration strategy. These tools can help automate various aspects of the migration process.</li>
<li><strong>Data Mapping and Transformation:</strong> Define a data mapping and transformation plan to handle differences in data types, constraints, and schema structures between various database types.</li>
<li><strong>Testing and Validation:</strong> Develop a comprehensive testing plan that includes unit testing, integration testing, and data validation. Ensure that the migrated database meets your performance and functionality goals.</li>
<li><strong>Rollback Plan:</strong> Prepare a rollback plan if unexpected issues arise during migration. This plan should outline steps to revert to the previous state without data loss.</li>
</ul>
<h3 id="heading-potential-challenges-and-how-to-overcome-them">Potential Challenges and How to Overcome Them:</h3>
<h4 id="heading-data-type-and-schema-differences">Data Type and Schema Differences</h4>
<p>MySQL, PostgreSQL, MSSQL have different data types and schema structures. Mapping and transforming data can be complex.</p>
<p><strong>Solution:</strong></p>
<ul>
<li>Define a precise data mapping and transformation strategy.</li>
<li>Utilize available tools for schema conversion.</li>
</ul>
<h4 id="heading-application-compatibility">Application Compatibility</h4>
<p>Applications may have queries or code specific to the DBMS. Compatibility issues can arise.</p>
<p><strong>Solution:</strong></p>
<ul>
<li>Modify and test application code to ensure compatibility with the target DBMS.</li>
</ul>
<h4 id="heading-data-volume-and-downtime">Data Volume and Downtime</h4>
<p>Large datasets and long migration times can result in significant downtime.</p>
<p><strong>Solution:</strong></p>
<ul>
<li>Implement strategies such as data chunking and parallel processing to minimize downtime.</li>
</ul>
<h4 id="heading-data-validation">Data Validation</h4>
<p>Ensuring data integrity and accuracy during migration is essential.</p>
<p><strong>Solution:</strong></p>
<ul>
<li>Develop comprehensive data validation scripts and conduct thorough testing.</li>
</ul>
<h4 id="heading-performance-optimization">Performance Optimization</h4>
<p>The performance of the migrated database may need to meet expectations.</p>
<p><strong>Solution:</strong></p>
<ul>
<li>Continuously monitor and optimize the performance of the new database post-migration.</li>
</ul>
<p>By meticulously planning your database migration, defining clear goals, and understanding the potential challenges, you set the foundation for a successful transition. The following sections will dive into the practical steps in executing the migration, including data mapping, code adaptation, and post-migration testing.</p>
<h2 id="heading-section-2-preparing-for-the-migration">Section 2: Preparing for the Migration</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056708829/531897f9-dc96-4dfa-9884-4ceac52de670.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>A well-prepared foundation is essential for a smooth database migration. This section will explore the prerequisites, backup procedures, and the significance of testing in a controlled environment.</p>
<h3 id="heading-prerequisites-for-the-migration-process">Prerequisites for the Migration Process:</h3>
<ul>
<li><strong>Database Servers:</strong> Ensure your source and target database servers are correctly set up, configured, and accessible.</li>
<li><strong>Migration Tools:</strong> Acquire and install the tools and scripts that align with your migration strategy. Popular tools include <a target="_blank" href="https://dbconvert.com/dbconvert-studio?ref=dbconvert.com">DBConvert Studio</a>,  pgloader, SQL Server Migration Assistant (SSMA) for MSSQL, Oracle SQL Developer for Oracle databases, and MySQL Workbench for schema conversion. </li>
</ul>
<blockquote>
<p><a target="_blank" href="https://dbconvert.com/dbconvert-studio?ref=dbconvert.com">DBConvert Studio</a> offers the flexibility to convert and synchronize data seamlessly in any combination between different database systems.</p>
</blockquote>
<ul>
<li><strong>Access Credentials:</strong> Have the appropriate access credentials for the source and target databases, including usernames and passwords with sufficient privileges.</li>
<li><strong>Network Connectivity:</strong> Confirm that network connectivity between the source and target databases is stable and secure. Ensure that firewalls and security groups allow the necessary traffic.</li>
<li><strong>Target Schema:</strong> Prepare the target schema structure in your target database. Create tables, indexes, constraints, and sequences to match your source database schema. Tools like DBConvert Studio can generate an equivalent schema on the destination database mirroring the source schema.</li>
</ul>
<h3 id="heading-how-to-back-up-your-existing-database">How to Back Up Your Existing Database:</h3>
<ol>
<li><strong>Full Database Backup:</strong></li>
</ol>
<p>Perform a complete source database backup using tools or database management interfaces. This backup ensures that your data is safe in case of unexpected issues during migration.</p>
<p>To backup a MySQL database, you can use the <code>mysqldump</code> command:</p>
<pre><code>mysqldump -u username -p dbname &gt; backup.sql
</code></pre><p>For Oracle databases, you can use the <code>expdp</code> (Data Pump Export) utility:</p>
<pre><code>expdp username/password@tns_alias dumpfile=backup.dmp
</code></pre><p>To backup a PostgreSQL database, you can use the <code>pg_dump</code> command:</p>
<pre><code>pg_dump -U username dbname &gt; backup.sql
</code></pre><p>For SQL Server databases, you can use the <code>sqlcmd</code> utility to generate a backup script:</p>
<pre><code>sqlcmd -S servername -d dbname -U username -P password -Q <span class="hljs-string">"BACKUP DATABASE dbname TO DISK='backup.bak'"</span>
</code></pre><ol start="2">
<li><strong>Backup Verification:</strong></li>
</ol>
<p>After creating the backup, verify its integrity by restoring it to a test environment. Ensure that the restored database is consistent and error-free.</p>
<p><strong>3. Data Consistency During Migration:</strong></p>
<p>Plan to perform a final backup before the migration process begins to capture any changes made to the database during the migration planning phase.</p>
<h3 id="heading-the-importance-of-testing-in-a-controlled-environment">The Importance of Testing in a Controlled Environment:</h3>
<ul>
<li><strong>Create a Sandbox Environment:</strong> Set up a controlled testing environment that mirrors your production environment as closely as possible. This environment should include the target database and any dependent applications.</li>
<li><strong>Migration Dry Run:</strong> Conduct a migration dry run in the sandbox environment. Use a subset of your data to simulate the migration process without affecting the production database. This step allows you to identify and address potential issues before the migration.</li>
<li><strong>Performance Testing:</strong> Assess the performance of the migrated database in the controlled environment. It includes running performance benchmarks and ensuring the database meets your performance expectations.</li>
<li><strong>Functional Testing:</strong> Test all application functionality against the migrated database. Ensure that queries, stored procedures, and application logic work as expected.</li>
<li><strong>Data Validation:</strong> Implement data validation scripts to confirm the accuracy and integrity of the data after migration. Verify that data transformations and mappings are correct.</li>
<li><strong>User Acceptance Testing (UAT):</strong> If applicable, involve end-users in user acceptance testing. Gather feedback and ensure that the migrated system meets user requirements and expectations.</li>
<li><strong>Rollback Testing:</strong> Develop and test your rollback plan in a controlled environment to ensure you can revert to the previous state if necessary.</li>
</ul>
<p>Testing in a controlled environment is paramount to minimize risks and ensure a successful migration. Any issues identified during testing can be addressed before migrating your production database. The following section will explore the migration process, including data mapping, transformation, and code adaptation.</p>
<h2 id="heading-section-3-performing-the-database-conversion">Section 3: Performing the Database Conversion</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056709750/e867c213-7847-4da7-a4e0-7111ab1a89ed.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>Performing a database conversion involves several steps that require careful consideration and execution. This section will guide you through a step-by-step process, provide code examples and scripts, and address data mapping, data type handling, and schema differences.</p>
<h3 id="heading-step-by-step-process-of-database-migration">Step-by-Step Process of Database Migration:</h3>
<ol>
<li><strong>Schema Assessment:</strong> Review the schema of your source database and target database. Identify differences in data types, constraints, and schema structures.</li>
<li><strong>Data Mapping and Transformation:</strong> Create a comprehensive plan for data mapping and transformation. Determine how data from the source db will be mapped to target, considering differences in data types and constraints. </li>
<li><strong>Schema Conversion:</strong> Use migration tools or scripts to convert the schema from the source to destination database syntax. Here's a basic example for converting a table:</li>
</ol>
<pre><code>-- PostgreSQL
CREATE TABLE <span class="hljs-string">"products"</span> (
<span class="hljs-string">"id"</span> SERIAL PRIMARY KEY,
<span class="hljs-string">"name"</span> VARCHAR(<span class="hljs-number">255</span>),
<span class="hljs-string">"price"</span> NUMERIC(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>)
);
</code></pre><p><em>PostgreSQL create table syntax</em></p>
<pre><code><span class="hljs-comment">/* MySQL */</span>
CREATE TABLE <span class="hljs-string">`products`</span> (
<span class="hljs-string">`id`</span> INT AUTO_INCREMENT PRIMARY KEY,
<span class="hljs-string">`name`</span> VARCHAR(<span class="hljs-number">255</span>),
<span class="hljs-string">`price`</span> DECIMAL(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>)
);
</code></pre><p><em>MySQL create table syntax</em></p>
<pre><code><span class="hljs-comment">/* Oracle */</span>
CREATE TABLE products (
  id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  name VARCHAR2(<span class="hljs-number">255</span>),
  price NUMBER(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>)
);
</code></pre><p><em>Oracle create table syntax</em></p>
<pre><code>-- MS SQL Server
CREATE TABLE products (
  id INT IDENTITY(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) PRIMARY KEY,
  name VARCHAR(<span class="hljs-number">255</span>),
  price NUMERIC(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>)
);
</code></pre><p><em>SQL Server create table syntax</em></p>
<blockquote>
<p><strong>Schema Conversion with <a target="_blank" href="https://dbconvert.com/dbconvert-studio?ref=dbconvert.com">DBConvert Studio</a>:</strong> If you prefer an automated approach and want to simplify the schema conversion process, consider using DBConvert Studio. This tool can automatically convert your database schema from the source to the destination database syntax, eliminating the need for manual scripting.</p>
</blockquote>
<p><strong>4. Data Migration:</strong> Use specialized tools or scripts to migrate. Ensure that data transformations and mappings are correctly applied.</p>
<p><strong>5. Indexes and Constraints:</strong> Recreate indexes and constraints in the target database that existed in source.</p>
<blockquote>
<p>DBConvert Studio provides an intuitive user interface that allows you to map data types, set constraints, and perform schema transformations with ease. This is especially beneficial for users who may not have extensive scripting experience, streamlining the migration process and reducing the risk of errors.</p>
</blockquote>
<p><strong>6. Stored Procedures and Functions:</strong> If your application relies on stored procedures or functions, rewrite them in the target's syntax. The logic may need to be adjusted to match the target db procedural language.</p>
<p><strong>7. Views and Triggers:</strong> Recreate views and triggers in target db, ensuring they function as intended.</p>
<p><strong>8. Application Code Updates:</strong> Modify your application code to adapt to target-specific SQL syntax and features.</p>
<h3 id="heading-data-mapping-data-type-handling-and-schema-differences">Data Mapping, Data Type Handling, and Schema Differences:</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056710754/20692990-d396-444e-b33d-6cec3a2882fd.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<ol>
<li><strong>Data Mapping:</strong> When performing a database migration, it's crucial to map your data accurately from the source to the target, considering the differences in data types between the database systems. </li>
<li><strong>Schema Differences:</strong> Be aware of schema differences. <em>PostgreSQL</em> is stricter with data type casting and enforces more rigorous SQL standards compliance than <em>MySQL</em>. </li>
<li><strong>Case Sensitivity:</strong> <em>PostgreSQL</em> and <em>Oracle</em> are case-sensitive by default, while <em>MySQL</em> and <em>SQL Server</em> are usually case-sensitive. Ensure that your queries and table/column references match the case sensitivity rules of PostgreSQL.</li>
<li><strong>Serial Columns:</strong> In PostgreSQL, you often use <code>SERIAL</code> data types for auto-incrementing columns instead of MySQL's <code>AUTO_INCREMENT</code>. In MS SQL Server, you commonly use the <code>IDENTITY</code> property to create auto-increment columns. In Oracle, you typically use a <code>SEQUENCE</code> and a trigger to achieve auto-increment behavior for a column.</li>
<li><strong>Character Encoding:</strong> Pay attention to character encoding differences between databases and ensure your data is converted correctly.</li>
<li><strong>Primary Keys and Unique Constraints:</strong> Review primary keys and unique constraints, as they might need to be modified to adhere to target's requirements.</li>
</ol>
<p>Migrating databases involves careful attention to detail, as differences between databases can impact data integrity and application functionality. Using migration tools and scripts specific to the task can simplify the process. Additionally, thorough testing and validation are essential to ensure a successful migration. The next section will explore the critical aspects of testing and validating the migrated database.</p>
<h2 id="heading-section-4-handling-data-and-application-code">Section 4: Handling Data and Application Code</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056711982/3591328b-2e94-4abe-9383-0632a803e543.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>Migrating a database involves more than just transferring data; it also entails adapting the data and application code to ensure compatibility with the target database system. In this section, we'll discuss the crucial tasks of transforming data and adjusting application code during migration.</p>
<h3 id="heading-transforming-and-adapting-data-during-migration">Transforming and Adapting Data During Migration:</h3>
<ul>
<li><strong>Data Mapping and Transformation:</strong> As discussed earlier, define a clear data mapping and transformation plan to handle differences in data types, constraints, and schema structures between databases. Use migration tools or scripts to automate data transformation whenever possible. </li>
<li><strong>Data Cleansing and Validation:</strong> Before migrating data, perform data cleansing and validation to address data quality issues, anomalies, or inconsistencies. Ensure that data integrity is maintained throughout the migration process.</li>
<li><strong>Null Handling:</strong> Be mindful of how NULL values are handled in your data. PostgreSQL, MSSQL and Oracle may have different default behaviors for NULL values compared to MySQL. In MySQL, NULL is a special marker used to indicate that a data value does not exist in the database. It represents the absence of a value or an unknown value. Adjust your data accordingly.</li>
<li><strong>Date and Time Conversions:</strong> When migrating date and time values between DBMSs like Oracle, MSSQL, MySQL, and PostgreSQL, it's essential to understand the date types, formats, and time zone handling specific to each system. You may need to use conversion functions and update time zone data to ensure accurate date and time representations in the target database.</li>
</ul>
<h3 id="heading-adjusting-application-code-and-queries-for-compatibility">Adjusting Application Code and Queries for Compatibility:</h3>
<ul>
<li><strong>SQL Syntax Differences:</strong> Review your application's SQL queries and adapt them to target db syntax. Pay attention to differences in date functions, string concatenation, and mathematical operations.</li>
<li><strong>Quoting Identifiers:</strong> PostgreSQL and Oracle uses double quotes  (<code>"</code>) for quoting identifiers (table and column names with spaces or special characters), while MySQL uses backticks. Adjust your queries accordingly. In MSSQL, identifiers are typically enclosed in square brackets (<code>[]</code>) or (<code>"</code>) for quoting.</li>
<li><strong>Stored Procedures and Functions:</strong> To ensure a smooth database migration, rewrite stored procedures, functions, and triggers to match the procedural language of the target DBMS. Common languages include:</li>
<li>MySQL: SQL/PSM</li>
<li>MSSQL: T-SQL</li>
<li>PostgreSQL: PL/pgSQL (with support for other languages)</li>
<li><p>Oracle: PL/SQL</p>
</li>
<li><p><strong>Database Connection Parameters:</strong> Update your application's database connection parameters to connect to the target database. Adjust the host, port, username, and password as needed.</p>
</li>
<li><strong>Data Retrieval Methods:</strong> Modify data retrieval methods in your application code to handle differences in how data is returned by DBMS.</li>
<li><strong>Testing and Validation:</strong> Rigorously test your application after making code adjustments to ensure it functions correctly with the migrated database.</li>
<li><strong>User Training:</strong> Train users and developers on any changes introduced by the migration, including differences in SQL syntax and database behavior.</li>
<li><strong>Documentation Updates:</strong> Update your application's documentation to reflect any changes in database interactions and queries due to the migration.</li>
<li><strong>Backward Compatibility:</strong> Consider maintaining backward compatibility with the original database system during the transition period, especially if the migration is part of a phased approach.</li>
</ul>
<p>Adapting your application code and queries is critical to a successful database migration. It ensures that your application continues to function as expected and takes full advantage of the capabilities of the target database system. Thorough testing and validation of the application are essential to catch any compatibility issues early in the migration process. The next section will explore the importance of post-migration testing and verification.</p>
<h2 id="heading-section-5-post-migration-testing-and-verification">Section 5: Post-Migration Testing and Verification</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056712779/3999f98e-47bf-4da0-865d-c58a7b1bbe26.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>The work doesn't end once the data and application code have been migrated. Dedicating time and resources to thorough post-migration testing and verification is crucial. In this section, we'll emphasize the importance of these steps and discuss how to ensure data integrity and functionality while handling unforeseen issues.</p>
<h3 id="heading-the-importance-of-thorough-testing-post-migration">The Importance of Thorough Testing Post-Migration:</h3>
<ul>
<li><strong>Data Integrity Assurance:</strong> Post-migration testing is essential to verify that data has been accurately and completely migrated from the source database to the target database. Confirm that primary keys, foreign keys, and constraints are functioning as expected.</li>
<li><strong>Application Functionality Validation:</strong> Ensure that all aspects of your application, including user interfaces, reports, and backend processes, work as expected with the migrated database. Test all application functions and features to guarantee they continue performing as intended.</li>
<li><strong>Performance Evaluation:</strong> Benchmark the performance of the migrated database against predefined criteria and expectations: measure query response times and system resource utilization. Identify and address any performance bottlenecks or issues.</li>
<li><strong>Data Validation:</strong> Implement comprehensive data validation scripts to confirm the accuracy and integrity of data in the migrated database. Verify that data transformations and mappings have been executed correctly.</li>
<li><strong>User Acceptance Testing (UAT):</strong> Involve end-users and stakeholders in user acceptance testing. Gather feedback on the functionality and usability of the application with the new database.</li>
</ul>
<h3 id="heading-verifying-data-integrity-and-functionality">Verifying Data Integrity and Functionality:</h3>
<ul>
<li><strong>Data Validation Queries:</strong> Develop SQL queries and scripts to validate data integrity. Check for data anomalies, missing records, and inconsistencies.</li>
<li><strong>Regression Testing:</strong> Perform regression testing on your application to ensure the migration hasn't compromised existing functionality. Re-run previously successful test cases to verify that they still pass.</li>
<li><strong>Boundary Testing:</strong> Test boundary conditions and edge cases to ensure that the migrated system can handle extreme scenarios without issues.</li>
<li><strong>Security and Access Control:</strong> Validate that the target database has correctly implemented security measures and access controls. Ensure that only authorized users can access sensitive data.</li>
<li><strong>Load and Stress Testing:</strong> Conduct load and stress testing to assess how the system behaves under heavy loads. Identify performance bottlenecks and scalability issues.</li>
<li><strong>Backup and Recovery Testing:</strong> Test backup and recovery procedures to ensure data can be restored in case of unexpected issues. Verify that the rollback plan is functional.</li>
</ul>
<h3 id="heading-handling-unforeseen-issues">Handling Unforeseen Issues:</h3>
<ul>
<li><strong>Issue Identification:</strong> Be prepared to identify and document any unforeseen issues during post-migration testing—track issues related to data, functionality, and performance.</li>
<li><strong>Issue Prioritization:</strong> Prioritize issues based on their impact on data integrity, functionality, and business operations. Address critical issues promptly.</li>
<li><strong>Root Cause Analysis:</strong> Conduct a thorough root cause analysis for critical issues to understand the underlying reasons. This analysis can inform corrective actions.</li>
<li><strong>Issue Resolution:</strong> Collaborate with the database migration team, developers, and stakeholders to resolve identified issues. Implement fixes, code changes, or adjustments as needed.</li>
<li><strong>Communication and Documentation:</strong> Maintain clear communication with stakeholders throughout the issue resolution process. Document the steps taken to address issues and their outcomes.</li>
</ul>
<p>Post-migration testing is a critical phase that ensures a successful transition to the new database system. It helps maintain data integrity, assures application functionality, and prepares your organization for unexpected challenges. Be vigilant, organized, and responsive to issues that may arise, and remember that post-migration testing is an ongoing process that continues even after the migration is complete. The following section will explore best practices and tips for a successful database conversion.</p>
<p>## </p>
<h2 id="heading-section-6-monitoring-and-maintenance">Section 6: Monitoring and Maintenance</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056713762/bd9c0b7a-e05d-412c-977e-edd639138270.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>The section of our guide focuses on the critical aspects of ongoing monitoring and maintenance for your database system post-migration. We'll discuss the importance of these activities, highlight tools and techniques for performance monitoring, and provide guidance on troubleshooting common issues.</p>
<h3 id="heading-ongoing-monitoring-and-maintenance-post-migration">Ongoing Monitoring and Maintenance Post-Migration:</h3>
<ol>
<li><strong>Continuous Monitoring:</strong> Establish a robust monitoring system to keep a close eye on the health and performance of your migrated database. Regularly review system metrics, logs, and alerts.</li>
<li><strong>Database Backups:</strong> Maintain a reliable backup strategy, including regular full and incremental backups. Test the restoration process periodically to ensure data recoverability.</li>
<li><strong>Routine Maintenance Tasks:</strong> Schedule everyday maintenance tasks, such as vacuuming, reindexing, and compaction, to optimize database performance and prevent fragmentation.</li>
<li><strong>Security Audits:</strong> Conduct regular security audits and vulnerability assessments to identify and address potential security risks and vulnerabilities.</li>
<li><strong>Performance Tuning:</strong> Continuously fine-tune your database for optimal performance. Analyze query execution plans, optimize indexes, and adjust configuration settings.</li>
</ol>
<h3 id="heading-tools-and-techniques-for-performance-monitoring">Tools and Techniques for Performance Monitoring:</h3>
<ol>
<li><strong>Database Management Systems (DBMS) Tools:</strong> Most DBMSs offer built-in performance monitoring and optimization tools. Familiarize yourself with the tools provided by your specific DBMS.</li>
<li><strong>Third-Party Monitoring Tools:</strong> Consider using third-party monitoring tools such as Prometheus or Grafana for advanced performance monitoring, alerting, and visualization.</li>
<li><strong>Query Profiling:</strong> Use query profiling tools to analyze and optimize slow or resource-intensive queries. Identify bottlenecks and make necessary adjustments.</li>
<li><strong>Log Analysis:</strong> Regularly review database logs for error messages, warnings, and performance-related information. Log aggregation tools like ELK Stack can be invaluable.</li>
</ol>
<h3 id="heading-troubleshooting-common-issues">Troubleshooting Common Issues:</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056714654/89361c07-fbe5-4385-b0f7-26b36351b203.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<ol>
<li><strong>Performance Degradation:</strong> If you notice performance degradation, investigate the root cause by analyzing query performance and system metrics. Adjust configurations, optimize queries, and consider hardware upgrades if necessary.</li>
<li><strong>Concurrency Issues:</strong> Monitor database locks and concurrent connections. Address contention issues by optimizing transactions and locking strategies.</li>
<li><strong>Data Corruption:</strong> Implement integrity checks and regularly validate data to promptly detect and rectify data corruption issues.</li>
<li><strong>Security Breaches:</strong> In case of a security breach or data breach, follow your incident response plan. Investigate the breach, implement security patches, and enhance security measures.</li>
<li><strong>Resource Exhaustion:</strong> Monitor resource utilization, including CPU, memory, and disk space. Implement resource scaling or optimization strategies to prevent resource exhaustion.</li>
<li><strong>Backup Failures:</strong> When backup failures occur, identify the cause and resolve it promptly. Regularly test backup and recovery procedures to ensure data recoverability.</li>
<li><strong>Software Updates:</strong> Stay updated with software updates and security patches for your DBMS, operating system, and third-party tools. Apply updates in a controlled manner to minimize disruption.</li>
<li><strong>Documentation and Knowledge Sharing:</strong> Maintain detailed documentation of your monitoring and maintenance activities. Share knowledge and best practices with your team to build a collective understanding of the database system.</li>
</ol>
<p>By prioritizing ongoing monitoring and maintenance, you can ensure your migrated database system's long-term stability, performance, and security. Troubleshooting common issues as they arise and proactively addressing potential problems will help you maintain a robust and reliable database environment.</p>
<h2 id="heading-ia"> </h2>
<p>Section 7: Best Practices and Tips</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056715688/bfda20a8-f328-4672-bb29-cb77aba4418f.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>In the final section of our guide, we'll delve into proven best practices, offer tips to avoid common migration pitfalls, and discuss strategies for optimizing the performance of your newly migrated database.</p>
<h3 id="heading-proven-best-practices-for-a-successful-database-conversion">Proven Best Practices for a Successful Database Conversion:</h3>
<ol>
<li><strong>Thorough Planning:</strong> Invest time in comprehensive planning and assessment of your current database and migration goals.</li>
<li><strong>Data Mapping and Transformation:</strong> Develop a well-defined data mapping and transformation plan to handle schema and data differences between source and target databases.</li>
<li><strong>Testing:</strong> Rigorously test and validate your migration in a controlled environment before migrating the production database.</li>
<li><strong>Data Validation:</strong> Implement robust data validation to ensure data integrity during and after migration.</li>
<li><strong>Backup and Rollback Plans:</strong> Maintain reliable backup and rollback plans to safeguard against unexpected issues.</li>
<li><strong>Application Code Adaptation:</strong> Modify application code and queries to align with the syntax and features of the target database.</li>
<li><strong>Post-Migration Testing:</strong> Dedicate time and resources to comprehensive post-migration testing to validate data, functionality, and performance.</li>
</ol>
<h3 id="heading-tips-for-avoiding-common-migration-pitfalls">Tips for Avoiding Common Migration Pitfalls:</h3>
<ol>
<li><strong>Engage Experts:</strong> Consider involving database experts or consultants with database migrations experience.</li>
<li><strong>Incremental Migration:</strong> Perform incremental or phased migrations to minimize downtime and reduce risks.</li>
<li><strong>Documentation:</strong> Maintain detailed documentation throughout the migration process, including decisions, configurations, and issue resolutions.</li>
<li><strong>Monitoring:</strong> Implement database performance monitoring and alerting to identify and address post-migration issues promptly.</li>
<li><strong>User Training:</strong> Train end-users and developers on the new database system and any changes in SQL syntax.</li>
<li><strong>Performance Benchmarking:</strong> Continuously monitor and benchmark the performance of the migrated database to identify areas for optimization.</li>
<li><strong>Regular Updates:</strong> Keep your database system and migration tools updated with the latest releases and patches.</li>
</ol>
<h3 id="heading-database-optimization-for-performance">Database Optimization for Performance:</h3>
<ol>
<li><strong>Indexing:</strong> Ensure appropriate indexes are in place for frequently queried columns to optimize query performance.</li>
<li><strong>Query Optimization:</strong> Continuously analyze and optimize SQL queries to improve efficiency and reduce query execution times.</li>
<li><strong>Caching:</strong> Implement caching mechanisms to reduce the load on the database system, especially for frequently accessed data.</li>
<li><strong>Partitioning:</strong> Consider database table partitioning to improve query performance on large datasets.</li>
<li><strong>Regular Maintenance:</strong> Schedule routine database maintenance tasks such as vacuuming and reindexing to keep the database running efficiently.</li>
<li><strong>Database Scaling:</strong> Be prepared to scale your database horizontally or vertically to handle increased workloads as your application grows.</li>
<li><strong>Query Monitoring:</strong> Use query monitoring tools to identify slow or inefficient queries and address them promptly.</li>
<li><strong>Security:</strong> Continuously assess and enhance the security of your database system to protect against potential threats.</li>
</ol>
<p>By adhering to best practices, staying vigilant for common pitfalls, and implementing performance optimization strategies, you can ensure a successful database conversion that meets your objectives and provides a robust foundation for your application. Remember that a well-executed migration can improve performance, reduce costs, and enhance functionality, ultimately benefiting your organization and its users.</p>
<h2 id="heading-section-9-conclusion">Section 9: Conclusion</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056716494/2fbbe516-dc81-40bf-bff0-0f0b6ffd5df2.jpeg" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p>In this comprehensive guide to database conversion between different database types in heterogeneous environments, we've explored the intricate process of migrating your database from one system to another. Here, we summarize key takeaways, highlight the benefits of a well-executed migration, and encourage readers to seek professional assistance.</p>
<h3 id="heading-key-takeaways">Key Takeaways:</h3>
<ul>
<li><strong>Planning is Paramount:</strong> Thoroughly plan your migration, assess your current database, and set clear objectives. A well-structured plan is the foundation of a successful migration.</li>
<li><strong>Testing is Crucial:</strong> Rigorous testing, both before and after migration, is essential to ensure data integrity, application functionality, and performance.</li>
<li><strong>Data Mapping and Transformation:</strong> Pay close attention to data mapping and transformation to address differences in data types, constraints, and schema structures.</li>
<li><strong>Application Code Adaptation:</strong> Modify application code and queries to align with the syntax and features of the target database system.</li>
<li><strong>Performance Monitoring and Maintenance:</strong> Implement ongoing monitoring and maintenance practices to optimize performance, ensure security, and troubleshoot common issues.</li>
<li><strong>Documentation and Training:</strong> Maintain comprehensive documentation throughout the migration process and provide training to users and developers regarding the new database system.</li>
</ul>
<h3 id="heading-benefits-of-a-well-executed-database-migration">Benefits of a Well-Executed Database Migration:</h3>
<ul>
<li><strong>Improved Performance:</strong> A successful migration can improve database performance, allowing your applications to scale more effectively.</li>
<li><strong>Cost Savings:</strong> You can reduce licensing and maintenance costs by migrating to an open-source database system.</li>
<li><strong>Advanced Features:</strong> Take advantage of advanced features and capabilities offered by the target database system, enhancing the functionality of your applications.</li>
<li><strong>Data Integrity:</strong> Ensure data integrity throughout migration, preventing data loss or corruption.</li>
<li><strong>Reduced Vendor Lock-In:</strong> Migrating to an open-source system reduces dependency on a single vendor, offering more control and flexibility.</li>
<li><strong>Enhanced Security:</strong> Implement security best practices in the target database system to safeguard your data and applications.</li>
</ul>
<h3 id="heading-seek-professional-assistance">Seek Professional Assistance:</h3>
<p>Database migration can be complex, and challenges may arise that require expert guidance. If you encounter obstacles or are unsure about specific aspects of your migration, feel free to seek professional assistance. Database experts and consultants with experience in migrations can provide valuable insights and solutions to ensure a smooth transition.</p>
<p>In closing, database migration is a strategic move that, when executed thoughtfully, can bring about significant benefits for your organization. It's a process that requires meticulous planning, thorough testing, and ongoing maintenance. By following the best practices outlined in this guide and staying vigilant, you can embark on a successful journey to migrate your databases, setting the stage for a more efficient and capable database environment. Please share your experiences, learn from others, and don't hesitate to seek our expert assistance to make the most of your database migration endeavor.</p>
<hr />
<h2 id="heading-discover-dbconvert-studio-your-database-conversion-and-sync-solution">Discover DBConvert Studio – Your Database Conversion and Sync Solution!</h2>
<p>🌐 Wide Compatibility: Support for MySQL, PostgreSQL, SQL Server, Oracle, and more.</p>
<p>🔄 Multi-Directional: Convert and sync data in any direction with ease.</p>
<p>🛠️ User-Friendly: No coding needed, an intuitive interface for all levels.</p>
<p>🔒 Data Integrity: Keep data accurate and consistent during migration.</p>
<p>📈 High-Performance: Swift, efficient data transfers for reduced downtime.</p>
<p>📊 Visual Mapping: Easy source-to-target mapping visualization.</p>
<p>Use DBConvert Studio and simplify database migrations now!</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056717630/7bca521d-2bf4-482e-89c6-78c63150853f.png" alt="Your Roadmap to Database Conversion Excellence." /></p>
<p><a target="_blank" href="https://dbconvert.com/dbconvert-studio">Download DBConvert Studio</a></p>
]]></content:encoded></item><item><title><![CDATA[Microsoft Access: Unveiling the Dual Power of Database and Front-End Development]]></title><description><![CDATA[title: Microsoft Access: Unveiling the Dual Power of Database and Front-End Development
published: true
date: 2023-06-03 15:06:44 UTC
tags: access,database,msaccess
canonical_url: https://dbconvert.com/blog/access-frontend-backend/
 
In the realm of ...]]></description><link>https://dbconvert.hashnode.dev/microsoft-access-unveiling-the-dual-power-of-database-and-front-end-development</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/microsoft-access-unveiling-the-dual-power-of-database-and-front-end-development</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Sat, 03 Jun 2023 15:06:44 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: Microsoft Access: Unveiling the Dual Power of Database and Front-End Development
published: true
date: 2023-06-03 15:06:44 UTC
tags: access,database,msaccess</p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogaccess-frontend-backend">canonical_url: https://dbconvert.com/blog/access-frontend-backend/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056722200/ed8c9670-9c2b-48f0-90c8-b77960f30f0f.png" alt="Microsoft Access: Unveiling the Dual Power of Database and Front-End Development" /></p>
<p>In the realm of software development, various tools and technologies aid in creating robust and efficient solutions. One such tool that has been empowering developers for decades is Microsoft Access. In this article, we will delve into the capabilities of Microsoft Access and explore how it enables developers to harness the dual power of database management and front-end development.</p>
<h2 id="heading-introduction">Introduction:</h2>
<p>Microsoft Access often remains underestimated, considered merely a toy database by many. However, it is time to shed light on its true potential. Access is a unique product that combines a database engine with a powerful front-end development tool called Visual Basic for Applications (VBA). In this article, we will explore the capabilities of both aspects and debunk the myths surrounding Access.</p>
<h2 id="heading-database-management-the-backbone-of-access">Database Management: The Backbone of Access.</h2>
<p>At its core, Microsoft Access is a relational database management system (RDBMS) that allows users to store, organize, and manipulate large amounts of data. With Access, developers can create tables, define relationships between them, and establish data integrity constraints.</p>
<p>This powerful database engine enables efficient querying and retrieval of data, making it a valuable asset for managing vast amounts of information.</p>
<p>Access provides a user-friendly interface for designing and creating database schemas, making it accessible to developers of varying expertise levels. With its intuitive table design view, developers can easily define fields, data types, and primary key constraints.</p>
<p>Access also includes a query builder that allows for creating complex queries without extensive SQL knowledge. These features streamline the database development process and empower developers to build robust data structures quickly.</p>
<h3 id="heading-access-database-limitations">Access database limitations:</h3>
<p>Access database is ideal for small to mid-sized applications. While it supports multiple users, it is not recommended for heavy concurrent usage. Here are some theoretical limitations to consider:</p>
<ul>
<li><p><strong>Maximum database size</strong> : 2 gigabytes, but can be bypassed by linking to tables in other Access databases.</p>
</li>
<li><p><strong>Total number of objects</strong> : 32,768 objects.</p>
</li>
<li><p><strong>Number of modules</strong> : 1,000 modules, including forms and reports.</p>
</li>
<li><p><strong>Character limits</strong> : Object names (64 characters), passwords (14 characters), and user/group names (20 characters).</p>
</li>
<li><p><strong>Maximum concurrent users</strong> : 255 users (theoretical).</p>
</li>
</ul>
<p>However, the practicality of some of these limitations may vary.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056723319/ac052314-d0d0-4fd6-b968-270868e3b7ec.jpeg" alt="Microsoft Access: Frontend" /></p>
<h2 id="heading-front-end-development-bringing-data-to-life">Front-End Development: Bringing Data to Life.</h2>
<p>While Microsoft Access excels in database management, it also offers robust front-end development capabilities.</p>
<p>Access includes an effective forms designer that enables developers to create user interfaces to interact with the underlying data. The forms designer provides various controls, such as text boxes, buttons, and dropdown menus, allowing developers to create intuitive and user-friendly interfaces.</p>
<p>The forms designer in Access supports various data binding options, allowing developers to link form controls directly to the database. This way, changes made on the form are automatically reflected in the database and vice versa, eliminating the need for manual synchronization.</p>
<h2 id="heading-integration-and-extensibility-going-beyond-the-basics">Integration and Extensibility: Going Beyond the Basics</h2>
<p>Microsoft Access seamlessly integrates with other Microsoft Office applications, such as Excel, Word, and Outlook. This integration allows developers to leverage the power of Access in conjunction with other tools to create comprehensive solutions. For example, data from Access can be exported to Excel for further analysis or presented in Word documents for reporting purposes. By combining the strengths of different Microsoft Office applications, developers can create cohesive and interconnected solutions that cater to various business needs.</p>
<p>Furthermore, Microsoft Access supports external data sources, enabling developers to connect to and interact with data from other systems and databases. This capability opens up possibilities for hybrid solutions leveraging data from multiple sources. Whether connecting to an SQL Server database or consuming data from a web service, Access provides the tools and connectors to integrate disparate data sources effortlessly.</p>
<h2 id="heading-dbconvert-conversion-and-synchronization-capabilities">DBConvert Conversion and Synchronization Capabilities:</h2>
<p>DBConvert's conversion and synchronization capabilities are instrumental in enhancing the functionality of Microsoft Access and expanding its capabilities by migrating/ synching data with MS SQL Server, MySQL, PostgreSQL, Oracle, and more.</p>
<p>With DBConvert, users can overcome the limitations of Access and seamlessly migrate their data to another database platforms.</p>
<p>Additionally, DBConvert enables <a target="_blank" href="https://dev.to/slotix/bidirectional-database-synchronization-4968-temp-slug-1861195">bidirectional synchronization</a> between Access and other RDBMS, ensuring that changes made in one database are reflected in the other, maintaining data consistency across the hybrid system.</p>
<p>DBConvert simplifies transferring Access data to popular cloud databases like <a target="_blank" href="https://dbconvert.com/amazon">Amazon RDS</a>, <a target="_blank" href="https://dbconvert.com/azure">Microsoft Azure SQL Database</a>, and <a target="_blank" href="https://dbconvert.com/google-cloud">Google Cloud SQL</a>. Moving data from MS Access opens up new possibilities for storing and managing data in the cloud, providing increased accessibility, scalability, and flexibility.</p>
<hr />
<h2 id="heading-summary">Summary:</h2>
<p>Access is often misunderstood as a toy database, yet it has immense potential. While it caters to smaller databases, elite Access developers utilize it as a front-end targeting "serious" databases like PostgreSQL, SQL Server, and Oracle. Microsoft Access is a testament to the power of combining database management and front-end development in a single tool. Access can seamlessly connect to various back-end databases with minimal code changes, offering developers a significant advantage.</p>
<p>It's time to recognize the true power of Microsoft Access beyond its perceived limitations. So, embrace Access as a valuable database and front-end development tool, and unlock a world of possibilities.</p>
<p>If you find yourself constrained by the limitations of Access, DBConvert offers a pathway to unleash the full potential of your data. With its robust conversion and synchronization capabilities, DBConvert empowers users to optimize their data management systems and achieve enhanced efficiency and flexibility and take your database operations to the next level.</p>
<p><a target="_blank" href="https://dbconvert.com/access/">Migrate to Access? Check out DBConvert Converters and Synchronization software.</a></p>
]]></content:encoded></item><item><title><![CDATA[Simplifying Data Migration: Converting DBF Files to SQL Server.]]></title><description><![CDATA[title: Simplifying Data Migration: Converting DBF Files to SQL Server.
published: true
date: 2023-05-19 12:06:43 UTC
tags: sqlserver,foxpro,database,mssql
canonical_url: https://dbconvert.com/blog/converting-dbf-to-sql-server/
 
Introduction.
DBF (dB...]]></description><link>https://dbconvert.hashnode.dev/simplifying-data-migration-converting-dbf-files-to-sql-server</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/simplifying-data-migration-converting-dbf-files-to-sql-server</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Fri, 19 May 2023 12:06:43 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: Simplifying Data Migration: Converting DBF Files to SQL Server.
published: true
date: 2023-05-19 12:06:43 UTC
tags: sqlserver,foxpro,database,mssql</p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogconverting-dbf-to-sql-server">canonical_url: https://dbconvert.com/blog/converting-dbf-to-sql-server/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056727172/0633b515-c89b-4cef-93c1-1ed330dd94e2.png" alt="Simplifying Data Migration: Converting DBF Files to SQL Server." /></p>
<h2 id="heading-introduction">Introduction.</h2>
<p>DBF (dBase File) is a widely recognized format for storing structured data. It has gained significant popularity among applications, particularly those operating on Microsoft DOS and Windows platforms. Initially, DBF files were closely associated with the dBase database management system, which enjoyed widespread use in the 1980s and 1990s. Over time, other database management systems like FoxPro, Clipper, and Visual FoxPro adopted the DBF format.</p>
<p>In the ever-evolving world of data management, businesses often face the challenge of migrating their data from legacy systems to more modern and scalable platforms. One such migration scenario involves converting DBF to SQL Server, commonly associated with dBase, XBase, Clipper, FoxBase and FoxPro databases.</p>
<p>This article explores the process of converting DBF to SQL Server, highlighting the benefits and providing insights into best practices for a robust transition.</p>
<h2 id="heading-understanding-the-need-for-migration">Understanding the Need for Migration.</h2>
<p>As technology progresses, legacy systems like FoxPro may no longer meet the demands of modern businesses. On the other hand, SQL Server offers a robust and feature-rich environment that can handle large volumes of data, provides enhanced security measures, and supports high-performance transactional applications. Migrating from DBF files to SQL Server ensures longevity, scalability, and compatibility with current and future data management needs.</p>
<h2 id="heading-benefits-of-migrating-to-sql-server">Benefits of Migrating to SQL Server.</h2>
<ol>
<li><p>Scalability: SQL Server offers scalability options to accommodate growing data volumes and user demands, ensuring your system can handle future growth.</p>
</li>
<li><p>Performance: SQL Server's optimized query processing and indexing capabilities enable faster and more efficient data retrieval, enhancing application performance.</p>
</li>
<li><p>Security: SQL Server provides robust security features, including encryption, user access controls, and data masking, protecting your valuable data from unauthorized access.</p>
</li>
<li><p>Integration: SQL Server smoothly integrates with other Microsoft products, facilitating integration with business intelligence tools, reporting services, and analytical platforms.</p>
</li>
</ol>
<h2 id="heading-choosing-the-right-conversion-tool">Choosing the Right Conversion Tool.</h2>
<p>Selecting a reliable and efficient conversion tool is crucial to simplify the DBF to SQL Server conversion process. <a target="_blank" href="https://dbconvert.com/foxpro/mssql/">DBConvert/ DBSync for FoxPro and MSSQL</a> software streamlines the migration process, providing a powerful and user-friendly solution. It offers comprehensive features, including intuitive user interfaces and efficient data mapping capabilities.</p>
<h3 id="heading-step-by-step-conversion-process">Step-by-Step Conversion Process.</h3>
<ol>
<li><p>Assess Your DBF Files: Begin by analyzing the structure and content of your DBF files. Understand the relationships, data types, and any specific requirements for the migration process.</p>
</li>
<li><p>Prepare the SQL Server Database: Create a new database or identify an existing one to serve as the target for your migrated data. Ensure that the SQL Server instance is configured correctly and accessible.</p>
</li>
<li><p>Install and Configure the Data Migration Tool Install the appropriate software, either DBConvert or DBSync, based on your specific task, whether conversion or synchronization. Proceed to configure the basic settings, including establishing connections for the source and target databases.</p>
</li>
<li><p>Map the Data In this crucial step, you must define the mapping between the fields in your DBF files and the corresponding columns in the SQL Server table. It is essential to consider data types, indices, and constraints to ensure a precise and efficient data transfer.</p>
</li>
<li><p>Execute the Conversion: Start the conversion process and monitor its progress. The tool provides real-time feedback, allowing you to track potential errors or issues requiring attention.</p>
</li>
<li><p>Verify and Validate: After the conversion, thoroughly verify the migrated data in the SQL Server database. Perform data integrity checks, validate relationships, and ensure data is accurately represented.</p>
</li>
</ol>
<blockquote>
<p>If you're using the DBConvert software, you'll be pleased to know that it automates the mapping process, making it a seamless experience. The software intelligently analyzes the structures of the DBF files and SQL Server tables and automatically establishes the mappings. However, if you desire further customization, the software also allows you to adjust the mappings according to your specific requirements manually. This flexibility will enable you to tailor the data mapping to meet your unique needs, ensuring a highly personalized data migration process.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056728057/a0794e44-d8fd-4d23-a3ce-6b0c9621ef8c.png" alt="DBConvert screenshot" /></p>
<h2 id="heading-synchronization">Synchronization.</h2>
<p><a target="_blank" href="https://dbconvert.com/blog/what-is-database-synchronization/">Synchronizing data</a> between legacy DBF files and SQL Server databases can be challenging due to the differences in their underlying technologies and structures. However, DBSync tool from DBConvert provides a reliable solution to streamline the synchronization process and ensure data consistency across these disparate systems.</p>
<p>Legacy FoxPro databases often serve as the backbone of critical applications in many organizations. However, as businesses evolve, there is a growing need to integrate these legacy systems with modern SQL Server databases to leverage advanced features, scalability, and improved data management capabilities.</p>
<p>DBSync handles the complexities of data mapping and transformation between FoxPro and SQL Server. It intelligently detects and resolves conflicts that may arise during the synchronization process, ensuring data integrity and minimizing the risk of data inconsistencies. This intelligent synchronizer mechanism considers each database platform's specific characteristics and provides accurate data replication.</p>
<p>With DBSync, organizations can schedule automated synchronization tasks to run at predefined intervals. This feature eliminates manual intervention and ensures data remains synchronized without constant monitoring. Additionally, the software provides detailed logs and reports to track the synchronization process, allowing for easy troubleshooting and auditing.</p>
<p>The user-friendly interface of DBSync simplifies the configuration and management of synchronization tasks. It guides users through the process with a wizard-like interface, making it easy to set up connections to both the legacy DBF Table and the SQL Server database. Users can define the mapping between tables, specify synchronization options, and customize the synchronization process to meet their requirements.</p>
<h2 id="heading-conclusion">Conclusion:</h2>
<p>Migrating DBF files to SQL Server allows businesses to modernize their data management systems, unlock advanced features, and ensure long-term scalability. By following a well-defined conversion process and utilizing reliable tools like DBConvert &amp; DBSync, businesses can seamlessly migrate their data from DBF files to the robust SQL Server platform. Embracing this migration not only future-proofs data management practices but also enables organizations to leverage the full potential of their data in an ever-evolving digital landscape.</p>
]]></content:encoded></item><item><title><![CDATA[MySQL vs PostgreSQL in 2023.]]></title><description><![CDATA[title: MySQL vs PostgreSQL in 2023.
published: true
date: 2023-02-01 11:00:06 UTC
tags: database,postgresql,mysql,postgres
canonical_url: https://dbconvert.com/blog/mysql-vs-postgresql/
 
Regarding choosing a relational database management system (RD...]]></description><link>https://dbconvert.hashnode.dev/mysql-vs-postgresql-in-2023</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/mysql-vs-postgresql-in-2023</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Wed, 01 Feb 2023 11:00:06 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: MySQL vs PostgreSQL in 2023.
published: true
date: 2023-02-01 11:00:06 UTC
tags: database,postgresql,mysql,postgres</p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogmysql-vs-postgresql">canonical_url: https://dbconvert.com/blog/mysql-vs-postgresql/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056731540/ecab378b-2151-4fc2-ad9b-1bfedec9356f.png" alt="MySQL vs PostgreSQL in 2023." /></p>
<p>Regarding choosing a relational database management system (RDBMS), two popular options are PostgreSQL and MySQL. Both have been around for decades and have proven highly reliable, secure, and scalable. However, they have different strengths and weaknesses that make one more suitable for specific use cases. This article will compare PostgreSQL and MySQL to help you make an informed decision in 2023.</p>
<h3 id="heading-history-and-development">History and Development</h3>
<p>PostgreSQL was first released in 1996 and has become a widely used open-source RDBMS. It is known for its strong adherence to SQL standards, robust feature set, and focus on data integrity and security.</p>
<p>MySQL, on the other hand, was first released in 1995 and has been widely used for web-based applications due to its high performance and ease of use. Over time, Oracle acquired the open-source database management system MySQL and turned it into a commercial product.</p>
<h3 id="heading-features">Features</h3>
<p>PostgreSQL and MySQL both offer a wide range of features as relational database management systems, but there are some key differences between the two:</p>
<ol>
<li>Data Types: PostgreSQL supports a broader range of advanced data types, including arrays, hstore (a key-value store), and JSONB (binary JSON), which provide more flexible and efficient data storage options. On the other hand, MySQL has a more limited set of data types and is geared toward more straightforward web applications.</li>
<li>Geospatial Support: PostgreSQL strongly supports geospatial data, including a rich set of data types, functions, and operators for handling geographic data. MySQL, while it has some geospatial support, could be more robust in this area.</li>
<li>Indexing: In MySQL, the default index type is B-tree, which is well-suited for most use cases. PostgreSQL has a more refined indexing system than MySQL, including support for B-tree, GiST (Generalized Search Tree), and GIN (Generalized Inverted Index) indexes. These provide more options for optimizing query performance and data retrieval.</li>
<li>Replication: PostgreSQL and MySQL support database replication, but the methods and options for replication differ. PostgreSQL supports multi-master replication, while MySQL primarily supports master-slave replication. MySQL has recently introduced a new replication model called Group Replication, but it is still a relatively new feature with some limitations.</li>
<li>Transactions: PostgreSQL and <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/innodb-multi-versioning.html">MySQL InnoDB utilize MVCC</a> (Multi-Version Concurrency Control) to handle concurrent data access. However, PostgreSQL offers evolved transaction management features such as transaction isolation levels, atomic transactions, and savepoints. In contrast, MySQL's transaction management options are more limited. PostgreSQL may be better for applications requiring high concurrency or complex transaction logic.</li>
<li>Stored Procedures: PostgreSQL and MySQL support stored procedures, but the language and functionality of stored procedures differ. PostgreSQL supports stored procedures written in various languages, including PL/pgSQL, PL/Tcl, PL/Perl, and more. MySQL, alternatively, primarily supports stored procedures written in SQL.</li>
<li>Extensions: PostgreSQL has a robust extension framework that allows developers to add custom functionality and extend the core features of the database. While it has some support for extensions, MySQL has a different level of extensibility than PostgreSQL.</li>
</ol>
<h3 id="heading-change-data-capture">Change data capture</h3>
<p>In terms of <a target="_blank" href="https://dbconvert.com/blog/change-data-capture-cdc-what-it-is-and-how-it-works/">change data capture</a> (CDC), both MySQL binary logs and PostgreSQL write-ahead logs (WALs) can capture changes made to the database. However, the specific features and usage of the CDC may vary.</p>
<p><a target="_blank" href="https://stream.dbconvert.com/guide/introduction">DBConvert Streams</a> is a software that can read MySQL and PostgreSQL transaction logs and transform the records to another dialect, making it suitable for heterogeneous database replication in real time.</p>
<h3 id="heading-performance">Performance</h3>
<p><strong>MySQL</strong> is known for its high performance and ability to process large
amounts of data. It has been optimized for read-heavy workloads and has a fast indexing system that helps improve query performance. However, concurrency issues such as lock contention can occur when combined with write operations, leading to performance degradation. This is due to the implementation of locks at the table level, preventing all actions while the write operation is in progress.</p>
<p>The InnoDB storage engine is used to solve the table-level locking issue. It is one of the most popular and widely used storage engines in the MySQL ecosystem. InnoDB supports row-level locking, improving concurrency for mixed workloads.</p>
<p>Additionally, the recent development of the high-performance storage engine, MyRocks, has further improved MySQL's ability to handle write-intensive workloads.</p>
<p><strong>PostgreSQL</strong> is designed to be more versatile, handling both read-heavy and write-heavy workloads, but with slightly lower performance than MySQL, which is optimized for read-heavy workloads. However, PostgreSQL has improved its performance in recent versions, especially regarding complex queries and data processing.
Additionally, PostgreSQL has a more advanced indexing system compared to MySQL, which can improve performance for complex queries. PostgreSQL also supports advanced data types, like arrays and JSONB, which can result in more efficient data storage and retrieval.
Ultimately, the performance of both PostgreSQL and MySQL will depend on various factors, such as hardware, data size, and query complexity.</p>
<p>When choosing between the two, consider your application's specific requirements and conduct performance testing with your data and workloads to determine the best fit.</p>
<h3 id="heading-scalability">Scalability</h3>
<p>Both MySQL and PostgreSQL can scale, but they have different strengths and weaknesses when it comes to scalability.
MySQL is often preferred for its horizontal scalability, which means it can be scaled out by adding more nodes to the database cluster. It is ideal for web applications that need to handle a large number of concurrent connections.</p>
<p>On the other hand, PostgreSQL is known for its vertical scalability, which means it can handle large amounts of data and processing power by adding more resources like memory and CPU to a single node. It also supports horizontal scaling through technologies such as sharding, which allows large datasets to be split across multiple nodes. PostgreSQL is preferred for applications requiring complex queries and transactions and for data warehouse and business intelligence workloads.</p>
<p>In terms of scalability, consider the specific requirements of your application. If you need to handle a large number of concurrent connections and need horizontal scalability, MySQL may be a better choice. However, PostgreSQL may be better if you require complex transactions and queries.</p>
<h3 id="heading-cost">Cost</h3>
<p>In 2023, it is still true that PostgreSQL is fully open-source and community-driven, whereas MySQL has a more complex history concerning licensing. MySQL was initially developed as a commercial product by MySQL AB, with free and paid versions available. The acquisition of MySQL AB by Oracle in 2010 raised some concerns among developers about the future of its open-source status. However, several open-source forks of the original MySQL, including MariaDB and Percona, have helped mitigate these concerns.</p>
<h2 id="heading-when-to-use-mysql">When to Use MySQL?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056732707/1265cdff-9664-4b8b-8451-9da0756dbff0.png" alt="MySQL vs PostgreSQL in 2023." /></p>
<p>While PostgreSQL has many cutting-edge features and is often considered a more advanced and complex database management system than MySQL, it does have its drawbacks.</p>
<p>Some of the common weaknesses of PostgreSQL include the following:</p>
<ol>
<li>Despite its advanced features and capabilities, PostgreSQL has yet to reach the level of popularity and widespread use of MySQL. This has resulted in a smaller number of third-party tools and a lesser number of experienced developers or database administrators in the PostgreSQL ecosystem.</li>
<li>Due to its advanced features, PostgreSQL can be more complex to set up and manage than MySQL, making it more suitable for experienced database administrators and developers.</li>
<li>PostgreSQL can be slower in certain use cases than MySQL due to its more complex architecture and features.</li>
<li>PostgreSQL can require more resources than MySQL, particularly in terms of memory and CPU usage.
While PostgreSQL is open-source, the cost of implementation and maintenance can still be high due to its advanced features and increased resource requirements.</li>
<li>PostgreSQL forks a new process for each new client connection, which can allocate a significant amount of memory, typically around 10 MB per connection. However, this architecture is designed to provide improved security and isolation between different clients and is generally considered a trade-off for better performance, reliability, and scalability.</li>
<li>PostgreSQL is designed to prioritize extensibility, standards compliance, scalability, and data integrity. Sometimes, these features can decrease performance compared to MySQL, especially in simple read-heavy workloads. However, it's important to note that the exact performance difference depends on various factors, such as the data's size, the queries' complexity, and the hardware being used.</li>
</ol>
<h2 id="heading-which-migration-is-more-common-mysql-to-postgresql-or-postgresql-to-mysql">Which migration is more common: MySQL to PostgreSQL or PostgreSQL to MySQL?</h2>
<p>The migration frequency between MySQL and PostgreSQL varies and depends on individual organizations' needs and requirements. Some organizations may <a target="_blank" href="https://dbconvert.com/mysql/postgresql/">migrate from MySQL to PostgreSQL</a> to take advantage of its advanced features, better SQL compliance, and open-source compatibility. PostgreSQL is also more prevalent in specific industries, such as financial services, government, and data warehousing, where performance, scalability, and security are essential considerations.</p>
<p>On the other hand, other companies may <a target="_blank" href="https://dbconvert.com/postgresql/mysql/">migrate from PostgreSQL to MySQL</a> for its simplicity, broad community of support, and lower cost of implementation.</p>
<blockquote>
<p>The migration trend is towards moving from MySQL to PostgreSQL based on various indicators. These indicators suggest that more people are shifting from MySQL to PostgreSQL compared to the reverse.</p>
</blockquote>
<ol>
<li>Availability of migration tools: Many open-source and commercial migration tools are available to assist in migrating data from MySQL to PostgreSQL. At the same time, there are fewer tools to migrate data from PostgreSQL to MySQL.</li>
<li>Online resources: There is greater availability of online tutorials and resources on migrating from MySQL to PostgreSQL compared to the other way around.</li>
<li>Community growth: The PostgreSQL community has been growing faster than the MySQL community, indicating a growing interest in using PostgreSQL over MySQL.</li>
<li>Open source contributions: The number of open source contributions to PostgreSQL is increasing, indicating that more people are investing time and resources into the technology and finding it useful for their needs.</li>
<li>Enterprise adoption: Some of the world's largest and most data-intensive organizations, such as Cisco, Fujitsu, and the U.S. Federal Aviation Administration (FAA), have publicly stated that they have moved from MySQL to PostgreSQL.</li>
<li>User surveys: Industry analysts and database experts have conducted surveys that suggest that more people are considering or planning to switch from MySQL to PostgreSQL.</li>
</ol>
<p>These facts only indicate that more migrations happen from MySQL to PostgreSQL than the other way around, and it may only be true in some cases.</p>
<h2 id="heading-conclusion">Conclusion.</h2>
<p>PostgreSQL and MySQL are robust relational database management systems with unique features and limitations. The decision to use one over the other should be based on the specific requirements of a project, such as the nature and amount of data, the intricacy of queries, and performance and scalability needs. As both PostgreSQL and MySQL are set to undergo further advancements in 2023, it is crucial to stay updated on their recent developments.</p>
<p>In addition, it's worth mentioning that tools like <a target="_blank" href="https://dbconvert.com/dbconvert-studio">DBConvert Studio</a> can help with migrating data between MySQL and PostgreSQL in either direction. These tools can simplify the process of transferring data from one database to another, which can be especially useful if you consider switching from one system to another.</p>
]]></content:encoded></item><item><title><![CDATA[Streaming data from MySQL to Postgres.]]></title><description><![CDATA[title: Streaming data from MySQL to Postgres.
published: true
date: 2023-01-14 16:41:42 UTC
tags: database,programming,mysql,postgresql
canonical_url: https://dbconvert.com/blog/streaming-data-mysql-postgres/
 
Streaming data from a MySQL database to...]]></description><link>https://dbconvert.hashnode.dev/streaming-data-from-mysql-to-postgres</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/streaming-data-from-mysql-to-postgres</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Sat, 14 Jan 2023 16:41:42 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: Streaming data from MySQL to Postgres.
published: true
date: 2023-01-14 16:41:42 UTC
tags: database,programming,mysql,postgresql</p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogstreaming-data-mysql-postgres">canonical_url: https://dbconvert.com/blog/streaming-data-mysql-postgres/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056736967/e35728f4-93dc-466a-826c-e73199db6d49.png" alt="Streaming data from MySQL to Postgres." /></p>
<p>Streaming data from a MySQL database to a PostgreSQL database can be a useful way to move data between systems or to create a real-time replica of a database for reporting and analysis. One way to accomplish this is through the use of <a target="_blank" href="https://dev.to/slotix/change-data-capture-cdc-what-it-is-and-how-it-works-2mgo">Change Data Capture (CDC)</a> tools.</p>
<p>CDC is a method of tracking changes made to a database and capturing them in a separate stream. This stream can then be used to replicate the changes to another database.</p>
<p>DBConvert Streams helps to replicate your MySQL data to PostgreSQL in real-time. It captures data changes from a source MySQL database and applies them to a target PostgreSQL database. This can be done by setting up a source to read the binary log of a MySQL database and transform the changes to a format that can be consumed by target PostgreSQL database.</p>
<hr />
<p>This blog post will provide a comprehensive guide on how to stream data from MySQL to Postgres.</p>
<p>To begin, let's clone the GitHub repository containing the <a target="_blank" href="https://github.com/slotix/dbconvert-streams-public">MySQL to PostgreSQL streaming example</a>.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> git@github.com:slotix/dbconvert-streams-public.git &amp;&amp; <span class="hljs-built_in">cd</span> dbconvert-streams-public/examples/mysql2postgres/sales-db/
</code></pre>
<h2 id="heading-docker-compose-configuration">Docker Compose configuration.</h2>
<p>Since DBConvert Streams relies on multiple services, the most efficient way to start the containers is by using <a target="_blank" href="https://docs.docker.com/compose/">Docker Compose</a>.</p>
<p>The <em>docker-compose.yml</em> file from the repository is provided below.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">'3.9'</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">dbs-api:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">api</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">slotix/dbs-api</span>
    <span class="hljs-attr">entrypoint:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./dbs-api</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--nats=nats:4222</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--source=source-reader:8021</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--target=target-writer:8022</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">8020</span><span class="hljs-string">:8020</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">nats</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./mysql2pg.json:/mysql2pg.json:ro</span>

  <span class="hljs-attr">dbs-source-reader:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">source-reader</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">slotix/dbs-source-reader</span>
    <span class="hljs-attr">entrypoint:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./dbs-source-reader</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--nats=nats:4222</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">8021</span><span class="hljs-string">:8021</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">dbs-api</span>

  <span class="hljs-attr">dbs-target-writer:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">target-writer</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">slotix/dbs-target-writer</span>
    <span class="hljs-attr">entrypoint:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./dbs-target-writer</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--nats=nats:4222</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">--prometheus=http://prometheus:9090</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">8022</span><span class="hljs-string">:8022</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">dbs-source-reader</span>

  <span class="hljs-attr">nats:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">nats</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nats</span>
    <span class="hljs-attr">entrypoint:</span> <span class="hljs-string">/nats-server</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">"--jetstream -m 8222 --store_dir /data/nats-server"</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">4222</span><span class="hljs-string">:4222</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">8222</span><span class="hljs-string">:8222</span>

  <span class="hljs-attr">prometheus:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">slotix/dbs-prometheus:latest</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">prom</span>
    <span class="hljs-attr">user:</span> <span class="hljs-string">root</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">9090</span><span class="hljs-string">:9090</span>

  <span class="hljs-attr">mysql-source:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">mysql-source</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">./source</span> 
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">MYSQL_ROOT_PASSWORD=123456</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'3306:3306'</span>

  <span class="hljs-attr">postgres-target:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">postgres-target</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">postgres:15-alpine</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">POSTGRES_USER=postgres</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">POSTGRES_PASSWORD=postgres</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">postgres</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'5432:5432'</span>
</code></pre>
<p><em>Docker-compose file for DBConvert Streams</em></p>
<p>This docker-compose file is going to bring up multiple services and link them together so they can communicate with each other. With this setup, the replication process takes place between <code>mysql-source</code> and <code>postgres-target</code> databases, and it is controlled by <code>dbs-api</code>, <code>dbs-source-reader</code>, <code>dbs-target-writer</code> and <code>nats</code> services.</p>
<h3 id="heading-dbconvert-streams-services">DBConvert Streams services.</h3>
<ul>
<li><code>dbs-api</code> service is the entry point of DBConvert Streams. It is where requests are sent with configuration settings for the source and target databases. It specifies the connection details to other components of the system such as <code>source-reader</code>, and <code>target-writer</code>.</li>
<li><code>dbs-source-reader</code> service is responsible for monitoring and capturing changes in the source database, then sending batches of records to the Event Hub.  </li>
<li><code>dbs-target-writer</code> service is used to receive changes from the Event Hub and apply them to the target database..</li>
<li><code>nats</code> service is the core of the Event Hub, it provides communication between other DBS services.</li>
<li><code>prometheus</code> service is used for monitoring the metrics of DBS services.</li>
</ul>
<h3 id="heading-database-services">Database services.</h3>
<p>The structure of the tables that will be used in our example is depicted in the diagram below.</p>
<p><a target="_blank" href="https://github.com/slotix/dbconvert-streams-public/blob/main/examples/img/sales-db-erd.png"><img src="https://github.com/slotix/dbconvert-streams-public/raw/main/examples/img/sales-db-erd.png" alt="Streaming data from MySQL to Postgres." /></a>
<em>Entity Relationship (ER) Diagram of Database.</em></p>
<p>The structure of MySQL source tables is adapted from the <a target="_blank" href="https://github.com/jdaarevalo/docker_postgres_with_data">jdaarevalo/docker_postgres_with_data</a> GitHub repository.</p>
<h3 id="heading-source-and-target-databases">Source and Target Databases.</h3>
<p><code>mysql-source</code> database image is based on <code>slotix/dbs-mysql:8</code>, which includes all the necessary <a target="_blank" href="https://github.com/slotix/dbconvert-streams-public/tree/main/docker-images/mysql/base">settings to enable MySQL CDC replication</a>. This image also contains the <a target="_blank" href="https://github.com/slotix/dbconvert-streams-public/blob/main/examples/mysql2postgres/sales-db/source/docker-entrypoint-initdb.d/initdb.sql"><code>initdb.sql</code> script</a>, which creates tables with the structures shown above.</p>
<p><code>postgres-target</code> database, on the other hand,  is based on the official lightweight <code>postgres:15-alpine</code> image. <code>postgres-target</code> database will receive all changes made to the <code>mysql-source</code> database.</p>
<blockquote>
<p>Both of these databases, <code>mysql-source</code> and <code>postgres-target</code>, are typically located on separate physical servers in a production environment. However, in this example, we will run them on the same machine within distinct containers for demonstration purposes.</p>
</blockquote>
<h2 id="heading-execution">Execution.</h2>
<p>To start all services described above, execute the following command:</p>
<pre><code class="lang-bash">docker-compose up --build -d
</code></pre>
<p>This command will use the <code>docker-compose.yml</code> file to build and start the necessary containers in detached mode (-d option). The <code>--build</code> flag will force the rebuild of the images before starting the containers.</p>
<hr />
<p>To check if the MySQL database inside the running container has all tables created successfully by the script on start, you can run the command:</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -it mysql-source mysql -uroot -p123456 <span class="hljs-built_in">source</span> -e <span class="hljs-string">'SHOW TABLES;'</span>
</code></pre>
<p>By running the above command, you can see a list of tables created in the <code>source</code> database inside the container, which will confirm if the script has created all the tables successfully on start.</p>
<pre><code class="lang-bash">+------------------+
| Tables_in_source |
+------------------+
| city |
| country |
| order_status |
| product |
| sale |
| status_name |
| store |
| users |
+------------------+
</code></pre>
<p><em>List of tables created on source</em></p>
<h2 id="heading-stream-configuration">Stream configuration</h2>
<p>This is the stream configuration file <code>mysql2pg.json</code>  which is used to setup the database replication process.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"source"</span>: {
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"mysql"</span>,
    <span class="hljs-attr">"connection"</span>: <span class="hljs-string">"root:123456@tcp(mysql-source:3306)/source"</span>,
    <span class="hljs-attr">"filter"</span>: {
      <span class="hljs-attr">"tables"</span>: [
        { <span class="hljs-attr">"name"</span>: <span class="hljs-string">"product"</span>, <span class="hljs-attr">"operations"</span>: [<span class="hljs-string">"insert"</span>]},
        { <span class="hljs-attr">"name"</span>: <span class="hljs-string">"country"</span>, <span class="hljs-attr">"operations"</span>: [<span class="hljs-string">"insert"</span>]},
        { <span class="hljs-attr">"name"</span>: <span class="hljs-string">"city"</span>, <span class="hljs-attr">"operations"</span>: [<span class="hljs-string">"insert"</span>]},
        { <span class="hljs-attr">"name"</span>: <span class="hljs-string">"store"</span>, <span class="hljs-attr">"operations"</span>: [<span class="hljs-string">"insert"</span>]},
        { <span class="hljs-attr">"name"</span>: <span class="hljs-string">"users"</span>, <span class="hljs-attr">"operations"</span>: [<span class="hljs-string">"insert"</span>]},
        { <span class="hljs-attr">"name"</span>: <span class="hljs-string">"status_name"</span>, <span class="hljs-attr">"operations"</span>: [<span class="hljs-string">"insert"</span>]},
        { <span class="hljs-attr">"name"</span>: <span class="hljs-string">"sale"</span>, <span class="hljs-attr">"operations"</span>: [<span class="hljs-string">"insert"</span>]},
        { <span class="hljs-attr">"name"</span>: <span class="hljs-string">"order_status"</span>, <span class="hljs-attr">"operations"</span>: [<span class="hljs-string">"insert"</span>]}
      ]
    }
  },
  <span class="hljs-attr">"target"</span>: {
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"postgresql"</span>,
    <span class="hljs-attr">"connection"</span>: <span class="hljs-string">"postgres://postgres:postgres@postgres-target:5432/postgres"</span>
  },
  <span class="hljs-attr">"limits"</span>: {
    <span class="hljs-attr">"numberOfEvents"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">"elapsedTime"</span>: <span class="hljs-number">0</span>
  }
}
</code></pre>
<ul>
<li>The <code>source</code> field specifies the type of the source database as "<em>mysql</em>" and the connection details to connect to the database, including username and password as well as the host and port.</li>
<li>The <code>filter</code> field within the source field specifies that only certain tables and their corresponding operations (in this case "<em>insert</em>") will be replicated.</li>
<li>The <code>target</code> field specifies the type of the target database as "<em>postgresql</em>" and the connection details to connect to the target database, including username and password as well as the host and port.</li>
<li>The <code>limits</code> field specifies that number of events and elapsed time are set to zero (0), which means that there are no limits in place for this replication process.</li>
</ul>
<p>It is also worth noting that according to this config, only insert operations will be captured on the tables specified in the filter field.</p>
<h3 id="heading-send-configuration-to-dbconvert-streams-api">Send configuration to DBConvert Streams API.</h3>
<pre><code class="lang-bash">docker run -t --rm \
    --network sales-db_default \
    curlimages/curl \
    --request POST \
    --url http://dbs-api:8020/api/v1/streams\?file=./mysql2pg.json
</code></pre>
<p>This command runs a <code>docker run</code> command to start a new container from the <code>curlimages/curl</code> image. It specifies that the container should join the network named <code>sales-db_default</code> using <code>--network</code> option.</p>
<p>This container will then run the command <code>curl</code> to make a HTTP POST request to the url <code>http://dbs-api:8020/api/v1/streams?file=./mysql2pg.json</code>. The URL contains an endpoint that is the dbs-api service which is running on port 8020 and is expecting a json file as a query parameter. This command creates a new stream on the dbs-api service with the configuration specified in the <code>mysql2pg.json</code> file.</p>
<p>It's important to note that this command assumes that the <code>sales-db_default</code> network and the <code>dbs-api</code> service are already created and running. It also assumes that the <code>mysql2pg.json</code> file is in the current working directory from which the command is run.</p>
<p>This is a JSON response indicating that the stream creation was successful.</p>
<pre><code class="lang-json">{<span class="hljs-attr">"status"</span>:<span class="hljs-string">"success"</span>,
    <span class="hljs-attr">"data"</span>:{
        <span class="hljs-attr">"id"</span>:<span class="hljs-string">"2KGlt8BCHLT0lXklrs5wqM6n7BQ"</span>,
        <span class="hljs-attr">"source"</span>:{...},
        <span class="hljs-attr">"target"</span>:{...},
        <span class="hljs-attr">"limits"</span>:{}
     }
}
</code></pre>
<p>It contains the following fields:</p>
<ul>
<li><code>status</code>: This field indicates the status of the request, in this case "<em>success</em>"</li>
<li><code>data</code>: This field contains the details of the stream that was created.</li>
<li><code>id</code>: This field contains a unique identifier for the stream, in this case "2KGlt8BCHLT0lXklrs5wqM6n7BQ"</li>
<li><code>source</code>: This field contains the details of the source database, including the type, connection details, and filter settings.</li>
<li><code>target</code>: This field contains the details of the target database, including the type and connection details.</li>
<li><code>limits</code>: This field contains the limits for the replication process, such as number of events and elapsed time.</li>
</ul>
<p>Note that the details of the source and target field are not given here for brevity, it is just shown as <code>...</code>.</p>
<h3 id="heading-check-if-tables-on-the-target-are-created-successfully">Check if tables on the target are created successfully.</h3>
<blockquote>
<p>💡 DBConvert Streams creates tables with the same structure as the source on the target if they are missing. At this point, all tables specified in the filter should exist on the Postgres target database.</p>
</blockquote>
<p>To connect to the <code>postgres-target</code> Docker container and check if tables exist, you can run the following command:</p>
<pre><code class="lang-bash"> docker <span class="hljs-built_in">exec</span> -it postgres-target psql -U postgres -d postgres -c <span class="hljs-string">'\dt'</span>
</code></pre>
<p>By running the above command, you can see a list of tables created in the <code>postgres-target</code> database, which will confirm if DBConvert Streams has created all the tables successfully.</p>
<pre><code class="lang-bash">            List of relations
 Schema | Name | Type | Owner
--------+--------------+-------+----------
 public | city         | table | postgres
 public | country      | table | postgres
 public | order_status | table | postgres
 public | product      | table | postgres
 public | sale         | table | postgres
 public | status_name  | table | postgres
 public | store        | table | postgres
 public | users        | table | postgres
(8 rows)
</code></pre>
<h3 id="heading-populate-the-source-with-sample-data">Populate the source with sample data.</h3>
<p>Now that the <code>mysql-source</code> and <code>postgres-target</code> databases have identical table sets with the same structure, it is time to find out if the streaming of data works properly. This can be done by inserting data into the <code>mysql-source</code> database and observing if the same data is replicated to the <code>postgres-target</code> database.</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- Set params</span>
<span class="hljs-keyword">SET</span> @number_of_sales = <span class="hljs-string">'100'</span>;
<span class="hljs-keyword">SET</span> @number_of_users = <span class="hljs-string">'100'</span>;
<span class="hljs-keyword">SET</span> @number_of_products = <span class="hljs-string">'100'</span>;
<span class="hljs-keyword">SET</span> @number_of_stores = <span class="hljs-string">'100'</span>;
<span class="hljs-keyword">SET</span> @number_of_countries = <span class="hljs-string">'100'</span>;
<span class="hljs-keyword">SET</span> @number_of_cities = <span class="hljs-string">'30'</span>;
<span class="hljs-keyword">SET</span> @status_names = <span class="hljs-string">'5'</span>;
<span class="hljs-keyword">SET</span> @start_date = <span class="hljs-string">'2023-01-01 00:00:00'</span>;
<span class="hljs-keyword">SET</span> @end_date = <span class="hljs-string">'2023-02-01 00:00:00'</span>;

<span class="hljs-keyword">USE</span> <span class="hljs-keyword">source</span>;

<span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> city ;
<span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> product ;
<span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> country ;
<span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> status_name;
<span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">users</span>;
<span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> order_status;
<span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> sale;
<span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">store</span>;

<span class="hljs-comment">-- Filling of products</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> product
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">RECURSIVE</span> t(<span class="hljs-keyword">id</span>) <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
    <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span>
    <span class="hljs-keyword">FROM</span> t
    <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span> &lt;= @number_of_products
)
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">CONCAT_WS</span>(<span class="hljs-string">' '</span>,<span class="hljs-string">'Product'</span>, <span class="hljs-keyword">id</span>)
<span class="hljs-keyword">FROM</span> t;

<span class="hljs-comment">-- Filling of countries</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> country
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">RECURSIVE</span> t(<span class="hljs-keyword">id</span>) <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
    <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span>
    <span class="hljs-keyword">FROM</span> t
    <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span> &lt;= @number_of_countries
)
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">CONCAT</span>(<span class="hljs-string">'Country '</span>, <span class="hljs-keyword">id</span>)
<span class="hljs-keyword">FROM</span> t;

<span class="hljs-comment">-- Filling of cities</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> city
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">RECURSIVE</span> t(<span class="hljs-keyword">id</span>) <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
    <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span>
    <span class="hljs-keyword">FROM</span> t
    <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span> &lt;= @number_of_cities
)
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>
    , <span class="hljs-keyword">CONCAT</span>(<span class="hljs-string">'City '</span>, <span class="hljs-keyword">id</span>)
    , <span class="hljs-keyword">FLOOR</span>(<span class="hljs-keyword">RAND</span>() * (@number_of_countries + <span class="hljs-number">1</span>))
<span class="hljs-keyword">FROM</span> t;

<span class="hljs-comment">-- Filling of stores</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">store</span>
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">RECURSIVE</span> t(<span class="hljs-keyword">id</span>) <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
    <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span>
    <span class="hljs-keyword">FROM</span> t
    <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span> &lt;= @number_of_stores
)
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>
    , <span class="hljs-keyword">CONCAT</span>(<span class="hljs-string">'Store '</span>, <span class="hljs-keyword">id</span>)
    , <span class="hljs-keyword">FLOOR</span>(<span class="hljs-keyword">RAND</span>() * (@number_of_cities + <span class="hljs-number">1</span>))
<span class="hljs-keyword">FROM</span> t;

<span class="hljs-comment">-- Filling of users</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span>
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">RECURSIVE</span> t(<span class="hljs-keyword">id</span>) <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
    <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span>
    <span class="hljs-keyword">FROM</span> t
    <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> + <span class="hljs-number">1</span> &lt;= @number_of_users
)
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>
    , <span class="hljs-keyword">CONCAT</span>(<span class="hljs-string">'User '</span>, <span class="hljs-keyword">id</span>)
<span class="hljs-keyword">FROM</span> t;

<span class="hljs-comment">-- Filling of status_names</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> status_name
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">RECURSIVE</span> t(status_name_id) <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
    <span class="hljs-keyword">SELECT</span> status_name_id + <span class="hljs-number">1</span>
    <span class="hljs-keyword">FROM</span> t
    <span class="hljs-keyword">WHERE</span> status_name_id + <span class="hljs-number">1</span> &lt;= @status_names
)
<span class="hljs-keyword">SELECT</span> status_name_id
    , <span class="hljs-keyword">CONCAT</span>(<span class="hljs-string">'Status Name '</span>, status_name_id)
<span class="hljs-keyword">FROM</span> t;

<span class="hljs-comment">-- Filling of sales  </span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sale
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">RECURSIVE</span> t(sale_id) <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
    <span class="hljs-keyword">SELECT</span> sale_id + <span class="hljs-number">1</span>
    <span class="hljs-keyword">FROM</span> t
    <span class="hljs-keyword">WHERE</span> sale_id + <span class="hljs-number">1</span> &lt;= @number_of_sales
)
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">UUID</span>() <span class="hljs-keyword">AS</span> sale_id
    , <span class="hljs-keyword">ROUND</span>(<span class="hljs-keyword">RAND</span>() * <span class="hljs-number">10</span>, <span class="hljs-number">3</span>) <span class="hljs-keyword">AS</span> amount
    , <span class="hljs-keyword">DATE_ADD</span>(@start_date, <span class="hljs-built_in">INTERVAL</span> <span class="hljs-keyword">RAND</span>() * <span class="hljs-number">5</span> <span class="hljs-keyword">DAY</span>) <span class="hljs-keyword">AS</span> date_sale
    , <span class="hljs-keyword">FLOOR</span>(<span class="hljs-keyword">RAND</span>() * (@number_of_products + <span class="hljs-number">1</span>)) <span class="hljs-keyword">AS</span> product_id
    , <span class="hljs-keyword">FLOOR</span>(<span class="hljs-keyword">RAND</span>() * (@number_of_users + <span class="hljs-number">1</span>)) <span class="hljs-keyword">AS</span> user_id
    , <span class="hljs-keyword">FLOOR</span>(<span class="hljs-keyword">RAND</span>() * (@number_of_stores + <span class="hljs-number">1</span>)) <span class="hljs-keyword">AS</span> store_id
<span class="hljs-keyword">FROM</span> t;

<span class="hljs-comment">-- Filling of order_status</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> order_status
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">RECURSIVE</span> t(order_status_id) <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
    <span class="hljs-keyword">SELECT</span> order_status_id + <span class="hljs-number">1</span>
    <span class="hljs-keyword">FROM</span> t
    <span class="hljs-keyword">WHERE</span> order_status_id + <span class="hljs-number">1</span> &lt;= @number_of_sales
)
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">UUID</span>() <span class="hljs-keyword">AS</span> order_status_id
    , <span class="hljs-keyword">DATE_ADD</span>(@start_date, <span class="hljs-built_in">INTERVAL</span> <span class="hljs-keyword">RAND</span>() * <span class="hljs-number">5</span> <span class="hljs-keyword">DAY</span>) <span class="hljs-keyword">AS</span> update_at
    , <span class="hljs-keyword">FLOOR</span>(<span class="hljs-keyword">RAND</span>() * (@number_of_sales + <span class="hljs-number">1</span>)) <span class="hljs-keyword">AS</span> sale_id
    , <span class="hljs-keyword">FLOOR</span>(<span class="hljs-keyword">RAND</span>() * (@status_names + <span class="hljs-number">1</span>)) <span class="hljs-keyword">AS</span> status_name_id
<span class="hljs-keyword">FROM</span> t;
</code></pre>
<p>_fill<em>tables.sql script</em></p>
<p>This script above starts by truncating all the tables in the <code>source</code> database to clear any previous data, and then it inserts sample data into the tables. Each table is filled with sample data using a different set of parameters set at the top of the script.</p>
<p>To execute this SQL script, you can run the following command:</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -i \
    mysql-source \
    mysql -uroot -p123456 -D <span class="hljs-built_in">source</span> &lt; <span class="hljs-variable">$PWD</span>/fill_tables.sql
</code></pre>
<h3 id="heading-comparing-number-of-records-in-source-and-target-databases">Comparing number of records in source and target databases.</h3>
<p>Let's compare the number of rows in the tables of the source and target databases.</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -it mysql-source mysql -uroot -p123456 -D <span class="hljs-built_in">source</span> -e <span class="hljs-string">"SELECT (SELECT COUNT(*) FROM product) as 'product_count',(SELECT COUNT(*) FROM country) as 'country_count',(SELECT COUNT(*) FROM city) as 'city_count',(SELECT COUNT(*) FROM store) as 'store_count',(SELECT COUNT(*) FROM users) as 'users_count',(SELECT COUNT(*) FROM status_name) as 'status_name_count',(SELECT COUNT(*) FROM sale) as 'sale_count',(SELECT COUNT(*) FROM order_status) as 'order_status_count';"</span>
</code></pre>
<p><em>How many records are in each table of mysql-source db?</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056738682/a5986e72-6be4-4b1b-b4a9-a9beb0a5490e.png" alt="Streaming data from MySQL to Postgres." />
<em>COUNTs for mysql-source tables.</em></p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -it postgres-target psql -U postgres -d postgres -c <span class="hljs-string">"SELECT (SELECT COUNT(*) FROM product) as product_count,(SELECT COUNT(*) FROM country) as country_count,(SELECT COUNT(*) FROM city) as city_count,(SELECT COUNT(*) FROM store) as store_count,(SELECT COUNT(*) FROM users) as users_count,(SELECT COUNT(*) FROM status_name) as status_name_count,(SELECT COUNT(*) FROM sale) as sale_count,(SELECT COUNT(*) FROM order_status) as order_status_count;"</span>
</code></pre>
<p><em>how many records are in each table of postgres-target db?</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056739623/51b7b049-91dd-471f-b044-168f9808dd92.png" alt="Streaming data from MySQL to Postgres." />
<em>COUNTs for postgres-target tables.</em></p>
<blockquote>
<p>As you can see from the resulting output, all tables in both the source and target databases have an identical number of records in each table.</p>
</blockquote>
<h3 id="heading-check-statistics">Check statistics.</h3>
<p>The following command sends a GET request to the DBConvert API endpoint <code>/api/v1/streams/stat</code> which retrieves the statistics of current data stream. The <code>jq</code> command is used to format the JSON output for better readability.</p>
<pre><code class="lang-bash">docker run -t --rm \
    --network sales-db_default \
    curlimages/curl \
    --request GET \
    --url http://dbs-api:8020/api/v1/streams/<span class="hljs-built_in">stat</span> | jq

{
  <span class="hljs-string">"streamID"</span>: <span class="hljs-string">"2KHTjpsZAUCb8y1BZny3YKoX5qO"</span>,
  <span class="hljs-string">"source"</span>: {
    <span class="hljs-string">"counter"</span>: 635,
    <span class="hljs-string">"elapsed"</span>: <span class="hljs-string">"0s"</span>,
    <span class="hljs-string">"started"</span>: <span class="hljs-string">"2023-01-13T17:24:50.089257721Z"</span>,
    <span class="hljs-string">"status"</span>: <span class="hljs-string">"RUNNING"</span>
  },
  <span class="hljs-string">"target"</span>: {
    <span class="hljs-string">"counter"</span>: 635,
    <span class="hljs-string">"elapsed"</span>: <span class="hljs-string">"0s"</span>,
    <span class="hljs-string">"started"</span>: <span class="hljs-string">"2023-01-13T17:24:50.089649312Z"</span>,
    <span class="hljs-string">"status"</span>: <span class="hljs-string">"RUNNING"</span>
  }
}
</code></pre>
<p>The above output shows the statistics of the current data stream. The "source" field shows the statistics of the source database, and "target" field shows the statistics of the target database.</p>
<p>The "counter" field shows the number of events that have been processed by the stream, "elapsed" field shows the time elapsed since the stream started, "started" field shows the date and time when the stream was started and "status" field shows the status of the current stream.</p>
<h3 id="heading-prometheus-metrics">Prometheus metrics.</h3>
<p>Prometheus is a monitoring system that scrapes metrics data from various sources and stores them in a time-series database. DBConvert Streams collects its internal metrics in Prometheus format, allowing you to explore and visualize live data in dashboards. To view the collected metrics, visit <a target="_blank" href="http://127.0.0.1:9090/">http://127.0.0.1:9090</a> in a web browser to access the Prometheus UI.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056740700/e0f833d2-53bb-4df1-8e0c-bef1f39d51d7.png" alt="Streaming data from MySQL to Postgres." /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Change Data Capture (CDC) systems like <strong>DBConvert Streams</strong> can be used to stream data from a MySQL database to a PostgreSQL database in real-time, allowing you to keep the two systems in sync and take advantage of the unique features and capabilities of each database.</p>
<p>This guide provided information on streaming data in one direction, from MySQL Binlog to PostgreSQL. <a target="_blank" href="https://github.com/slotix/dbconvert-streams-public">The DBConvert Streams Github repository</a> contains more examples of configuring data streams, including from PostgreSQL Wals to MySQL and other configurations. These examples can serve as a starting point for setting up your own data stream, tailored to your specific needs and use case.</p>
<p>Getting your feedback about DBConvert Streams is essential for the development team to improve the software and make it more useful for the community. By sharing your ideas, reporting bugs, and requesting new features, you can actively participate in the development of the software and help to make it more robust and useful for everyone. Your participation is valued and appreciated by the development team and the community.</p>
]]></content:encoded></item><item><title><![CDATA[PostgreSQL Change data capture (CDC) + golang sample code.]]></title><description><![CDATA[title: PostgreSQL Change data capture (CDC) + golang sample code.
published: true
date: 2022-03-28 09:12:40 UTC
tags: database,postgresql,postgres,programming
canonical_url: https://dbconvert.com/blog/postgresql-change-data-capture-cdc/
 
The archite...]]></description><link>https://dbconvert.hashnode.dev/postgresql-change-data-capture-cdc-golang-sample-code</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/postgresql-change-data-capture-cdc-golang-sample-code</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Mon, 28 Mar 2022 09:12:40 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: PostgreSQL Change data capture (CDC) + golang sample code.
published: true
date: 2022-03-28 09:12:40 UTC
tags: database,postgresql,postgres,programming</p>
<h2 id="heading-canonicalurl-httpsdbconvertcomblogpostgresql-change-data-capture-cdc">canonical_url: https://dbconvert.com/blog/postgresql-change-data-capture-cdc/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056744760/7ee8d444-371d-436e-9864-2ec6432fe13d.png" alt="PostgreSQL Change data capture (CDC)" /></p>
<p>The architecture of modern web applications consists of several software components such as dashboards, analytics, databases, data lakes, caches, search, etc.</p>
<p>The database is usually the core part of any application. Real-time data updates keep disparate data systems in continuous sync and respond quickly to new information. So how to keep your application ecosystem in sync? How do these other components get information about changes in the database? <strong>Change Data Capture</strong> or <strong>CDC</strong> refers to any solution that identifies new or changed data.</p>
<blockquote>
<p><strong>This post is about PostgreSQL CDC</strong>  <strong>and the ways to achieve this.</strong></p>
<p><strong>Change data capture (CDC)</strong> is an approach to data integration to detect, capture, and deliver the changes made to database data sources.</p>
</blockquote>
<p>In General, CDC-based data integration consists of the following steps:</p>
<ol>
<li>Capture change data in a source database.</li>
<li>Convert the changed data to a format that your consumers can accept.</li>
<li>Publish the data to consumers or target database.</li>
</ol>
<p>PostgreSQL offers two built-in ways to make CDC possible:</p>
<ul>
<li>From <em>transaction logs,</em> PostgreSQL WALs, aka Write Ahead Logs.</li>
<li><em>Database Triggers.</em></li>
</ul>
<p>Let's briefly discuss the pros and cons of using Transaction logs (WALs) and Triggers to capture data changes.</p>
<h3 id="heading-triggers">Triggers.</h3>
<p>Trigger-based methods involve creating audit triggers on the database to capture all the events related to INSERT, UPDATE and DELETE methods.</p>
<p>Triggers can be attached to tables (partitioned or not) or views.</p>
<p>Triggers can also fire for TRUNCATE statements. If a trigger event occurs, the trigger's function is called at the appropriate time to handle the event.</p>
<ul>
<li>😄 The most important advantage of this method is that all of this can be done at the SQL level, unlike transaction logs.</li>
<li>😕 However, the use of triggers has a significant impact on the performance of the source database, because these triggers need to be run on the application database when changes are made to the data.</li>
</ul>
<h3 id="heading-transaction-logs">Transaction Logs</h3>
<p>On the other hand, for modern DBMS, <em>transaction logs (WAL for PostgreSQL)</em> are commonly used for <strong>transaction logging</strong> , replication, and REDO.</p>
<p>In PostgreSQL, all transactions like INSERT, UPDATE, DELETE, and DDLs are written to the WAL before the client sends the transaction result.</p>
<ul>
<li>The advantage of this approach is that <strong>it does not affect the performance of the database in any way.</strong></li>
<li>It also requires no modification to DB tables or the application. There is no need to create additional tables in the source database.</li>
<li>Log-based CDC is generally considered the superior approach to change data capture applicable to all possible scenarios, including systems with extremely high transaction volumes.</li>
</ul>
<blockquote>
<p><strong>If you want row-by-row streaming of Postgres data changes as they happen, you'll need <em>Logical Decoding</em> or <em>Postgres logical replication feature</em>.</strong></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056745961/c4ddf285-38ae-4672-868b-44797407fbc9.gif" alt="Image description" /></p>
<h3 id="heading-using-postgres-logical-decoding">Using Postgres Logical Decoding.</h3>
<p><a target="_blank" href="https://www.postgresql.org/docs/current/logicaldecoding-example.html">Logical decoding</a> is the official name of PostgreSQL's log-based CDC (Logical Replication).</p>
<p>Logical decoding uses the content of the PostgreSQL Write-Ahead Log to store all of the activities that occur in the database. Write Ahead Log is an internal log that describes database changes on a storage level.</p>
<ol>
<li>The first step in using logical decoding is to set the following parameters in the Postgres configuration <code>postgresql.conf</code>.</li>
</ol>
<pre><code class="lang-ini"><span class="hljs-attr">wal_level</span> = logical
<span class="hljs-attr">max_replication_slots</span> = <span class="hljs-number">5</span>
<span class="hljs-attr">max_wal_senders</span> = <span class="hljs-number">10</span>
</code></pre>
<ul>
<li>Setting <code>wal_level</code> to <code>logical</code> allows the WAL to record information needed for logical decoding.</li>
<li>Ensure that your <code>max_replication_slots</code> value is equal to or higher than the number of PostgreSQL connectors that use WAL <em>plus</em> the number of other replication slots your database uses.</li>
<li>Ensure that the <code>max_wal_senders</code> parameter, which specifies the maximum number of concurrent connections to the WAL, is at least twice the number of logical replication slots. For example, if your database uses 5 replication slots in total, the <code>max_wal_senders</code> value must be 10 or greater.</li>
</ul>
<p><em>Restart your Postgres server to apply the changes.</em></p>
<ol start="2">
<li>The second step is to set up logical replication using the output plugin <code>test_decoding</code></li>
</ol>
<p>Create a logical replication slot for the database you want to sync by running the following command.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> pg_create_logical_replication_slot(<span class="hljs-string">'replication_slot'</span>, <span class="hljs-string">'test_decoding'</span>);
</code></pre>
<p><strong>Note:</strong> <em>Each replication <a target="_blank" href="https://www.postgresql.org/docs/10/warm-standby.html#STREAMING-REPLICATION-SLOTS-MANIPULATION">slot has a name, which can contain lower-case letters, numbers, and the underscore character.</a></em></p>
<p>To verify the slot is created successfully run the following command.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> slot_name, <span class="hljs-keyword">plugin</span>, slot_type, <span class="hljs-keyword">database</span>, active, restart_lsn, confirmed_flush_lsn <span class="hljs-keyword">FROM</span> pg_replication_slots;
</code></pre>
<ol start="3">
<li>In the next step create a publication for all your tables or only specific ones. If you specify tables, you add or remove tables from the publication later.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> PUBLICATION pub <span class="hljs-keyword">FOR</span> <span class="hljs-keyword">ALL</span> <span class="hljs-keyword">TABLES</span>;
</code></pre>
<p>or</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> PUBLICATION pub <span class="hljs-keyword">FOR</span> <span class="hljs-keyword">TABLE</span> table1, table2, table3;
</code></pre>
<p>Optionally you can choose which operations to include in the publication. For example, the following publication includes only INSERT and UPDATE operations for <code>table1</code>.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> PUBLICATION insert_update_only_pub <span class="hljs-keyword">FOR</span> <span class="hljs-keyword">TABLE</span> table1 <span class="hljs-keyword">WITH</span> (publish = <span class="hljs-string">'INSERT, UPDATE'</span>);
</code></pre>
<ol start="4">
<li>Verify that your chosen tables are in the publication.</li>
</ol>
<pre><code class="lang-bash">psql-stream=<span class="hljs-comment"># SELECT * FROM pg_publication_tables WHERE pubname='pub';</span>
Output
pubname | schemaname | tablename
---------+------------+-----------
pub | public | table1
pub | public | table2
pub | public | table3
(3 rows)
</code></pre>
<p>Since then, our publication <code>pub</code> tracks all tables' changes in the <code>psql-stream</code> database.</p>
<ol start="5">
<li>Let's create an abstract table <code>t</code> and fill it with some records.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> t (<span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span>, <span class="hljs-keyword">name</span> <span class="hljs-built_in">text</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> t(<span class="hljs-keyword">id</span>) <span class="hljs-keyword">SELECT</span> g.id <span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-number">1</span>, <span class="hljs-number">10</span>) <span class="hljs-keyword">as</span> g(<span class="hljs-keyword">id</span>);
</code></pre>
<p>As a result we have 10 records in the table <code>t</code>.</p>
<pre><code class="lang-bash">psql-stream=<span class="hljs-comment"># SELECT count(*) FROM t;</span>
count
-------
10
(1 row)
</code></pre>
<ol start="6">
<li>Finally, it is time to check if our Logical Replication works.</li>
</ol>
<p>Run the following command in the PostgreSQL console to see Postgres WAL entries.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> pg_logical_slot_get_changes(<span class="hljs-string">'replication_slot'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-literal">NULL</span>);
</code></pre>
<p>As a result, you get something like:</p>
<pre><code class="lang-bash">    lsn | xid | data                          
-----------+------+--------------------------------------------------------
 0/19EA2C0 | 1045 | BEGIN 1045
 0/19EA2C0 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:1 name[text]:null
 0/19EA300 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:2 name[text]:null
 0/19EA340 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:3 name[text]:null
 0/19EA380 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:4 name[text]:null
 0/19EA3C0 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:5 name[text]:null
 0/19EA400 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:6 name[text]:null
 0/19EA440 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:7 name[text]:null
 0/19EA480 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:8 name[text]:null
 0/19EA4C0 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:9 name[text]:null
 0/19EA500 | 1045 | table public.t: INSERT: id[<span class="hljs-built_in">integer</span>]:10 name[text]:null
 0/19EA5B0 | 1045 | COMMIT 1045
(13 rows)
</code></pre>
<p><code>pg_logical_slot_peek_changes</code> is another PostgreSQL command to peek changes from WAL entries  without consuming them.  So calling <code>pg_logical_slot_peek_changes</code> multiple times returns the same result each time.</p>
<p>On the other hand  <code>pg_logical_slot_get_changes</code>  only returns results the first time. The following calls of <code>pg_logical_slot_get_changes</code> return empty result sets. This means when <code>get</code> command is executed, the results are served and deleted, which greatly enhancing our ability to write the logic for using these events to create a replica of the table.</p>
<ol start="7">
<li>Remember to destroy a slot you no longer need to stop it consuming</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> pg_drop_replication_slot(<span class="hljs-string">'replication_slot'</span>);
</code></pre>
<h3 id="heading-output-plugins">Output plugins.</h3>
<p>We've already talked about <code>test_decoding</code> output plugin available on Postgres 9.4+. Though created as an example of an output plugin, it is still useful if your consumer supports it.</p>
<p>Along with the <code>test_decoding</code> plugin, another <code>pgoutput</code> plugin is shipped with PostgreSQL natively. <code>pgoutput</code> is available since Postgres 10. Some consumers support it for decoding (e.g. Debezium).</p>
<p>Run the following command to create the plugin based on <code>pgoutput</code> as in step 2 above.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> pg_create_logical_replication_slot(<span class="hljs-string">'replication_slot'</span>, <span class="hljs-string">'pgoutput'</span>);
</code></pre>
<p>The following command consumes data changes similar to those described in step 6.</p>
<pre><code class="lang-bash">psql-stream=<span class="hljs-comment"># SELECT * FROM pg_logical_slot_peek_binary_changes('replication_slot', null, null, 'proto_version', '1', 'publication_names', 'pub');</span>
    lsn | xid | data                                           
-----------+------+------------------------------------------------------------------------------------------
 0/19A15F8 | 1038 | \x4200000000019a1d9000027de20a91a0ea0000040e
 0/19A15F8 | 1038 | \x52000080387075626c69630074006400020169640000000017ffffffff006e616d650000000019ffffffff
 0/19A15F8 | 1038 | \x49000080384e0002740000000234306e
 0/19A1890 | 1038 | \x49000080384e0002740000000234316e
 0/19A1910 | 1038 | \x49000080384e0002740000000234326e
 0/19A1990 | 1038 | \x49000080384e0002740000000234336e
 0/19A1A10 | 1038 | \x49000080384e0002740000000234346e
 0/19A1A90 | 1038 | \x49000080384e0002740000000234356e
 0/19A1B10 | 1038 | \x49000080384e0002740000000234366e
 0/19A1B90 | 1038 | \x49000080384e0002740000000234376e
 0/19A1C10 | 1038 | \x49000080384e0002740000000234386e
 0/19A1C90 | 1038 | \x49000080384e0002740000000234396e
 0/19A1DC0 | 1038 | \x430000000000019a1d9000000000019a1dc000027de20a91a0ea
(13 rows)
</code></pre>
<p>Here you can notice that the results are returned in binary format. <em><code>pgoutput</code> plugin produces binary output.</em></p>
<p><code>wal2json</code> is another popular output plugin for logical decoding.</p>
<p>Here is a sample output from <code>wal2json</code> plugin</p>
<pre><code class="lang-json">{
      <span class="hljs-attr">"change"</span>:[
         {
            <span class="hljs-attr">"kind"</span>:<span class="hljs-string">"insert"</span>,
            <span class="hljs-attr">"schema"</span>:<span class="hljs-string">"public"</span>,
            <span class="hljs-attr">"table"</span>:<span class="hljs-string">"t"</span>,
            <span class="hljs-attr">"columnnames"</span>:[
               <span class="hljs-string">"id"</span>,
               <span class="hljs-string">"name"</span>
            ],
            <span class="hljs-attr">"columntypes"</span>:[
               <span class="hljs-string">"integer"</span>,
               <span class="hljs-string">"character varying(255)"</span>
            ],
            <span class="hljs-attr">"columnvalues"</span>:[
               <span class="hljs-number">1</span>,
               <span class="hljs-string">""</span>
            ]
         }
      ]
   }
   {
      <span class="hljs-attr">"change"</span>:[
         {
            <span class="hljs-attr">"kind"</span>:<span class="hljs-string">"update"</span>,
            <span class="hljs-attr">"schema"</span>:<span class="hljs-string">"public"</span>,
            <span class="hljs-attr">"table"</span>:<span class="hljs-string">"t"</span>,
            <span class="hljs-attr">"columnnames"</span>:[
               <span class="hljs-string">"id"</span>,
               <span class="hljs-string">"name"</span>
            ],
            <span class="hljs-attr">"columntypes"</span>:[
               <span class="hljs-string">"integer"</span>,
               <span class="hljs-string">"character varying(255)"</span>
            ],
            <span class="hljs-attr">"columnvalues"</span>:[
               <span class="hljs-number">1</span>,
               <span class="hljs-string">"New Value"</span>
            ],
            <span class="hljs-attr">"oldkeys"</span>:{
               <span class="hljs-attr">"keynames"</span>:[
                  <span class="hljs-string">"id"</span>
               ],
               <span class="hljs-attr">"keytypes"</span>:[
                  <span class="hljs-string">"integer"</span>
               ],
               <span class="hljs-attr">"keyvalues"</span>:[
                  <span class="hljs-number">1</span>
               ]
            }
         }
      ]
   }
   {
      <span class="hljs-attr">"change"</span>:[
         {
            <span class="hljs-attr">"kind"</span>:<span class="hljs-string">"delete"</span>,
            <span class="hljs-attr">"schema"</span>:<span class="hljs-string">"public"</span>,
            <span class="hljs-attr">"table"</span>:<span class="hljs-string">"t"</span>,
            <span class="hljs-attr">"oldkeys"</span>:{
               <span class="hljs-attr">"keynames"</span>:[
                  <span class="hljs-string">"id"</span>
               ],
               <span class="hljs-attr">"keytypes"</span>:[
                  <span class="hljs-string">"integer"</span>
               ],
               <span class="hljs-attr">"keyvalues"</span>:[
                  <span class="hljs-number">1</span>
               ]
            }
         }
      ]
   }
</code></pre>
<h3 id="heading-important-tips-about-slots">Important tips about slots.</h3>
<p>Keep the following in mind when working with slots:</p>
<ul>
<li>Each slot has only one output plugin (you choose which one).</li>
<li>Each slot provides changes from only one database.</li>
<li>One database can have multiple slots.</li>
<li>Each data change is typically is emitted once per slot.</li>
<li>But a slot may re-emit the changes when the Postgres instance is restarted. A consumer must deal with this situation.</li>
<li>An unconsumed slot is a threat to the availability of your Postgres instance. Postgres will save all WAL files for these unconsumed changes. This can lead to storage overflow.</li>
</ul>
<h3 id="heading-postgresql-wal-consumers">PostgreSQL WAL consumers.</h3>
<p>A consumer is any application that can ingest the Postgres logical decoding stream.  <a target="_blank" href="https://www.postgresql.org/docs/current/app-pgrecvlogical.html">pg_recvlogical</a> is a PostgreSQL application that can manage slots and consume the stream from them. It is included in the Postgres distribution,  so it's probably already installed with PostgreSQL.</p>
<p><img src="https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE4fHxnbyUyMGNvZGV8ZW58MHx8fHwxNjQ4NDU1NDI3&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="PostgreSQL Change data capture (CDC)" />
<em>Photo by Markus Spiske / Unsplash</em></p>
<h3 id="heading-ia"> </h3>
<p>Golang sample code. </p>
<p>The following Golang code example shows how to get started creating your own Postgress WAL consumer. It uses PostgreSQL-10.x logical replication to stream database changes (decoded WAL messages) from the source database.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"os"</span>
    <span class="hljs-string">"os/signal"</span>
    <span class="hljs-string">"strings"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"github.com/jackc/pgconn"</span>
    <span class="hljs-string">"github.com/jackc/pglogrepl"</span>
    <span class="hljs-string">"github.com/jackc/pgproto3/v2"</span>
)

<span class="hljs-keyword">const</span> CONN = <span class="hljs-string">"postgres://postgres:postgres@localhost/psql-streamer?replication=database"</span>
<span class="hljs-keyword">const</span> SLOT_NAME = <span class="hljs-string">"replication_slot"</span>
<span class="hljs-keyword">const</span> OUTPUT_PLUGIN = <span class="hljs-string">"pgoutput"</span>
<span class="hljs-keyword">const</span> INSERT_TEMPLATE = <span class="hljs-string">"create table t (id int, name text);"</span>

<span class="hljs-keyword">var</span> Event = <span class="hljs-keyword">struct</span> {
    Relation <span class="hljs-keyword">string</span>
    Columns []<span class="hljs-keyword">string</span>
}{}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
    <span class="hljs-keyword">defer</span> cancel()
    conn, err := pgconn.Connect(ctx, CONN)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(err)
    }
    <span class="hljs-keyword">defer</span> conn.Close(ctx)

    <span class="hljs-comment">// 1. Create table</span>
    <span class="hljs-keyword">if</span> _, err := conn.Exec(ctx, INSERT_TEMPLATE).ReadAll(); err != <span class="hljs-literal">nil</span> {
        fmt.Errorf(<span class="hljs-string">"failed to create table: %v"</span>, err)
    }

    <span class="hljs-comment">// 2. ensure publication exists</span>
    <span class="hljs-keyword">if</span> _, err := conn.Exec(ctx, <span class="hljs-string">"DROP PUBLICATION IF EXISTS pub;"</span>).ReadAll(); err != <span class="hljs-literal">nil</span> {
        fmt.Errorf(<span class="hljs-string">"failed to drop publication: %v"</span>, err)
    }

    <span class="hljs-keyword">if</span> _, err := conn.Exec(ctx, <span class="hljs-string">"CREATE PUBLICATION pub FOR ALL TABLES;"</span>).ReadAll(); err != <span class="hljs-literal">nil</span> {
        fmt.Errorf(<span class="hljs-string">"failed to create publication: %v"</span>, err)
    }

    <span class="hljs-comment">// 3. create temproary replication slot server</span>
    <span class="hljs-keyword">if</span> _, err = pglogrepl.CreateReplicationSlot(ctx, conn, SLOT_NAME, OUTPUT_PLUGIN, pglogrepl.CreateReplicationSlotOptions{Temporary: <span class="hljs-literal">true</span>}); err != <span class="hljs-literal">nil</span> {
        fmt.Errorf(<span class="hljs-string">"failed to create a replication slot: %v"</span>, err)
    }

    <span class="hljs-keyword">var</span> msgPointer pglogrepl.LSN
    pluginArguments := []<span class="hljs-keyword">string</span>{<span class="hljs-string">"proto_version '1'"</span>, <span class="hljs-string">"publication_names 'pub'"</span>}

    <span class="hljs-comment">// 4. establish connection</span>
    err = pglogrepl.StartReplication(ctx, conn, SLOT_NAME, msgPointer, pglogrepl.StartReplicationOptions{PluginArgs: pluginArguments})
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        fmt.Errorf(<span class="hljs-string">"failed to establish start replication: %v"</span>, err)
    }

    <span class="hljs-keyword">var</span> pingTime time.Time
    <span class="hljs-keyword">for</span> ctx.Err() != context.Canceled {
        <span class="hljs-keyword">if</span> time.Now().After(pingTime) {
            <span class="hljs-keyword">if</span> err = pglogrepl.SendStandbyStatusUpdate(ctx, conn, pglogrepl.StandbyStatusUpdate{WALWritePosition: msgPointer}); err != <span class="hljs-literal">nil</span> {
                fmt.Errorf(<span class="hljs-string">"failed to send standby update: %v"</span>, err)
            }
            pingTime = time.Now().Add(<span class="hljs-number">10</span> * time.Second)
            <span class="hljs-comment">//fmt.Println("client: please standby")</span>
        }

        ctx, cancel := context.WithTimeout(ctx, time.Second*<span class="hljs-number">10</span>)
        <span class="hljs-keyword">defer</span> cancel()

        msg, err := conn.ReceiveMessage(ctx)
        <span class="hljs-keyword">if</span> pgconn.Timeout(err) {
            <span class="hljs-keyword">continue</span>
        }
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            fmt.Errorf(<span class="hljs-string">"something went wrong while listening for message: %v"</span>, err)
        }

        <span class="hljs-keyword">switch</span> msg := msg.(<span class="hljs-keyword">type</span>) {
        <span class="hljs-keyword">case</span> *pgproto3.CopyData:
            <span class="hljs-keyword">switch</span> msg.Data[<span class="hljs-number">0</span>] {
            <span class="hljs-keyword">case</span> pglogrepl.PrimaryKeepaliveMessageByteID:
            <span class="hljs-comment">//    fmt.Println("server: confirmed standby")</span>

            <span class="hljs-keyword">case</span> pglogrepl.XLogDataByteID:
                walLog, err := pglogrepl.ParseXLogData(msg.Data[<span class="hljs-number">1</span>:])
                <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                    fmt.Errorf(<span class="hljs-string">"failed to parse logical WAL log: %v"</span>, err)
                }

                <span class="hljs-keyword">var</span> msg pglogrepl.Message
                <span class="hljs-keyword">if</span> msg, err = pglogrepl.Parse(walLog.WALData); err != <span class="hljs-literal">nil</span> {
                    fmt.Errorf(<span class="hljs-string">"failed to parse logical replication message: %v"</span>, err)
                }
                <span class="hljs-keyword">switch</span> m := msg.(<span class="hljs-keyword">type</span>) {
                <span class="hljs-keyword">case</span> *pglogrepl.RelationMessage:
                    Event.Columns = []<span class="hljs-keyword">string</span>{}
                    <span class="hljs-keyword">for</span> _, col := <span class="hljs-keyword">range</span> m.Columns {
                        Event.Columns = <span class="hljs-built_in">append</span>(Event.Columns, col.Name)
                    }
                    Event.Relation = m.RelationName
                <span class="hljs-keyword">case</span> *pglogrepl.InsertMessage:
                    <span class="hljs-keyword">var</span> sb strings.Builder
                    sb.WriteString(fmt.Sprintf(<span class="hljs-string">"INSERT %s("</span>, Event.Relation))
                    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-built_in">len</span>(Event.Columns); i++ {
                        sb.WriteString(fmt.Sprintf(<span class="hljs-string">"%s: %s "</span>, Event.Columns[i], <span class="hljs-keyword">string</span>(m.Tuple.Columns[i].Data)))
                    }
                    sb.WriteString(<span class="hljs-string">")"</span>)
                    fmt.Println(sb.String())
                <span class="hljs-keyword">case</span> *pglogrepl.UpdateMessage:
                    <span class="hljs-keyword">var</span> sb strings.Builder
                    sb.WriteString(fmt.Sprintf(<span class="hljs-string">"UPDATE %s("</span>, Event.Relation))
                    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-built_in">len</span>(Event.Columns); i++ {
                        sb.WriteString(fmt.Sprintf(<span class="hljs-string">"%s: %s "</span>, Event.Columns[i], <span class="hljs-keyword">string</span>(m.NewTuple.Columns[i].Data)))
                    }
                    sb.WriteString(<span class="hljs-string">")"</span>)
                    fmt.Println(sb.String())
                <span class="hljs-keyword">case</span> *pglogrepl.DeleteMessage:
                    <span class="hljs-keyword">var</span> sb strings.Builder
                    sb.WriteString(fmt.Sprintf(<span class="hljs-string">"DELETE %s("</span>, Event.Relation))
                    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-built_in">len</span>(Event.Columns); i++ {
                        sb.WriteString(fmt.Sprintf(<span class="hljs-string">"%s: %s "</span>, Event.Columns[i], <span class="hljs-keyword">string</span>(m.OldTuple.Columns[i].Data)))
                    }
                    sb.WriteString(<span class="hljs-string">")"</span>)
                    fmt.Println(sb.String())
                <span class="hljs-keyword">case</span> *pglogrepl.TruncateMessage:
                    fmt.Println(<span class="hljs-string">"ALL GONE (TRUNCATE)"</span>)
                }
            }
        <span class="hljs-keyword">default</span>:
            fmt.Printf(<span class="hljs-string">"received unexpected message: %T"</span>, msg)
        }
    }
}
</code></pre>
<p>This code just logs incoming events, but in a production environment you can easily send them to a message queue or a target database.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Logical decoding in PostgreSQL provides an efficient way for other application components to stay up-to-date with data changes in your Postgres database.</p>
<blockquote>
<p>Traditionally, the <em> <strong>pull notification model</strong> </em> has been used, in which each application component queries Postgres at a certain interval. Logical encoding uses the <em> <strong>push notification model</strong> </em>, where Postgres notifies other parts of the application of every change as soon as it happens.</p>
</blockquote>
<p>Data change events can now be sent to consumers in milliseconds without querying the database. With logic decoding, the PostgreSQL database becomes a central part of your modern dynamic real-time application.</p>
<p><a target="_blank" href="https://streams.dbconvert.com">DBConvert Streams</a> is a new data replication platform that uses CDC technology to stream data between databases.</p>
]]></content:encoded></item><item><title><![CDATA[How to scrape a website that requires login?]]></title><description><![CDATA[title: How to scrape a website that requires login?
published: true
date: 2020-11-09 22:04:24 UTC
tags: cookies,webscraping,webdev,showdev
canonical_url: https://dataflowkit.com/blog/how-to-pass-cookies-to-a-scraper-from-a-web-browser/
 
Many website...]]></description><link>https://dbconvert.hashnode.dev/how-to-scrape-a-website-that-requires-login</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/how-to-scrape-a-website-that-requires-login</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Mon, 09 Nov 2020 22:04:24 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: How to scrape a website that requires login?
published: true
date: 2020-11-09 22:04:24 UTC
tags: cookies,webscraping,webdev,showdev</p>
<h2 id="heading-canonicalurl-httpsdataflowkitcombloghow-to-pass-cookies-to-a-scraper-from-a-web-browser">canonical_url: https://dataflowkit.com/blog/how-to-pass-cookies-to-a-scraper-from-a-web-browser/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056751026/e89e4f89-6377-40df-aa63-a3d8f3c383db.png" alt="How to Log in to a website by passing cookies to a web scraper?" /></p>
<p>Many websites demand users to register or login before they provide any information. Browsers store cookies for each session as the user navigates the website. Other websites may show pop-ups if they do not have location cookies or if the user explicitly consents to the collection of their data.</p>
<p>Indeed, you can simulate user input to enter credentials, click a button to submit a form. Sometimes, you need to press a checkbox to accept website terms while scraping the data.</p>
<p>Another way is to pass session cookies when you send a request to a website. This article will show how to transfer cookies from a web browser to a Dataflow Kit web scraper.</p>
<h3 id="heading-follow-the-instructions-described-below-to-crawl-specific-websites-that-require-login">Follow the instructions described below to crawl specific websites that require login:</h3>
<ol>
<li>Install <a target="_blank" href="http://www.editthiscookie.com/">EditThisCookie</a> extension to your web browser.</li>
<li>Go to the website that you want to crawl and sign in with your credentials.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056752293/0b083b7a-5479-489e-98ad-5578aecda5f9.png" alt="How to Log in to a website by passing cookies to a web scraper?" /></p><figcaption>Open a website to scrape.</figcaption><p></p>
<ol start="3">
<li>Open the "EditThisCookie" extension by clicking the button next to your URL. Copy the cookies to the clipboard using the "Export" button.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056753669/3fcf8e4d-244f-40ef-bb38-2be43ed3a8dd.png" alt="How to Log in to a website by passing cookies to a web scraper?" /></p><figcaption>Export cookies to JSON Array format</figcaption><p></p>
<ol start="4">
<li>Now paste cookies (Ctrl + V) from the clipboard into the "Initial cookies" field of a Dataflow Kit scraper. Cookies in JSON array format are compatible with the cookie format used by Dataflow Kit.</li>
</ol>
<p>As an example, we'll use the Dataflow Kit <a target="_blank" href="https://dataflowkit.com/url-to-screenshot">Screen Capture Service</a> to illustrate the cookie transfer function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056754799/9a523d38-ff94-440f-9800-0b8a1575ca6d.png" alt="How to Log in to a website by passing cookies to a web scraper?" /></p>
<p>That's all! Now you run the scraper, and it starts already logged in.</p>
<h3 id="heading-result">Result</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056756058/405671c7-de12-4a82-8f16-34a896ccc4cb.png" alt="How to Log in to a website by passing cookies to a web scraper?" /></p>
<p>In the captured screenshot, we can see that it was captured after the login page.</p>
%[INVALID_URL]<hr />
<p>You are not limited to transferring the initial cookies only to the Dataflow Kit services provided on our website. You can add initial cookies to any custom web scraper powered by the Dataflow Kit framework. You can customize your payloads at <a target="_blank" href="https://account.dataflowkit.com/tasks">https://account.dataflowkit.com/tasks</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056757560/b59652f3-0bed-4b2c-914d-d4d5c1fdfa36.png" alt="How to Log in to a website by passing cookies to a web scraper?" /></p><figcaption>Custom tasks</figcaption><p></p>
<p>You can customize any Task payload and add InitialCookies manually to request.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056759114/0ee4c9b6-d222-4051-b36c-077f730eeaa6.png" alt="How to Log in to a website by passing cookies to a web scraper?" /></p><figcaption>Add Initial Cookies to your payloads</figcaption><p></p>
<hr />
<p>Depending on a scraped website, cookies may be short-lived, and this approach with passing initial cookies is not a way to go.  In this case, the right solution is to use actions to simulate filling out forms and pressing the submit button.</p>
]]></content:encoded></item><item><title><![CDATA[Beginner’s guide to Web Scraping with PHP.]]></title><description><![CDATA[title: Beginner’s guide to Web Scraping with PHP.
published: true
date: 2020-11-02 15:25:48 UTC
tags: PHP,API,scrape,webscraping
canonical_url: https://dataflowkit.com/blog/php-api/
 
Scraping simple HTML from the Web is not a problem in modern progr...]]></description><link>https://dbconvert.hashnode.dev/beginners-guide-to-web-scraping-with-php</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/beginners-guide-to-web-scraping-with-php</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Mon, 02 Nov 2020 15:25:48 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: Beginner’s guide to Web Scraping with PHP.
published: true
date: 2020-11-02 15:25:48 UTC
tags: PHP,API,scrape,webscraping</p>
<h2 id="heading-canonicalurl-httpsdataflowkitcomblogphp-api">canonical_url: https://dataflowkit.com/blog/php-api/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056763236/d5b74d3f-3409-4ce8-afd5-b5b3b58d4256.png" alt="Beginner’s guide to Web Scraping with PHP." /></p>
<p>Scraping simple HTML from the Web is not a problem in modern programming languages. While PHP is especially suited for web development, its ability to send HTTP requests is severely lacking. The <a target="_blank" href="https://github.com/rmccue/Requests">Requests library for PHP</a> developers is an excellent solution for sending HTTP requests to websites.</p>
<h2 id="heading-render-javascript-webpages">Render Javascript webpages.</h2>
<p>It's not enough to download content from a website as-is with a library like PHP Requests. Most modern websites are heavily based on Javascript frameworks like Angular, React, or Vue.js. We can talk about client-side rendering where Javascript content returned as a response needs to be rendered in a web browser. Mainly the headless Chrome browser is used to render dynamic content from websites and returns it as a static HTML.</p>
<h2 id="heading-using-proxies">Using Proxies.</h2>
<p>Another challenge is to fetch web page content restricted to users from specified countries only. <em>Using proxy servers</em> is required to obtain country-specific versions of target websites or to bypass content download restrictions.</p>
<hr />
<blockquote>
<p>In most cases, running your own headless Chrome browser cluster and a proxy pool is expensive. It makes more sense to use a special service to<br />render Javascript driven web pages in the cloud, and return static HTML.</p>
</blockquote>
<h2 id="heading-how-to-scrape-websites-using-php-script">How to scrape Websites using PHP script?</h2>
<p>I will share the code for PHP developers who have shown a lot of interest lately. We will generate the simple PHP script that sends requests to <a target="_blank" href="https://dataflowkit.com/html-scraping">Web Scraping Service API</a>.  To automate HTML scraping tasks, follow the steps describes below:</p>
<h2 id="heading-1-get-a-free-api-key">1. Get a Free API Key.</h2>
<p><strong>Dataflow Kit API Key is required</strong> to get access to Dataflow Kit API. the server. You can obtain it from the user dashboard after free registration. Once you sign-up, we grant you <em>free 1000 credits.</em></p>
<p>Go to <a target="_blank" href="https://account.dataflowkit.com/">https://account.dataflowkit.com</a> and either use Facebook/Google login or register with your email.</p>
<p>Click on the <strong>"Log in"</strong>  button to register with your Facebook or Google account. Or press the <strong>"Sign Up"</strong> link to register with your email.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056764948/2a22dfca-e903-469a-bcf3-c0ede2c2a634.png" alt="Beginner’s guide to Web Scraping with PHP." /></p>
<p>You will need to authorize requests to the Dataflow Kit API. Later we will add it to our PHP script. Please find it in <a target="_blank" href="https://account.dataflowkit.com/settings">dashboard Settings</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056766044/5bb9632b-b2d1-48e1-9871-6e4e52cb2725.png" alt="Beginner’s guide to Web Scraping with PHP." /></p>
<h2 id="heading-2-install-php-requests">2. Install PHP Requests.</h2>
<p>There is one dependency here. Before running the final script, follow installation instructions at <a target="_blank" href="https://github.com/rmccue/Requests">https://github.com/rmccue/Requests</a> and install PHP Requests package mentioned above.</p>
<h2 id="heading-3-generate-php-script-and-send-requests-to-the-api">3. Generate PHP script and send requests to the API.</h2>
<p>3.1. Go to <a target="_blank" href="https://dataflowkit.com/html-scraping">https://dataflowkit.com/html-scraping</a> .   Specify some parameters for HTML Scraping API code generator to generate PHP Script.</p>

<div class="hn-table">
<table>
<thead>
<tr>
<td>Parameter</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>api_key</td><td>API Key is used to authenticate with the API - You can find it in your Account Dashboard</td></tr>
<tr>
<td>URL</td><td>Provide a URL to download content.</td></tr>
<tr>
<td>Proxy</td><td>Select a country to pass requests through a proxy located there to target web sites.</td></tr>
<tr>
<td>Render Javascript</td><td>Set it to "Yes" to render Javascript dynamic web pages. For static HTML web pages, choose "No." Defaults to "Yes."</td></tr>
<tr>
<td>Wait Delay</td><td>Specify the "Wait Delay" parameter for a custom delay (in seconds). It can sometimes be helpful to set aside more time to render certain elements of the website after the initial page load.</td></tr>
<tr>
<td>Actions</td><td>Use actions: Input, Click, Wait, Scroll to automate manual workflows while rendering web pages. They simulate real-world human interaction with pages.</td></tr>
</tbody>
</table>
</div>
<p>Depending on specified parameters, you get something like:</p>
<pre><code>&lt;?php
include(<span class="hljs-string">'vendor/rmccue/requests/library/Requests.php'</span>);
Requests::register_autoloader();
$headers = array(
    <span class="hljs-string">'Content-Type'</span> =&gt; <span class="hljs-string">'application/json'</span>
);
$url = <span class="hljs-string">'https://dbconvert.com/'</span>;
$data = <span class="hljs-string">'{"url":"'</span> . $url . <span class="hljs-string">'","type": "chrome","waitDelay": 0.5}'</span>;
$response = Requests::post(<span class="hljs-string">'https://api.dataflowkit.com/v1/fetch?api_key=API-KEY'</span>, $headers, $data);
var_dump($response-&gt;body);
?&gt;
</code></pre><figcaption>PHP script for accessing Dataflow Kit API.</figcaption>

<p>3.2. Save the code above, for example, as "dfk-api.php"</p>
<p>3.3. Now add the actual API Key found at  <a target="_blank" href="https://account.dataflowkit.com/settings">https://account.dataflowkit.com/settings</a> in place of API-KEY.  It looks like something "ab5cc2a84f7efab1693e8fc72he5f7e844b1bf5cbad9ea33".  See the step #1.</p>
<p>3.4. That's all. Now you can run the script and get rendered HTML content from any web site.</p>
<h2 id="heading-note-for-docker-users">Note for Docker users.</h2>
<p>It is even simpler to build and run a docker image to run the script.</p>
<pre><code>FROM php:<span class="hljs-number">7.4</span>-cli
RUN apt-get update &amp;&amp; \
    apt-get upgrade -y &amp;&amp; \
    apt-get install -y git
RUN git clone git:<span class="hljs-comment">//github.com/rmccue/Requests.git</span>
COPY . /usr/src/dfk-api
RUN mv Requests /usr/src/dfk-api
WORKDIR /usr/src/dfk-api
CMD [<span class="hljs-string">"php"</span>, <span class="hljs-string">"./dfk-api.php"</span>]
</code></pre><figcaption>Dockerfile</figcaption>

<p>Follow the steps below to build &amp; run a PHP script that calls Dataflow Kit HTML scraping API service:</p>
<ol>
<li>Open file dfk-api.php</li>
<li>Exchange API-KEY with the actual one from <a target="_blank" href="https://account.dataflowkit.com/settings">https://account.dataflowkit.com/settings</a> . You can obtain it for free after registration at https://dataflowkit.com</li>
<li>Run the following command in the terminal to build a docker image.<pre><code>docker build -t dfk-api-php .
</code></pre></li>
<li>Run a command in a new container<pre><code>docker run -it --rm --name dfk-api-php dfk-api-php
</code></pre></li>
</ol>
<hr />
<h2 id="heading-github-repository-for-php-code-for-accessing-dataflow-kit-api">Github repository for PHP code for accessing Dataflow Kit API.</h2>
<p>Feel free to fork a Github repository at <a target="_blank" href="https://github.com/slotix/dfk-api-php">https://github.com/slotix/dfk-api-php</a> and customize the code for your needs.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Web scraping of plain HTML web pages generated by a server is simple. You can use "PHP Requests" library to get HTML content.</p>
<p>When scraping large amounts from dynamically generated Javascript  data, you might run into the following problems:</p>
<ul>
<li>You need to run multiple instances of the headless Chrome browser to handle large amounts of input.</li>
<li>You have to send requests through a pool of proxies to avoid blocking.</li>
</ul>
<p>In the same way, you can create PHP scripts to <a target="_blank" href="https://dataflowkit.com/url-to-pdf">save web pages as PDF</a> or <a target="_blank" href="https://dataflowkit.com/url-to-screenshot">take screenshots</a>.</p>
<p>The next step obviously after scraping a webpage is to extract specific data from rendered HTML. Depending on a website, it may be a separate HTML element like an <em>image, text, link</em>. Or for example, e-commerce sites list several products on a page as <em>blocks of data</em> grouped by some patterns.</p>
<p>You can use other PHP code generators available on dedicated pages to build PHP scripts to make requests for <a target="_blank" href="https://dataflowkit.com/webscraping-hub">scraping various web sites</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Scrape Google Maps: Extract business leads, phone numbers, addresses.]]></title><description><![CDATA[title: Scrape Google Maps: Extract business leads, phone numbers, addresses.
published: true
date: 2020-08-17 12:16:10 UTC
tags: googlemaps,googlemapsscraping
canonical_url: https://dataflowkit.com/blog/scrape-google-maps-extract-business-leads-phone...]]></description><link>https://dbconvert.hashnode.dev/scrape-google-maps-extract-business-leads-phone-numbers-addresses</link><guid isPermaLink="true">https://dbconvert.hashnode.dev/scrape-google-maps-extract-business-leads-phone-numbers-addresses</guid><dc:creator><![CDATA[Dmitry Narizhnykh]]></dc:creator><pubDate>Mon, 17 Aug 2020 12:16:10 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>title: Scrape Google Maps: Extract business leads, phone numbers, addresses.
published: true
date: 2020-08-17 12:16:10 UTC
tags: googlemaps,googlemapsscraping</p>
<h2 id="heading-canonicalurl-httpsdataflowkitcomblogscrape-google-maps-extract-business-leads-phone-numbers-addresses">canonical_url: https://dataflowkit.com/blog/scrape-google-maps-extract-business-leads-phone-numbers-addresses/</h2>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747056770514/08cf79bd-2da1-497c-8c75-b1003feec4dc.png" alt="Scrape Google Maps: Extract business leads, phone numbers, addresses." /></p>
<p>A lot of places on the Internet contain many lead generation sources that you can use to market your product or service. Google Maps is probably one of the best to get information about local businesses because of almost all companies presented in Google Maps.</p>
<p>It would take you a lot of time to manually copy and paste data from Google Maps. We offer a better way to scrape Google maps data to CSV, Excel, or JSON data.</p>
<p>If you're not a coder, it is enough to enter a search query and customize several parameters before launching Google Maps Scraper and getting desired data.</p>
<p>Or you can generate a "ready-to-run" code for your preferred language to send requests to Google scraper API.</p>
<blockquote>
<p><strong>Extract 100% Relevant B2B Leads Data Using Google Maps Extractor to Increase Your Sales Revenue</strong>.</p>
</blockquote>
<p>Google maps scraping service from Dataflow Kit automates data extraction of the following fields:</p>
<ol>
<li>Business Name</li>
<li>Address</li>
<li>Phone Number</li>
<li>Website</li>
<li>Rating</li>
<li>Reviews</li>
</ol>
<p>Please check out <a target="_blank" href="https://dataflowkit.com/scrape-google-maps">Google maps scraper</a>.</p>
]]></content:encoded></item></channel></rss>