Files
nexus/sreweekly/articles/470/08-avoid-cross-shard-data-movement-in-distributed-databases.html
2026-09-12 17:23:01 +08:00

3483 lines
156 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="In this article, learn four effective strategies to optimize distributed joins, reduce network overhead, and improve query performance in sharded databases.">
<meta name="keywords" content="Database, shard, data type">
<meta property="og:description" content="In this article, learn four effective strategies to optimize distributed joins, reduce network overhead, and improve query performance in sharded databases.">
<meta property="og:site_name" content="dzone.com">
<meta property="og:title" content="Avoid Cross-Shard Data Movement in Distributed Databases">
<meta property="og:url" content="https://dzone.com/articles/avoid-cross-shard-data-movement">
<meta property="og:image" content="https://dz2cdn1.dzone.com/storage/article-thumb/18305475-thumb.jpg">
<meta property="og:type" content="article">
<meta name="twitter:site" content="@DZoneInc">
<meta name="twitter:image" content="https://dz2cdn1.dzone.com/storage/article-thumb/18305475-thumb.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:description" content="In this article, learn four effective strategies to optimize distributed joins, reduce network overhead, and improve query performance in sharded databases.">
<meta name="twitter:title" content="Avoid Cross-Shard Data Movement in Distributed Databases">
<meta name="referrer" content="origin-when-cross-origin">
<meta name="google-site-verification" content="kndbhxcupfEqWmZclhCpB6vlgOs7QSmx2UHAGGnP2mA">
<meta name="df-verify" content="df0d76632b4543">
<link rel="icon" type="image/x-icon" href="https://dz2cdn1.dzone.com/themes/dz20/images/favicon.png">
<link rel="image_src" href="https://dz2cdn1.dzone.com/storage/article-thumb/18305475-thumb.jpg">
<link rel="canonical" href="https://dzone.com/articles/avoid-cross-shard-data-movement">
<title>Avoid Cross-Shard Data Movement in Distributed Databases</title>
<link rel="preload" href="https://dz2cdn1.dzone.com/themes/dz20/font/fontello.woff?11773374" as="font" type="font/woff" crossorigin="anonymous">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/icons.css">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/lib/static/bootstrap/bootstrap.min.css">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/article/global.css">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/header-updated/styles.css">
<style>
:root {
--xs-size: 2px;
--sm-size: 5px;
--md-size: 10px;
--lg-size: 15px;
--xl-size: 25px;
--sm-border-size: 8px;
--sm-font-size: 13px;
--sm-plus-font-size: 16px;
--md-font-size: 18px;
--lg-font-size: 22px;
--xl-font-size: 26px;
}
/* Display Quick-Access Classes */
.display-none { display: none; }
.display-block { display: block; }
.display-inline { display: inline; }
.display-inline-block { display: inline-block; }
/* Margin Quick-Access Classes */
.m-xs { margin: var(--xs-size); }
.m-sm { margin: var(--sm-size); }
.m-md { margin: var(--md-size); }
.m-lg { margin: var(--lg-size); }
.m-xl { margin: var(--xl-size); }
.mt-xs, .my-xs { margin-top: var(--xs-size); }
.mr-xs, .mx-xs { margin-right: var(--xs-size); }
.mb-xs, .my-xs { margin-bottom: var(--xs-size); }
.ml-xs, .mx-xs { margin-left: var(--xs-size); }
.mt-sm, .my-sm { margin-top: var(--sm-size); }
.mr-sm, .mx-sm { margin-right: var(--sm-size); }
.mb-sm, .my-sm { margin-bottom: var(--sm-size); }
.ml-sm, .mx-sm { margin-left: var(--sm-size); }
.mt-md, .my-md { margin-top: var(--md-size); }
.mr-md, .mx-md { margin-right: var(--md-size); }
.mb-md, .my-md { margin-bottom: var(--md-size); }
.ml-md, .mx-md { margin-left: var(--md-size); }
.mt-lg, .my-lg { margin-top: var(--lg-size); }
.mr-lg, .mx-lg { margin-right: var(--lg-size); }
.mb-lg, .my-lg { margin-bottom: var(--lg-size); }
.ml-lg, .mx-lg { margin-left: var(--lg-size); }
.mt-xl, .my-xl { margin-top: var(--xl-size); }
.mr-xl, .mx-xl { margin-right: var(--xl-size); }
.mb-xl, .my-xl { margin-bottom: var(--xl-size); }
.ml-xl, .mx-xl { margin-left: var(--xl-size); }
.ml-auto, .mx-auto { margin-left: auto; }
.mr-auto, .mx-auto { margin-right: auto; }
.mt-auto, .my-auto { margin-top: auto; }
.mb-auto, .my-auto { margin-bottom: auto; }
.my-none, .mt-none { margin-top: 0 !important; }
.mx-none, .mr-none { margin-right: 0 !important; }
.my-none, .mb-none { margin-bottom: 0 !important; }
.mx-none, .ml-none { margin-left: 0 !important; }
/* Padding Quick-Access Classes */
.p-xs { padding: var(--xs-size); }
.p-sm { padding: var(--sm-size); }
.p-md { padding: var(--md-size); }
.p-lg { padding: var(--lg-size); }
.p-xl { padding: var(--xl-size); }
.pt-xs, .py-xs { padding-top: var(--xs-size); }
.pr-xs, .px-xs { padding-right: var(--xs-size); }
.pb-xs, .py-xs { padding-bottom: var(--xs-size); }
.pl-xs, .px-xs { padding-left: var(--xs-size); }
.pt-sm, .py-sm { padding-top: var(--sm-size); }
.pr-sm, .px-sm { padding-right: var(--sm-size); }
.pb-sm, .py-sm { padding-bottom: var(--sm-size); }
.pl-sm, .px-sm { padding-left: var(--sm-size); }
.pt-md, .py-md { padding-top: var(--md-size); }
.pr-md, .px-md { padding-right: var(--md-size); }
.pb-md, .py-md { padding-bottom: var(--md-size); }
.pl-md, .px-md { padding-left: var(--md-size); }
.pt-lg, .py-lg { padding-top: var(--lg-size); }
.pr-lg, .px-lg { padding-right: var(--lg-size); }
.pb-lg, .py-lg { padding-bottom: var(--lg-size); }
.pl-lg, .px-lg { padding-left: var(--lg-size); }
.pt-xl, .py-xl { padding-top: var(--xl-size); }
.pr-xl, .px-xl { padding-right: var(--xl-size); }
.pb-xl, .py-xl { padding-bottom: var(--xl-size); }
.pl-xl, .px-xl { padding-left: var(--xl-size); }
.py-none, .pt-none { padding-top: 0 !important; }
.px-none, .pr-none { padding-right: 0 !important; }
.py-none, .pb-none { padding-bottom: 0 !important; }
.px-none, .pl-none { padding-left: 0 !important; }
/* Flex Quick-Access Classes */
.flex {
display: flex;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-column-reverse {
display: flex;
flex-direction: column-reverse;
}
.flex-row {
display: flex;
flex-direction: row;
}
.flex-row-reverse {
display: flex;
flex-direction: row-reverse;
}
.flex-wrap {
flex-wrap: wrap;
}
.flex-grow {
flex-grow: 1;
}
.align-center { align-items: center; }
.align-end { align-items: flex-end; }
.content-center {
align-content: center;
}
.justify-center { justify-content: center; }
.justify-start { justify-content: flex-start; }
.justify-end { justify-content: flex-end; }
.justify-around { justify-content: space-around; }
.justify-between { justify-content: space-between; }
.justify-evenly { justify-content: space-evenly; }
.gap-sm { gap: var(--sm-size); }
.gap-md { gap: var(--md-size); }
.gap-lg { gap: var(--lg-size); }
.gap-xl { gap: var(--xl-size); }
/* Display Quick-Access Classes */
.inline-block { display: inline-block; }
/* Font Quick-Access Classes */
.font-xl { font-size: var(--xl-font-size); }
.font-lg { font-size: var(--lg-font-size); }
.font-md { font-size: var(--md-font-size); }
.font-sm-plus { font-size: var(--sm-plus-font-size); }
.font-sm { font-size: var(--sm-font-size); }
.font-strike { text-decoration: line-through; }
.font-underline { text-decoration: underline; }
.font-overline { text-decoration: overline; }
.font-italic { font-style: italic; }
.font-bold { font-weight: bold; }
.font-black { color: #000000; }
.font-white { color: #ffffff; }
.font-gray { color: var(--brand-gray-text); }
.font-danger { color: var(--header-dropdown-button-bg-danger); }
.font-center { text-align: center; }
.no-wrap { white-space: nowrap; }
/* Consistent headings between h and non-h tags */
.heading {
margin-top: 0;
margin-bottom: var(--md-size);
}
.heading.font-xl { line-height: var(--xl-font-size); }
.heading.font-lg { line-height: var(--lg-font-size); }
.heading.font-md { line-height: var(--md-font-size); }
.heading.font-sm-plus { line-height: var(--sm-plus-font-size); }
.heading.font-sm { line-height: var(--sm-font-size); }
/* Font Clamp Quick-Access Classes */
.line-clamp,
.line-clamp-2,
.line-clamp-3,
.line-clamp-4,
.line-clamp-5 {
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.line-clamp-2 { -webkit-line-clamp: 2 !important; }
.line-clamp-3 { -webkit-line-clamp: 3 !important; }
.line-clamp-4 { -webkit-line-clamp: 4 !important; }
.line-clamp-5 { -webkit-line-clamp: 5 !important; }
/* User-Select Quick-Access Classes */
.select-none { user-select: none; }
/* Position Quick-Access Classes */
.absolute { position: absolute; }
.relative { position: relative; }
.float-left { float: left; }
.float-right { float: right; }
.pos-top { top: 0; }
.pos-right { right: 0; }
.pos-bottom { bottom: 0; }
.pos-left { left: 0; }
.va-top { vertical-align: top; }
.va-middle { vertical-align: middle; }
.va-bottom { vertical-align: bottom; }
/* Transition Quick-Access Classes */
.trans-linear-quick {
transition: all 0.15s linear;
}
/* Background Quick-Access Classes */
.bg-gray { background: #cccccc; }
.bg-white { background-color: white; }
.bg-none { background: none; }
/* Border Quick-Access Classes */
.border-gray { border: 1px solid #cccccc; }
.tab-pane.border-gray { border: 1px solid #ddd; }
.no-border, .border-none { border: none !important; }
.bt-none { border-top: none !important; }
.br-none { border-right: none !important; }
.bb-none { border-bottom: none !important; }
.bl-none { border-left: none !important; }
/* Border Radius Quick-Access Classes */
.round-t-sm, .round-tl-sm { border-top-left-radius: var(--sm-border-size); }
.round-t-sm, .round-tr-sm { border-top-right-radius: var(--sm-border-size); }
.round-b-sm, .round-bl-sm { border-bottom-left-radius: var(--sm-border-size); }
.round-b-sm, .round-br-sm { border-bottom-right-radius: var(--sm-border-size); }
.round-sm { border-radius: var(--sm-border-size); }
.round-fully { border-radius: 50%; }
/* Misc Quick-Access Classes */
.haikei {
position: relative;
background-image: url('https://dz2cdn1.dzone.com/themes/dz20/images/polygon-scatter-haikei-shapes.svg');
background-repeat: no-repeat;
background-size: cover;
}
.haikei:before {
content: '';
position:absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: var(--color-event-background);
z-index: -1;
}
.margin-auto-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.flex-auto-center {
display: flex;
margin-left: auto;
margin-right: auto;
}
.mw-1100 { max-width: 1100px; }
.mw-1300 { max-width: 1300px; }
.full-width { width: 100%; }
.h-separator {
background-color: #cccccc;
height: 1px;
width: 100%;
margin: 5px auto;
}
.no-spacing {
margin: 0 !important;
padding: 0 !important;
}
.inherit-color { color: inherit; }
.inherit-decoration { text-decoration: inherit; }
/* Table Quick-Access Classes */
.table-border-gray tr:not(:last-child) {
border-bottom: 1px solid #cccccc;
}
table.full-width tr td:last-child {
width:100%;
}
/* Animation Quick-Access Classes */
@keyframes anim-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(359deg); }
}
.anim-spin {
display: inline-block;
animation: anim-spin 2s infinite linear;
}
.hov-pointer { cursor: pointer; }
.hov-brighten:hover { filter: brightness(1.2); }
.hov-darken:hover { filter: brightness(0.95); }
.hov-underline:hover { text-decoration: underline; }
/* Small tweaks related to components when using these styles */
.nav-tabs {
border-bottom: none;
}
.tab-content > .flex-column.active,
.tab-content > .flex-row.active {
display: flex;
}
/* Alpine components with x-cloak should not be visible by default until conditionals kick in */
[x-cloak] { display: none !important; }
</style>
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/alpine-components/modal.css">
<script defer src="https://dz2cdn1.dzone.com/themes/dz20/lib/alpinejs/3.13.2/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('article', {
id: null,
engagement: {
open: false,
page: 1,
users: [],
additional: true,
loading: false,
initializing: false,
unauthorized: false,
enqueued: null,
dequeued: null,
reset() {
this.open = false;
this.page = 1;
this.users.splice(0);
this.additional = true;
this.loading = false;
this.initializing = false;
this.enqueued = null;
this.dequeued = null;
},
enqueue(user) {
this.dequeued = null;
this.enqueued = user;
},
dequeue(user) {
this.enqueued = null;
this.dequeued = user;
},
add(user) {
this.users.push(user);
this.enqueued = null;
},
remove(user) {
const index = this.users.findIndex(u => u.id === user.id);
if (index !== -1) {
this.users.splice(index, 1);
}
this.dequeued = null;
},
contains(user) {
return this.users.filter(u => u.id === user.id).length;
}
}
});
Alpine.effect(() => {
const store = Alpine.store('article');
if (!store.engagement.additional && store.engagement.enqueued) {
if (!store.engagement.contains(store.engagement.enqueued)) {
store.engagement.add(store.engagement.enqueued);
}
}
});
Alpine.effect(() => {
const store = Alpine.store('article');
if (store.engagement.page && store.engagement.dequeued) {
store.engagement.remove(store.engagement.dequeued);
}
})
});
</script></head>
<body x-data>
<div class="skybox skybox-closeBtn dz_skybox" data-gpt-slot="skybox" id="div-gpt-ad-1435246566686-99"></div>
<header id="ftl-header">
<div class="header-top">
<div class="header-container">
<div class="pull-left logo-container">
<div class="logo">
<a class="inner" href="/">
<picture>
<source srcset="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.webp" type="image/webp">
<source srcset="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.png" type="image/png">
<img src="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.png" width="181" height="56" alt="DZone">
</picture>
</a>
</div>
</div>
<div class="pull-right login-and-search">
<div id="authenticated-block" class="logged-in">
<div class="welcome-back">Thanks for visiting DZone today,</div>
<div id="user-header" class="user-info">
<button class="user-avatar">
<span id="header-username" class="username"></span>
<img id="header-avatar" src="" alt="user avatar">
</button>
<div id="user-dropdown" class="browse-user-menu">
<div class="user-content">
<a id="header-user-plug" href="#" class="user-description"></a>
<a id="header-user-edit" href="#" class="edit-profile">Edit Profile</a>
</div>
<ul class="user-actions">
<li id="first-user-action">
<a id="header-dropdown-manage-email" href="#">Manage Email Subscriptions</a>
</li>
<li>
<a href="/articles/how-to-submit-a-post-to-dzone?utm_source=DZone&utm_medium=user_dropdown&utm_campaign=how_to_post">
How to Post to DZone
</a>
</li>
<li>
<a href="/articles/dzones-article-submission-guidelines">
Article Submission Guidelines
</a>
</li>
</ul>
<div class="bottom">
<a href="/users/logout.html" class="sign-out">Sign Out</a>
<a id="dropdown-view-profile" href="#" class="view-profile">View Profile</a>
</div>
</div>
</div>
<div class="post-content">
<button id="post-button" class="post-content--button">
<span class="post-class">Post</span>
<i class="icon-plus"></i>
</button>
<div id="post-menu" class="posting-links">
<div class="posting-links-menu">
<ul>
<li>
<img src="https://dz2cdn1.dzone.com/themes/dz20/images/dz-postarticle.svg" width="15" height="18" style="width: 15px; height: 18px;">
<a href="/content/article/post.html">Post an Article</a>
</li>
<li>
<a id="drafts-link" href="#">Manage My Drafts</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="unauthenticated-block">
<div class="dz-intro">Over 2 million developers have joined DZone.</div>
<div class="mobile-invisible sign-in-join">
<a href="/users/login.html">Log In</a>
<span class="dz-intro-span">/</span>
<a href="/static/registration.html">Join</a>
</div>
<a class="join-icon" href="/users/login.html" aria-label="User">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide svg-user lucide-user-icon lucide-user">
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
</a>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('searchDrawer', () => ({
open: false,
query: '',
minCharsMet: false,
toggleVisibility() {
this.open = !this.open;
if (this.open) {
this.$nextTick(() => {
this.$refs.query.focus();
});
}
},
updateSearchValue() {
if (!this.query || !this.query.length || this.query.length < 3) {
this.minCharsMet = false;
return;
}
this.minCharsMet = true;
localStorage.setItem('ls.searchValue', this.query);
},
searchSite() {
if (this.minCharsMet) {
window.location = '/search';
}
}
}));
});
</script>
<div class="headerSearch" x-data="searchDrawer()" x-cloak>
<button class="btn-search dropdown-toggle" x-on:click="toggleVisibility()" aria-label="Search">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide svg-search lucide-search-icon lucide-search">
<path d="m21 21-4.34-4.34"></path>
<circle cx="11" cy="11" r="8"></circle>
</svg>
</button>
<template x-teleport=".header-container">
<div id="search-drawer" x-show="open" x-on:click.outside="open = false" x-transition>
<div class="search-input">
<input type="text"
placeholder="Search"
autofocus="autofocus"
x-model="query"
x-ref="query"
x-on:input.change="updateSearchValue()"
x-on:keyup.enter="searchSite()"
>
<button x-on:click="searchSite()" x-bind:disabled="!minCharsMet">
<span>Search</span>
</button>
</div>
<div class="search-footer">
Please enter at least three characters to search
</div>
</div>
</template>
</div>
</div>
</div> </div>
<div class="header-bottom">
<div class="header-bottom-container">
<a class="resource-link" href="/refcardz">Refcards</a>
<a class="resource-link" href="/trendreports">Trend Reports</a>
<div class="resource-link link-menu">
<a href="/events">Events</a>
<a href="/events/video-library">Video Library</a>
</div>
</div>
</div>
<nav class="header-menu-bar">
<div class="header-menu resource-category">
<a href="/refcardz">Refcards</a>
</div>
<div class="header-menu-separator resource-category-separator"></div>
<div class="header-menu resource-category">
<a href="/trendreports">Trend Reports</a>
</div>
<div class="header-menu-separator resource-category-separator"></div>
<div class="header-menu resource-category no-bottom-radius" data-click-activation>
<p class="menu-label">Events</p>
<div class="header-menu-items">
<div class="header-menu-columns">
<a class="header-menu-item" href="/events">View Events</a>
<a class="header-menu-item" href="/events/video-library">Video Library</a>
</div>
</div>
</div>
<div class="header-menu zone-menu" data-click-activation>
<p class="menu-label">Zones <i class="icon-down-dir icon-closed"></i><i class="icon-right-dir icon-open"></i></p>
<div class="header-menu-items">
<div class="header-menu-columns">
<div class="header-menu-column-item">
<a class="header-menu-item" href="/culture-and-methodologies">Culture and Methodologies</a>
<a class="header-menu-item" href="/agile">Agile</a>
<a class="header-menu-item" href="/career-development">Career Development</a>
<a class="header-menu-item" href="/methodologies">Methodologies</a>
<a class="header-menu-item" href="/team-management">Team Management</a>
</div>
<div class="header-menu-column-item">
<a class="header-menu-item" href="/data-engineering">Data Engineering</a>
<a class="header-menu-item" href="/ai-ml">AI/ML</a>
<a class="header-menu-item" href="/big-data">Big Data</a>
<a class="header-menu-item" href="/data">Data</a>
<a class="header-menu-item" href="/databases">Databases</a>
<a class="header-menu-item" href="/iot">IoT</a>
</div>
<div class="header-menu-column-item">
<a class="header-menu-item" href="/software-design-and-architecture">Software Design and Architecture</a>
<a class="header-menu-item" href="/cloud-architecture">Cloud Architecture</a>
<a class="header-menu-item" href="/containers">Containers</a>
<a class="header-menu-item" href="/integration">Integration</a>
<a class="header-menu-item" href="/microservices">Microservices</a>
<a class="header-menu-item" href="/performance">Performance</a>
<a class="header-menu-item" href="/security">Security</a>
</div>
<div class="header-menu-column-item">
<a class="header-menu-item" href="/coding">Coding</a>
<a class="header-menu-item" href="/frameworks">Frameworks</a>
<a class="header-menu-item" href="/java">Java</a>
<a class="header-menu-item" href="/javascript">JavaScript</a>
<a class="header-menu-item" href="/languages">Languages</a>
<a class="header-menu-item" href="/tools">Tools</a>
</div>
<div class="header-menu-column-item">
<a class="header-menu-item" href="/testing-deployment-and-maintenance">Testing, Deployment, and Maintenance</a>
<a class="header-menu-item" href="/deployment">Deployment</a>
<a class="header-menu-item" href="/devops-and-cicd">DevOps and CI/CD</a>
<a class="header-menu-item" href="/maintenance">Maintenance</a>
<a class="header-menu-item" href="/monitoring-and-observability">Monitoring and Observability</a>
<a class="header-menu-item" href="/testing-tools-and-frameworks">Testing, Tools, and Frameworks</a>
</div>
<div class="header-menu-column-item sponsored">
<a class="header-menu-item" href="javascript:void(0)">Partner Zones</a>
<a class="header-menu-item" href="/hubs/build-ai-agents-that-are-ready-for-production/">Build AI Agents That Are Ready for Production</a>
</div>
</div>
</div>
</div>
<div class="header-menu parent-category" tabindex="1">
<a href="/culture-and-methodologies">Culture and Methodologies</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/agile">Agile</a>
<a class="header-menu-item" href="/career-development">Career Development</a>
<a class="header-menu-item" href="/methodologies">Methodologies</a>
<a class="header-menu-item" href="/team-management">Team Management</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category" tabindex="2">
<a href="/data-engineering">Data Engineering</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/ai-ml">AI/ML</a>
<a class="header-menu-item" href="/big-data">Big Data</a>
<a class="header-menu-item" href="/data">Data</a>
<a class="header-menu-item" href="/databases">Databases</a>
<a class="header-menu-item" href="/iot">IoT</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category" tabindex="3">
<a href="/software-design-and-architecture">Software Design and Architecture</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/cloud-architecture">Cloud Architecture</a>
<a class="header-menu-item" href="/containers">Containers</a>
<a class="header-menu-item" href="/integration">Integration</a>
<a class="header-menu-item" href="/microservices">Microservices</a>
<a class="header-menu-item" href="/performance">Performance</a>
<a class="header-menu-item" href="/security">Security</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category" tabindex="4">
<a href="/coding">Coding</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/frameworks">Frameworks</a>
<a class="header-menu-item" href="/java">Java</a>
<a class="header-menu-item" href="/javascript">JavaScript</a>
<a class="header-menu-item" href="/languages">Languages</a>
<a class="header-menu-item" href="/tools">Tools</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category" tabindex="5">
<a href="/testing-deployment-and-maintenance">Testing, Deployment, and Maintenance</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/deployment">Deployment</a>
<a class="header-menu-item" href="/devops-and-cicd">DevOps and CI/CD</a>
<a class="header-menu-item" href="/maintenance">Maintenance</a>
<a class="header-menu-item" href="/monitoring-and-observability">Monitoring and Observability</a>
<a class="header-menu-item" href="/testing-tools-and-frameworks">Testing, Tools, and Frameworks</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category sponsored" tabindex="6">
<a href="javascript:void(0)">Partner Zones</a>
<div class="header-menu-items sponsored">
<a class="header-menu-item" href="/hubs/build-ai-agents-that-are-ready-for-production/">Build AI Agents That Are Ready for Production</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
</nav>
</header>
<script>
const csrf = {
parameter: 'TH_CSRF',
header: 'X-TH-CSRF',
token: '-6013068958275038528'
}; // set csrf for auth-status script
</script>
<script>
addEventListener('DOMContentLoaded', function() {
handleRedirects();
handleMenus();
handleMobileMenuHeights();
handleGotoLinks();
});
function isHidden(element) {
try {
return window.getComputedStyle(element).display === 'none';
} catch (_) {
return false;
}
}
function getLink(element) {
if (element.hasAttribute('data-goto')) {
return element.getAttribute('data-goto');
}
return element.href;
}
function isLeftClick(event) {
if (event.altKey || event.shiftKey) {
return false;
} else if ('buttons' in event || 'which' in event) {
return event.buttons === 1 || event.which === 1;
} else {
return (event.button === 1 || (event.type === 'click'));
}
}
function handleRedirects() {
const redirections = [...document.querySelectorAll('[data-activate-menu]'), ...document.querySelectorAll('[data-click-target]')];
redirections.forEach(function(element) {
const menuSelector = element.getAttribute('data-activate-menu') || element.getAttribute('data-click-target');
const redirectingElement = document.querySelector(menuSelector);
if (redirectingElement) {
element.style.cursor = 'pointer';
const redirect = function(e) {
if (redirectingElement.hasAttribute('href') || redirectingElement.hasAttribute('data-goto')) {
if (redirectingElement.hasAttribute('data-new-window') || e.ctrlKey || e.metaKey) {
window.open(getLink(redirectingElement), '_blank');
} else {
window.open(getLink(redirectingElement), '_self');
}
} else {
const evt = new e.constructor(e.type, e);
redirectingElement.dispatchEvent(evt);
}
};
element.addEventListener('mouseup', redirect);
element.addEventListener('mousedown', (e) => e.preventDefault());
element.addEventListener('click', (e) => e.preventDefault());
}
});
}
function handleMenus() {
const menuElements = [
...document.querySelectorAll('.header-menu > a'),
...document.querySelectorAll('.header-menu > p.menu-label')
];
let scrollYMemory = -1;
function scrollToMemory() {
if (scrollYMemory !== -1) {
setTimeout(function() {
window.scrollTo(0, scrollYMemory);
scrollYMemory = -1;
}, 10);
}
}
function hideMenus() {
// unfocus menus & items, and set the menus to non-visible.
menuElements.forEach(function (element) {
element.blur();
element.parentElement.blur();
element.parentElement.classList.remove('menu-opened');
const menuItems = element.parentElement.querySelector('.header-menu-items');
if (menuItems) {
menuItems.style.display = 'none';
}
});
const wasHidden = document.body.style.overflowY === 'hidden';
document.body.style.overflowY = 'auto';
if (wasHidden) {
scrollToMemory();
}
}
function isEventOutsideMenu(e) {
return e.target.closest && !e.target.closest('.header-menu') && !e.target.closest('[data-activate-menu]');
}
// Handle mobile menu toggling
menuElements.forEach(function(element) {
const menu = element.parentElement;
const headerItems = menu.querySelector('.header-menu-items');
const menuEntries = headerItems ? headerItems.querySelectorAll('.header-menu-item') : [];
const focus = function() {
menu.focus();
menu.classList.add('menu-opened');
if (headerItems) {
headerItems.style.display = 'block';
}
if (menu.classList.contains('zone-menu')) {
scrollYMemory = window.scrollY;
document.body.style.overflowY = 'hidden';
} else {
scrollYMemory = -1;
}
};
const unfocus = function() {
menu.blur();
menu.classList.remove('menu-opened');
if (headerItems) {
headerItems.style.display = 'none';
}
const wasHidden = document.body.style.overflowY === 'hidden';
document.body.style.overflowY = 'auto';
if (wasHidden) {
scrollToMemory();
}
};
const toggleMenuVisibility = function(e) {
if ((e.type === 'click' || e.type === 'mouseup') && !isLeftClick(e)) {
e.preventDefault();
return;
}
const hidden = isHidden(headerItems);
if (menu.hasAttribute('data-click-activation')) { // handle click activated toggling
if (hidden) {
hideMenus(); // hide other open menus first
focus();
} else {
unfocus();
}
e.preventDefault();
} else if (hidden) {
hideMenus(); // hide other open menus first
focus();
e.preventDefault(); // prevent 'click' event from firing when menu is hidden
}
};
element.addEventListener('touchend', toggleMenuVisibility);
element.addEventListener('mouseup', toggleMenuVisibility);
// Add hover events to non-click-activated menus, even though CSS should cover it.
if (!menu.hasAttribute('data-click-activation')) {
menu.addEventListener('mouseover', function () {
hideMenus(); // hide other open menus first
focus();
});
menu.addEventListener('mouseout', function (e) {
if (isEventOutsideMenu(e)) {
unfocus();
}
});
}
// Hide menu when child is clicked
menuEntries.forEach(function(menuEntry) {
const linkToItem = function(e) {
if (e.type === 'mousedown' || e.type === 'click') {
e.preventDefault();
return;
}
if (e.type === 'mouseup' && !isLeftClick(e)) {
e.preventDefault();
return;
}
window.open(getLink(menuEntry), (e.ctrlKey || e.metaKey) ? '_blank' : (menuEntry.target || '_self'));
unfocus();
e.preventDefault();
};
const linkToMobileItem = function(e) {
if (e.type === 'touchstart') {
menuEntry.setAttribute('data-touchmove', false);
} else if (e.type === 'touchmove') {
menuEntry.setAttribute('data-touchmove', true);
} else if (e.type === 'touchend' && (!menuEntry.hasAttribute('data-touchmove') || menuEntry.getAttribute('data-touchmove').toLowerCase() === 'false')) {
window.open(getLink(menuEntry), (e.ctrlKey || e.metaKey) ? '_blank' : (menuEntry.target || '_self'));
unfocus();
e.preventDefault();
}
};
menuEntry.addEventListener('mousedown', linkToItem);
menuEntry.addEventListener('mouseup', linkToItem);
menuEntry.addEventListener('click', linkToItem);
menuEntry.addEventListener('touchstart', linkToMobileItem);
menuEntry.addEventListener('touchmove', linkToMobileItem);
menuEntry.addEventListener('touchend', linkToMobileItem);
});
});
function hideIfNonMenuBounds(e) {
if (isEventOutsideMenu(e)) {
hideMenus();
}
}
addEventListener('mousemove', hideIfNonMenuBounds);
addEventListener('touchend', hideIfNonMenuBounds);
addEventListener('mouseup', hideIfNonMenuBounds);
addEventListener('mousedown', hideIfNonMenuBounds);
addEventListener('click', hideIfNonMenuBounds);
}
function handleMobileMenuHeights() {
function setAppHeight() {
document.documentElement.style.setProperty('--app-height', window.innerHeight + 'px');
}
addEventListener('resize', function() {
setAppHeight();
});
setAppHeight();
}
function handleGotoLinks() {
// Add anchor mimicking to elements with data-goto attributes
// This addresses SEO concerns of linking to noindex pages by allowing JS to handle the URL
const anchorElements = document.querySelectorAll('*[data-goto]');
anchorElements.forEach((anchorElement) => {
anchorElement.addEventListener('mouseover', () => {
anchorElement.style.cursor = 'pointer';
anchorElement.style.textDecoration = 'underline';
});
anchorElement.addEventListener('mouseout', () => {
anchorElement.style.cursor = 'unset';
anchorElement.style.textDecoration = 'unset';
});
anchorElement.addEventListener('mouseup', (e) => {
e.preventDefault();
});
anchorElement.addEventListener('mousedown', (e) => {
e.preventDefault();
});
anchorElement.addEventListener('click', (e) => {
e.preventDefault();
const anchorHref = anchorElement.getAttribute('data-goto');
if (anchorElement.hasAttribute('data-new-window') || e.ctrlKey || e.metaKey) {
window.open(anchorHref, '_blank');
} else {
window.open(anchorHref, '_self');
}
});
});
}
</script><script>
const authenticatedBlock = document.querySelector('#authenticated-block');
const unauthenticatedBlock = document.querySelector('#unauthenticated-block');
let authenticated = {
isAuthenticated: false,
isAdmin: false,
user: {
id: null,
name: null,
url: null,
profileImage: null,
}
};
fetch('/services/internal/data/articles-getAuthenticationStatus', {
headers: {
'Accept': 'application/json'
}
})
.then(function (result) {
return result.json()
})
.then(function (result) {
const res = result.result.data
if (!res.authenticated) {
unauthenticatedBlock.classList.add('shown')
} else {
authenticated.user.id = res.id;
authenticated.user.name = res.realName;
authenticated.user.url = res.profileUrl;
authenticated.user.profileImage = res.avatar;
authenticated.user.jobTitle = res.jobTitle;
authenticated.user.companyName = res.companyName;
bindProps('#header-username', null, null, (res.firstName || res.username), null)
bindProps('#header-avatar', null, res.avatar, null, null)
bindProps('#header-user-plug', res.profileUrl, null, res.realName, null)
bindProps('#header-user-edit', '/users/' + res.id + '/edit.html', null, null, null)
bindProps('#header-dropdown-manage-email', '/newsletters/' + res.id + '/manage.html', null, null, null)
bindProps('#dropdown-view-profile', res.profileUrl, null, null, null)
bindProps('#drafts-link', '/users/' + res.id + '/drafts.html', null, null, null)
if (res.isAdmin) {
// Construct backwards so the #after call places elements in the correct order
const firstUserAction = document.querySelector('#first-user-action')
const adminConsoleItem = document.createElement('li')
const adminConsoleLink = createLink('/dzone/staff/index.html', 'Admin Console')
adminConsoleItem.appendChild(adminConsoleLink)
firstUserAction.after(adminConsoleItem)
const moderationItem = document.createElement('li')
const moderationLink = createLink('/moderation/list.html', 'Moderation')
moderationItem.appendChild(moderationLink)
firstUserAction.after(moderationItem)
const bountyModerationItem = document.createElement('li')
const bountyModerationLink = createLink('/moderation/bounties', 'Bounty Moderation')
bountyModerationItem.appendChild(bountyModerationLink)
firstUserAction.after(bountyModerationItem)
}
authenticated.isAuthenticated = res.authenticated;
authenticated.isAdmin = res.isAdmin;
authenticatedBlock.classList.add('shown')
}
}).catch(function (result) {
console.error(result)
})
/**
* Binds different properties to the selected element.
*
* @param selector - Selector to select the element
* @param href - href attribute value
* @param src - src attribute value
* @param innerHTML - innerHTML property value
* @param innerText - innerText property value
*/
function bindProps(selector, href, src, innerHTML, innerText) {
const element = document.querySelector(selector)
if (element) {
if (href) element.href = href
if (src) element.src = src
if (innerHTML) element.innerHTML = innerHTML
if (innerText) element.innerText = innerText
}
}
/**
* Creates a new link element.
*
* @param href - href attribute value
* @param innerText - innerText property value
* @returns {HTMLAnchorElement} The generated link element
*/
function createLink(href, innerText) {
const link = document.createElement('a')
link.href = href
link.innerText = innerText
return link
}
</script><script>
const userHeader = document.querySelector('#user-header')
const userDropdown = document.querySelector('#user-dropdown')
const postDropdown = document.querySelector('#post-button')
const postMenu = document.querySelector('#post-menu')
let userDropdownOpen = false
let postDropdownOpen = false
document.addEventListener('click', function(event) {
if (postDropdown && postDropdown.contains(event.target)) {
setUserDropdown(false)
setPostDropdown(!postDropdownOpen)
} else if (userHeader && userHeader.contains(event.target)) {
setPostDropdown(false)
setUserDropdown(!userDropdownOpen)
} else {
setUserDropdown(false)
setPostDropdown(false)
}
})
function setUserDropdown(value) {
userDropdownOpen = value
if (userDropdownOpen) {
if (userDropdown) {
userDropdown.classList.add('open')
}
} else {
if (userDropdown) {
userDropdown.classList.remove('open')
}
}
}
function setPostDropdown(value) {
postDropdownOpen = value
if (postDropdownOpen) {
if (postMenu) {
postMenu.classList.add('open')
}
} else {
if (postMenu) {
postMenu.classList.remove('open')
}
}
}
</script><script>
document.addEventListener("alpine:init", () => {
Alpine.store('global', {
executeHttp(path, body, method) {
const options = {
method: method,
headers: {
[csrf.header]: csrf.token
}
};
if (method !== 'GET') {
options.body = JSON.stringify(body);
options.headers = {
...options.headers,
'Content-Type': 'application/json; charset=UTF-8'
};
}
return new Promise((resolve, reject) => {
fetch(path, options)
.then(res => {
if (!res.ok) {
reject(res);
} else {
resolve(res);
}
})
.catch(err => reject(err));
});
},
getFromService(path) {
return this.executeHttp(path, null, 'GET');
},
postToService(path, body = {}) {
return this.executeHttp(path, body, 'POST');
},
putToService(path, body = {}) {
return this.executeHttp(path, body, 'PUT');
}
});
});
</script>
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/colors.css">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/article/styles.css">
<div id="body-container">
<div id="announcement-container-outer">
<div id="announcement-previous">
<i class="icon-angle-left"></i>
</div>
<div id="announcement-next">
<i class="icon-angle-right"></i>
</div>
<div id="announcement-container">
<div class="announcement announcement-count-1"
data-position="1">
<div class="body"><p><strong>Could your team report a vulnerability within 24 hours? </strong>Find out on September 23.</p></div>
<div class="spacer"></div>
<a href="https://cvent.me/O32zXR?utm_source=Announcements&amp;utm_medium=DzoneWeb&amp;utm_campaign=QtGroup-0923" target="_blank">
<button>Assess Your CRA Readiness</button>
</a>
</div>
</div>
</div>
<script type="text/javascript" async>
(function() {
let announcementPosition = 1;
let minAnnouncementPosition = -1;
let maxAnnouncementPosition = -1;
const announcementPrevBtn = document.querySelector('#announcement-previous');
const announcementNextBtn = document.querySelector('#announcement-next');
function withAnnouncements(callback) {
const announcements = document.querySelectorAll('#announcement-container .announcement');
for (let announcement of announcements) {
callback(announcement);
}
}
function initAnnouncementVars() {
document.querySelector(':root').style.setProperty('--mobile-announcement-separator-width', '1px');
withAnnouncements(function(announcement) {
const pos = parseInt(announcement.getAttribute('data-position'));
minAnnouncementPosition = minAnnouncementPosition === -1 ? pos : Math.min(minAnnouncementPosition, pos);
maxAnnouncementPosition = maxAnnouncementPosition === -1 ? pos : Math.max(maxAnnouncementPosition, pos);
});
if (document.querySelector('.announcementBarContainer')) {
document.querySelector(':root').style.setProperty('--body-top-padding', '0');
}
if (maxAnnouncementPosition <= 0) {
document.querySelector(':root').style.setProperty('--body-top-padding', '0');
}
sizeToFullWhenOneEntryOnMobile();
}
function setAnnouncementPosition(position) {
if (window.outerWidth >= 890) {
return; // we do not need to change the position, since we can display everything on desktop.
}
// Make the announcement cyclical
if (minAnnouncementPosition !== -1 && maxAnnouncementPosition !== -1) {
if (position > maxAnnouncementPosition) {
position = minAnnouncementPosition; // overflow to the first announcement
} else if (position < minAnnouncementPosition) {
position = maxAnnouncementPosition; // underflow to the last announcement
}
announcementPosition = position;
}
const shownAnnouncements = [];
let reverseFlex = false; // should only be true when the first and last items are showing
// Now that the position is valid, apply the transforms
withAnnouncements(function(announcement) {
const pos = parseInt(announcement.getAttribute('data-position'));
const isWrapped = position === maxAnnouncementPosition && pos === minAnnouncementPosition; // showing first + last at same time
const doesNextQualify = window.outerWidth >= 500 && (pos === position + 1 || isWrapped);
if (pos === position || doesNextQualify) {
shownAnnouncements.push(announcement);
} else {
announcement.style.display = 'none';
}
announcement.style.opacity = 0.0;
if (isWrapped) {
reverseFlex = true;
}
});
for (let announcement of shownAnnouncements) {
announcement.style.display = 'flex';
announcement.style.opacity = 1.0;
}
const announcementContainer = document.querySelector('#announcement-container');
if (announcementContainer) {
announcementContainer.style.flexDirection = reverseFlex ? 'row-reverse' : 'row';
}
}
function resetAnnouncements() {
announcementPosition = 1;
const announcementContainer = document.querySelector('#announcement-container');
if (announcementContainer) {
announcementContainer.style.flexDirection = 'row';
}
withAnnouncements(function(announcement) {
announcement.style.opacity = 1.0;
announcement.style.display = 'flex';
});
}
function sizeToFullWhenOneEntryOnMobile() {
if (maxAnnouncementPosition <= 2 && announcementPrevBtn && announcementNextBtn) {
announcementPrevBtn.style.display = maxAnnouncementPosition === 2 && window.outerWidth < 500 ? 'flex' : 'none';
announcementNextBtn.style.display = maxAnnouncementPosition === 2 && window.outerWidth < 500 ? 'flex' : 'none';
}
if (maxAnnouncementPosition === 1 && window.outerWidth >= 500 && window.outerWidth < 890) {
document.querySelector(':root').style.setProperty('--mobile-announcement-separator-width', '0');
document.querySelector('#announcement-container .announcement').style.maxWidth = '100%';
}
}
function resetAnnouncementsOnResize() {
announcementPosition = 1; // we want to reset the announcement position every resize
if (window.outerWidth >= 890) { // 4 announcements can be shown (215px * 4) + separator padding
resetAnnouncements();
} else { // if we're still on mobile, set the position to normalize things after resize
setAnnouncementPosition(announcementPosition);
sizeToFullWhenOneEntryOnMobile();
}
}
window.addEventListener('resize', resetAnnouncementsOnResize);
initAnnouncementVars();
setAnnouncementPosition(announcementPosition); // sets the min & max positions as well as initializes transforms
if (announcementPrevBtn) {
announcementPrevBtn.onclick = function() {
setAnnouncementPosition(announcementPosition - 1);
};
}
if (announcementNextBtn) {
announcementNextBtn.onclick = function() {
setAnnouncementPosition(announcementPosition + 1);
};
}
})(); </script>
<div id="ftl-article" class="trending-article-body">
<aside class="trending-sidebar" aria-labelledby="related-sidebar-heading">
<div class="trending">
<h2 id="related-sidebar-heading">Related</h2>
<div class="trending-separator"></div>
<ul>
<li class="item">
<a href="/articles/mcp-opentelemetry-tracing" class="related-link">Tracing the Agentic Loop: Monitoring Multi-Round-Trip MCP Calls With OpenTelemetry</a>
</li>
<li class="item">
<a href="/articles/retiring-a-tier-0-legacy-database-without-breaking" class="related-link">Retiring a Tier-0 Legacy Database Without Breaking the Business</a>
</li>
<li class="item">
<a href="/articles/aggregate-reference-problem" class="related-link">The Aggregate Reference Problem</a>
</li>
<li class="item">
<a href="/articles/the-serverless-ceiling-designing-write-heavy-backe" class="related-link">The Serverless Ceiling: Designing Write-Heavy Backends With Aurora Limitless</a>
</li>
</ul>
</div>
</aside>
<div class="container-fluid body trending-article-fluid">
<div class="row">
<div class="col-md-12">
<div class="articles-wrap">
<div class="ad-container">
<div id="div-gpt-ad-1435246566686-0" class="ads-billboard-article dz2_article_billboard_new" data-gpt-slot="top"></div>
</div>
<div class="article-stream widget-top-border">
<div class="article-main">
<div class="content-right-images">
<div id="div-gpt-ad-1435246566686-2" class="sidebar-ad dz2_article_halfpage_new" data-gpt-slot="sidebar1"></div>
<div class="trending-separator"></div>
<aside class="trending" aria-labelledby="trending-sidebar-heading">
<h2 id="trending-sidebar-heading">Trending</h2>
<ul>
<li class="item">
<a href="/articles/prevent-duplicate-api-calls" class="trending-link" target="_self">Prevent Duplicate API Calls With Idempotency: Patterns That Work</a>
</li>
<li class="item">
<a href="/articles/understanding-golden-prompts" class="trending-link" target="_self">Golden Prompts: Turning AI Prompting into an Engineering Practice</a>
</li>
<li class="item">
<a href="/articles/oracle-select-ai-vector-search" class="trending-link" target="_self">Select AI and Vector Search on a Legacy Oracle Schema: What It Actually Takes</a>
</li>
<li class="item">
<a href="/articles/goose-agentgateway-security" class="trending-link" target="_self">Part 2: Securing and Scaling Goose-to-Java Agent Traffic With agentgateway</a>
</li>
</ul>
</aside>
</div>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Avoid Cross-Shard Data Movement in Distributed Databases",
"author": [{"image":{"@type":"ImageObject","caption":"Baskar Sikkayan","url":"https://secure.gravatar.com/avatar/80b9c8f75d350cccb189ca77db412590?d=identicon&r=PG"},"@type":"Person","worksFor":{"@type":"Organization","name":"Apple Inc"},"name":"Baskar Sikkayan","url":"https://dzone.com/users/5280786/udayabaski.html"}],
"audience": "software developers",
"keywords": "",
"timeRequired": "PT5M",
"commentCount": 1,
"wordCount": "1248",
"accessMode": "textual, visual",
"datePublished": "2025-03-26T00:00:00Z",
"articleSection": "",
"publisher": {
"@type": "Organization",
"name": "DZone",
"url": "https://dzone.com",
"logo": {
"@type": "ImageObject",
"url": "https://dzone.com/themes/dz20/images/dz_logo_2021_cropped.png"
}
},
"articleBody": "Modern applications rely on distributed databases to handle massive amounts of data and scale seamlessly across multiple nodes. While sharding helps distribute the load, it also introduces a major challenge — cross-shard joins and data movement, which can significantly impact performance. When a query requires joining tables stored on different shards, the database must move data across nodes, leading to: High network latency due to data shufflingIncreased query execution time as distributed queries become expensiveHigher CPU usage as more computation is needed to merge data across nodes But what if we could eliminate unnecessary cross-shard joins? In this article, we'll explore four proven strategies to avoid data movement in distributed databases: Replicating reference tablesCollocating related data in the same shardUsing a mapping table for efficient joinsPrecomputed join tables (materialized views) By applying these strategies, you can optimize query execution, minimize network overhead, and scale your database efficiently. Understanding the Problem: Cross-Shard Joins and Data Movement How Data Movement Happens Imagine a typical e-commerce database where: The Orders table is sharded by CustomerID. SQL CREATE TABLE Orders ( order_id INT PRIMARY KEY AUTO_INCREMENT, -- Unique ID for the order customer_id INT NOT NULL, -- Foreign key to Customers (Sharding Key) product_id INT NOT NULL, -- Foreign key to Products quantity INT DEFAULT 1, -- Number of units ordered total_price DECIMAL(10,2), -- Total price of the order order_status ENUM('Pending', 'Shipped', 'Delivered', 'Cancelled') DEFAULT 'Pending', order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, shard_key INT GENERATED ALWAYS AS (customer_id) VIRTUAL -- Helps with sharding logic ); Column Name Data Type Description order_id INT (Primary Key, Auto Increment) Unique identifier for the order. customer_id INT (Sharding Key) Foreign key to Customers table; used for sharding. product_id INT (Foreign Key) References Products.product_id. quantity INT (Default: 1) Number of units ordered. total_price DECIMAL(10,2) Total cost of the order. order_status ENUM('Pending', 'Shipped', 'Delivered', 'Cancelled') (Default: 'Pending') Current order status. order_date TIMESTAMP (Default: CURRENT_TIMESTAMP) Timestamp when the order was placed. shard_key INT (Virtual Column) Helps in sharding logic by using customer_id. Sharding Key: customer_id Ensures that all orders of a given customer remain on the same shard. Why Not order_id? Because customers place multiple orders, keeping all their orders on the same shard optimizes query performance for customer history retrieval. The Products table is sharded by ProductID. SQL CREATE TABLE Products ( product_id INT PRIMARY KEY AUTO_INCREMENT, -- Unique product ID (Sharding Key) product_name VARCHAR(255) NOT NULL, -- Name of the product category VARCHAR(100), -- Product category (e.g., Electronics, Clothing) price DECIMAL(10,2) NOT NULL, -- Product price stock_quantity INT DEFAULT 0, -- Available stock count last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, shard_key INT GENERATED ALWAYS AS (product_id) VIRTUAL -- Helps with sharding logic ); Column Name Data Type Description product_id INT (Primary Key, Auto Increment) Unique identifier for the product (Sharding Key). product_name VARCHAR(255) Name of the product. category VARCHAR(100) Product category (e.g., Electronics, Clothing). price DECIMAL(10,2) Price of the product. stock_quantity INT (Default: 0) Available stock count. last_updated TIMESTAMP (Default: CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) Timestamp for last update. shard_key INT (Virtual Column) Helps in sharding logic by using product_id. Sharding Key: product_id Ensures that product details are distributed evenly across shards. Why Not category? Because product_id ensures uniform distribution, whereas some categories may be more popular and could cause unbalanced shards. Now, let's say we want to retrieve the product names for a specific customer’s orders: SQL SELECT o.order_id, o.customer_id, p.product_name FROM Orders o JOIN Products p ON o.product_id = p.product_id WHERE o.customer_id = 123; Since Orders and Products are sharded differently, fetching the product_name requires data movement between shards. This can cause significant performance degradation, especially as the system scales. Strategy 1: Replicating Reference Tables Concept Instead of storing reference tables on separate shards, we replicate them across all nodes. This allows queries to perform joins locally, eliminating inter-shard communication. How to Implement In a database like PostgreSQL Citus, we can create a replicated reference table: SQL CREATE TABLE Products ( product_id INT PRIMARY KEY, product_name TEXT ) DISTRIBUTED REPLICATED; Benefits Eliminates cross-shard joins for lookups.Fast query execution, as the reference data is available on all shards. When NOT to Use If the reference table is too large (e.g., millions of records).If the reference data changes frequently, causing replication overhead. Strategy 2: Collocating Related Data in the Same Shard Concept Instead of sharding Orders by CustomerID and Products by ProductID, we shard both tables by the same key (CustomerID). How It Works SQL SELECT o.order_id, o.customer_id, p.product_name FROM Orders o JOIN Products p ON o.product_id = p.product_id WHERE o.customer_id = 123; Now, because both tables are in the same shard, the join happens locally, avoiding cross-shard data movement. Benefits Optimized for queries that frequently join tables based on a shared key.Works well for applications where customer-specific data is frequently accessed. When NOT to Use If tables grow at different rates, leading to uneven shard distribution.If queries involve cross-customer searches, making sharding by CustomerID inefficient. Strategy 3: Using a Mapping Table for Efficient Joins Concept Instead of performing cross-shard joins, we use a mapping table that stores which shard contains the required data. How It Works We create a customer-product mapping table: SQL CREATE TABLE CustomerProductMap ( customer_id INT, product_id INT, shard_id INT, PRIMARY KEY (customer_id, product_id) ); Before querying, we first retrieve the shard_id: SQL SELECT shard_id FROM CustomerProductMap WHERE customer_id = 123; Then, we query only the relevant shard: SQL SELECT o.order_id, o.customer_id, p.product_name FROM Orders o JOIN Products p ON o.product_id = p.product_id WHERE o.customer_id = 123 AND o.shard_id = &lt;retrieved_shard&gt;; Benefits Reduces the number of shards queried, improving performance.Works well for large datasets that cannot be replicated. When NOT to Use If updates to CustomerProductMap are frequent, causing maintenance overhead. Strategy 4: Precomputed Join Tables (Materialized Views) Concept Instead of executing joins at query time, we precompute and store frequently used join results in a materialized view or a separate table. How It Works We create a denormalized table that precomputes Orders and Products: SQL CREATE TABLE Precomputed_Order_Products ( order_id INT PRIMARY KEY, customer_id INT, product_id INT, product_name TEXT, order_date TIMESTAMP ) SHARDED BY (customer_id); A background ETL process precomputes the joins and inserts the data: SQL INSERT INTO Precomputed_Order_Products (order_id, customer_id, product_id, product_name, order_date) SELECT o.order_id, o.customer_id, p.product_id, p.product_name, o.order_date FROM Orders o JOIN Products p ON o.product_id = p.product_id; Querying without joins: SQL SELECT order_id, customer_id, product_name, order_date FROM Precomputed_Order_Products WHERE customer_id = 123; Benefits No joins required at query time, significantly improving performance.Ideal for read-heavy workloads where query speed is critical. When NOT to Use If the dataset changes frequently, requiring frequent recomputation.If storage costs for redundant data are too high. Choosing the Right Strategy: Trade-offs and Considerations ApproachProsConsReplicating Reference TablesFast joins, eliminates data movementOnly works for small tablesCollocating Data in the Same ShardEfficient joins, avoids movementRequires careful shard key selectionMapping Table ApproachEfficient query routingExtra storage &amp; maintenance overheadPrecomputed Join TablesBest for read-heavy workloadsRequires background ETL jobs General Guidelines Use replication – For small reference tablesUse colocation – When queries naturally group by a specific keyUse mapping tables – When reference tables are too large to replicateUse precomputed joins – For high-performance analytical queries Conclusion Cross-shard data movement is one of the biggest performance challenges in distributed databases. We can significantly optimize query performance and reduce unnecessary network overhead by applying reference table replication, colocation, mapping tables, and precomputed joins. Choosing the right strategy depends on query patterns, data distribution, and storage constraints. With the right approach, you can build highly scalable, performant distributed systems without being hindered by cross-shard joins.",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://dzone.com/articles/avoid-cross-shard-data-movement"
},
"image": {
"@type": "ImageObject",
"url": "https://dz2cdn1.dzone.com/storage/article-thumb/18305475-thumb.jpg"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "DZone",
"item": "https://dzone.com"
},
{
"@type": "ListItem",
"position": 2,
"name": "Data Engineering",
"item": "https://dzone.com/data-engineering"
},
{
"@type": "ListItem",
"position": 3,
"name": "Databases",
"item": "https://dzone.com/databases"
},
{
"@type": "ListItem",
"position": 4,
"name": "Avoid Cross-Shard Data Movement in Distributed Databases",
"item": "https://dzone.com/articles/avoid-cross-shard-data-movement"
}
]
}
</script>
<article>
<div class="content">
<div class="header">
<ol class="breadcrumb">
<li class="server"><a href="https://dzone.com">DZone</a></li>
<li class="server"><a href="https://dzone.com/data-engineering">Data Engineering</a></li>
<li class="server"><a href="https://dzone.com/databases">Databases</a></li>
<li class="active server">Avoid Cross-Shard Data Movement in Distributed Databases</li>
</ol>
<div class="header-title">
<div class="title">
<h1 class="article-title">Avoid Cross-Shard Data Movement in Distributed Databases</h1>
</div>
<div class="subhead">
<p>Learn four effective strategies to optimize distributed joins, reduce network overhead, and improve query performance in sharded databases.</p>
</div>
<div class="publish-meta">
By<span style="user-select: none;">&nbsp;</span>
<div class="article-author-meta">
<img src="https://secure.gravatar.com/avatar/80b9c8f75d350cccb189ca77db412590?d=identicon&r=PG" class="avatar" alt="Baskar Sikkayan user avatar" width="40">
<div class="author-info">
<span class="author-name">
<a href="/users/5280786/udayabaski.html" rel="nofollow" data-core-user="false">Baskar Sikkayan</a>
</span>
</div>
&middot;
</div>
<span class="author-date">
Mar. 26, 25
</span>
&middot;
<span>Tutorial</span>
</div>
</div>
</div>
<div class="author-n-useraction">
<div class="like action" x-data="engagementModal(articleId)">
<span id="activity-like-icon" class="dz-like icon-thumbs-up" x-on:click="updateStore()"></span>
<span class="action-label like-text" x-on:click="open()" x-cloak>
<span>Likes</span>
<span id="activity-like-counter" class="like-count">(5)</span>
</span>
<template x-teleport="body">
<div class="engagement-overlay" x-show="$store.article.engagement.open && nodeId === $store.article.id" x-on:keyup.escape.window="close()">
<div class="engagement-modal">
<div class="inner" x-on:click.outside="close()">
<div class="header">
<div class="title">Likes</div>
<button class="close" x-on:click="close()"></button>
</div>
<div class="content">
<div x-show="$store.article.engagement.initializing" class="loading-screen">
<i class="icon icon-spin3 anim-spin"></i>
</div>
<div x-show="!$store.article.engagement.initializing">
<template x-for="user in $store.article.engagement.users" :key="user.id">
<div class="media">
<div class="media-left">
<img class="avatar"
x-bind:src="user.profile.profileImage"
loading="lazy"
width="50"
height="50"
>
</div>
<div class="media-right">
<a x-bind:href="user.computed.url" x-html="user.profile.name"></a>
<div x-show="formatJobData(user)" x-html="formatJobData(user)"></div>
</div>
</div>
</template>
</div>
<div x-show="isDataUnavailable()" class="center-screen">
<div x-show="!$store.article.engagement.unauthorized">
<div>There are no likes...yet! &#128064;</div>
<div>Be the first to like this post!</div>
</div>
<div x-show="$store.article.engagement.unauthorized">
<div>It looks like you're not logged in.</div>
<div><a href="/users/login.html">Sign in</a> to see who liked this post!</div>
</div>
</div>
<div x-show="isFooterShowing()">
<div class="footer">
<button class="btn btn-primary" x-on:click="fetchEngagements()"
x-bind:disabled="$store.article.engagement.loading"
>
Load More
<i x-show="$store.article.engagement.loading" class="icon icon-spin3 anim-spin"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template> </div>
<div class="action comment-action">
<span class="comment">
<i class="icon-comment"></i>
<span class="action-label">Comment</span>
<span id="activity-comment-counter" class="comment-count"></span>
</span>
</div>
<div class="save action">
<div id="activity-save-icon" class="save icon-star-empty">
<span id="activity-save-text" class="action-label">Save</span>
</div>
</div>
<div class="tweet action">
<a id="tweet-link" href="" class="title" target="_blank">
<span><i class="icon-twitter"></i></span>
<span class="action-label">Tweet</span>
</a>
</div>
<div class="linkedin action">
<a id="linkedin-link" href="https://www.linkedin.com/sharing/share-offsite/?url=https://dzone.com/articles/avoid-cross-shard-data-movement" class="title" target="_blank">
<span><i class="icon-linkedin-1"></i></span>
<span class="action-label">Share</span>
</a>
</div>
<div class="right-most">
<div id="activity-view-container" class="article-views action">
<i class="icon-eye"></i>
<span class="action-label view-count">6.9K Views</span>
</div>
</div>
</div>
<div class="signin-prompt">
<p>Join the DZone community and get the full member experience.</p>
<a id="article-signin-prompt" href="/static/registration.html">Join For Free</a>
</div>
<div class="arrow-down"></div>
<div id="top-bumper-container"></div>
<div>
<div class="content-html"><p data-end="100" data-start="78">Modern applications rely on distributed databases to handle massive amounts of data and scale seamlessly across multiple nodes. While sharding helps distribute the load, it also introduces a major challenge — cross-shard joins and data movement, which can significantly impact performance.</p>
<p data-end="100" data-start="78">When a query requires joining tables stored on <a href="https://dzone.com/articles/database-sharding-and-its-challenges">different shards</a>, the database must move data across nodes, leading to:</p>
<ul data-end="734" data-start="520">
<li data-end="571" data-start="520">High network latency due to data shuffling</li>
<li data-end="651" data-start="572">Increased query execution time as distributed queries become expensive</li>
<li data-end="734" data-start="652">Higher CPU usage as more computation is needed to merge data across nodes</li>
</ul>
<p data-end="910" data-start="736">But what if we could eliminate unnecessary cross-shard joins?&nbsp;</p>
<p data-end="910" data-start="736">In this article, we'll explore four proven strategies to avoid data movement in <a href="https://dzone.com/articles/what-is-a-distributed-database">distributed databases</a>:</p>
<ol data-end="1106" data-start="912">
<li data-end="949" data-start="912">Replicating reference tables</li>
<li data-end="1001" data-start="950">Collocating related data in the same shard</li>
<li data-end="1052" data-start="1002">Using a mapping table for efficient joins</li>
<li data-end="1106" data-start="1053">Precomputed join tables (materialized views)</li>
</ol>
<p data-end="1241" data-start="1108">By applying these strategies, you can optimize query execution, minimize network overhead, and scale your database efficiently.</p>
<h2 data-end="1319" data-start="1248"><strong data-end="1317" data-start="1251">Understanding the Problem: Cross-Shard Joins and Data Movement</strong></h2>
<h3 data-end="1356" data-start="1321"><strong data-end="1354" data-start="1325">How Data Movement Happens</strong></h3>
<p data-end="1403" data-start="1357">Imagine a typical e-commerce database where:</p>
<p>The <strong data-end="1420" data-start="1410">Orders</strong> table is sharded by <code data-end="1453" data-start="1441">CustomerID</code>.</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="CREATE TABLE Orders (
order_id INT PRIMARY KEY AUTO_INCREMENT, -- Unique ID for the order
customer_id INT NOT NULL, -- Foreign key to Customers (Sharding Key)
product_id INT NOT NULL, -- Foreign key to Products
quantity INT DEFAULT 1, -- Number of units ordered
total_price DECIMAL(10,2), -- Total price of the order
order_status ENUM('Pending', 'Shipped', 'Delivered', 'Cancelled') DEFAULT 'Pending',
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
shard_key INT GENERATED ALWAYS AS (customer_id) VIRTUAL -- Helps with sharding logic
);" data-lang="text/x-sql">
<pre><code lang="text/x-sql">CREATE TABLE Orders (
order_id INT PRIMARY KEY AUTO_INCREMENT, -- Unique ID for the order
customer_id INT NOT NULL, -- Foreign key to Customers (Sharding Key)
product_id INT NOT NULL, -- Foreign key to Products
quantity INT DEFAULT 1, -- Number of units ordered
total_price DECIMAL(10,2), -- Total price of the order
order_status ENUM('Pending', 'Shipped', 'Delivered', 'Cancelled') DEFAULT 'Pending',
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
shard_key INT GENERATED ALWAYS AS (customer_id) VIRTUAL -- Helps with sharding logic
);</code></pre>
</div>
</div>
</div>
<p><br></p>
<div class="table-responsive" style="border: none;">
<table data-end="962" data-start="126" style="max-width: 100%; width: auto; table-layout: fixed; display: table;" width="auto">
<thead data-end="184" data-start="126">
<tr data-end="184" data-start="126" style="overflow-wrap: break-word; width: auto;" width="auto">
<th data-end="142" data-start="126" style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Column Name
</div></th>
<th data-end="169" data-start="142" style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Data Type
</div></th>
<th data-end="184" data-start="169" style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Description
</div></th>
</tr>
</thead>
<tbody data-end="962" data-start="242">
<tr data-end="330" data-start="242" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="254" data-start="244">order_id</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
INT (Primary Key, Auto Increment)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Unique identifier for the order.
</div></td>
</tr>
<tr data-end="429" data-start="331" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="346" data-start="333">customer_id</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
INT (Sharding Key)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Foreign key to <code data-end="401" data-start="390">Customers</code> table; used for sharding.
</div></td>
</tr>
<tr data-end="509" data-start="430" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="444" data-start="432">product_id</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
INT (Foreign Key)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
References <code data-end="506" data-start="485">Products.product_id</code>.
</div></td>
</tr>
<tr data-end="580" data-start="510" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="522" data-start="512">quantity</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
INT (Default: 1)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Number of units ordered.
</div></td>
</tr>
<tr data-end="651" data-start="581" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="596" data-start="583">total_price</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
DECIMAL(10,2)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Total cost of the order.
</div></td>
</tr>
<tr data-end="770" data-start="652" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="668" data-start="654">order_status</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
ENUM('Pending', 'Shipped', 'Delivered', 'Cancelled') (Default: 'Pending')
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Current order status.
</div></td>
</tr>
<tr data-end="868" data-start="771" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="785" data-start="773">order_date</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
TIMESTAMP (Default: CURRENT_TIMESTAMP)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Timestamp when the order was placed.
</div></td>
</tr>
<tr data-end="962" data-start="869" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="882" data-start="871">shard_key</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
INT (Virtual Column)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Helps in sharding logic by using <code data-end="959" data-start="946">customer_id</code>.
</div></td>
</tr>
</tbody>
</table>
</div>
<h3><br><strong data-end="903" data-start="886">Sharding Key: customer_id</strong></h3>
<p>Ensures that all orders of a given customer remain on the same shard.</p>
<h3><strong data-end="1018" data-start="995">Why Not order_id?</strong>&nbsp;</h3>
<p>Because customers place multiple orders, keeping all their orders on the same shard optimizes query performance for customer history retrieval.</p>
<p>The <strong data-end="1475" data-start="1463">Products</strong> table is sharded by <code data-end="1507" data-start="1496">ProductID</code>.</p>
<div class="codeMirror-wrapper newest" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="CREATE TABLE Products (
product_id INT PRIMARY KEY AUTO_INCREMENT, -- Unique product ID (Sharding Key)
product_name VARCHAR(255) NOT NULL, -- Name of the product
category VARCHAR(100), -- Product category (e.g., Electronics, Clothing)
price DECIMAL(10,2) NOT NULL, -- Product price
stock_quantity INT DEFAULT 0, -- Available stock count
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
shard_key INT GENERATED ALWAYS AS (product_id) VIRTUAL -- Helps with sharding logic
);" data-lang="text/x-sql">
<pre><code lang="text/x-sql">CREATE TABLE Products (
product_id INT PRIMARY KEY AUTO_INCREMENT, -- Unique product ID (Sharding Key)
product_name VARCHAR(255) NOT NULL, -- Name of the product
category VARCHAR(100), -- Product category (e.g., Electronics, Clothing)
price DECIMAL(10,2) NOT NULL, -- Product price
stock_quantity INT DEFAULT 0, -- Available stock count
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
shard_key INT GENERATED ALWAYS AS (product_id) VIRTUAL -- Helps with sharding logic
);</code></pre>
</div>
</div>
</div>
<p><br></p>
<div class="table-responsive" style="border: none;">
<table data-end="1777" data-start="1018" style="max-width: 100%; width: auto; table-layout: fixed; display: table;" width="auto">
<thead data-end="1081" data-start="1018">
<tr data-end="1081" data-start="1018" style="overflow-wrap: break-word; width: auto;" width="auto">
<th data-end="1037" data-start="1018" style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Column Name
</div></th>
<th data-end="1066" data-start="1037" style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Data Type
</div></th>
<th data-end="1081" data-start="1066" style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Description
</div></th>
</tr>
</thead>
<tbody data-end="1777" data-start="1143">
<tr data-end="1250" data-start="1143" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="1157" data-start="1145">product_id</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
INT (Primary Key, Auto Increment)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Unique identifier for the product (Sharding Key).
</div></td>
</tr>
<tr data-end="1321" data-start="1251" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="1267" data-start="1253">product_name</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
VARCHAR(255)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Name of the product.
</div></td>
</tr>
<tr data-end="1419" data-start="1322" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="1334" data-start="1324">category</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
VARCHAR(100)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Product category (e.g., Electronics, Clothing).
</div></td>
</tr>
<tr data-end="1491" data-start="1420" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="1429" data-start="1422">price</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
DECIMAL(10,2)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Price of the product.
</div></td>
</tr>
<tr data-end="1564" data-start="1492" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="1510" data-start="1494">stock_quantity</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
INT (Default: 0)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Available stock count.
</div></td>
</tr>
<tr data-end="1681" data-start="1565" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="1581" data-start="1567">last_updated</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
TIMESTAMP (Default: CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Timestamp for last update.
</div></td>
</tr>
<tr data-end="1777" data-start="1682" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
<code data-end="1695" data-start="1684">shard_key</code>
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
INT (Virtual Column)
</div></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">
<div>
Helps in sharding logic by using <code data-end="1774" data-start="1762">product_id</code>.
</div></td>
</tr>
</tbody>
</table>
</div>
<h3><br><strong data-end="1846" data-start="1829">Sharding Key: product_id</strong></h3>
<p>Ensures that product details are distributed evenly across shards.</p>
<h3><strong data-end="1957" data-start="1934">Why Not category?</strong>&nbsp;</h3>
<p>Because <code data-end="1978" data-start="1966">product_id</code> ensures uniform distribution, whereas some categories may be more popular and could cause unbalanced shards.</p>
<p data-end="1600" data-start="1512">Now, let's say we want to retrieve the product names for a specific customer’s orders:</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="SELECT o.order_id, o.customer_id, p.product_name
FROM Orders o
JOIN Products p ON o.product_id = p.product_id
WHERE o.customer_id = 123;" data-lang="text/x-sql">
<pre><code lang="text/x-sql">SELECT o.order_id, o.customer_id, p.product_name
FROM Orders o
JOIN Products p ON o.product_id = p.product_id
WHERE o.customer_id = 123;</code></pre>
</div>
</div>
</div>
<p><br></p>
<p>Since <code data-end="1765" data-start="1757">Orders</code> and <code data-end="1780" data-start="1770">Products</code> are sharded differently, fetching the <code data-end="1837" data-start="1823">product_name</code> requires data movement between shards. This can cause significant performance degradation, especially as the system scales.</p>
<h2 data-end="2023" data-start="1974"><strong data-end="2021" data-start="1977">Strategy 1: Replicating Reference Tables</strong></h2>
<h3 data-end="2042" data-start="2025"><strong data-end="2040" data-start="2029">Concept</strong></h3>
<p data-end="2229" data-start="2043">Instead of storing reference tables on separate shards, we replicate them across all nodes. This allows queries to perform joins locally, eliminating inter-shard communication.</p>
<h3 data-end="2257" data-start="2231">How to Implement</h3>
<p data-end="2348" data-start="2258">In a database like PostgreSQL Citus, we can create a replicated reference table:</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="CREATE TABLE Products (
product_id INT PRIMARY KEY,
product_name TEXT
) DISTRIBUTED REPLICATED;" data-lang="text/x-sql">
<pre><code lang="text/x-sql">CREATE TABLE Products (
product_id INT PRIMARY KEY,
product_name TEXT
) DISTRIBUTED REPLICATED;</code></pre>
</div>
</div>
</div>
<p><br></p>
<h3 data-end="2484" data-start="2466"><strong data-end="2482" data-start="2470">Benefits</strong></h3>
<ul>
<li>Eliminates cross-shard joins for lookups.</li>
<li>Fast query execution, as the reference data is available on all shards.</li>
</ul>
<h3 data-end="2633" data-start="2608"><strong data-end="2631" data-start="2612">When NOT to Use</strong></h3>
<ul>
<li>If the reference table is too large (e.g., millions of records).</li>
<li>If the reference data changes frequently, causing replication overhead.</li>
</ul>
<h2 data-end="2856" data-start="2793"><strong data-end="2854" data-start="2796">Strategy 2: Collocating Related Data in the Same Shard</strong></h2>
<h3 data-end="2875" data-start="2858"><strong data-end="2873" data-start="2862">Concept</strong></h3>
<p data-end="3014" data-start="2876">Instead of sharding Orders by <code data-end="2920" data-start="2908">CustomerID</code> and Products by <code data-end="2952" data-start="2941">ProductID</code>, we shard both tables by the same key (<code data-end="3010" data-start="2998">CustomerID</code>).</p>
<h3 data-end="3014" data-start="2876">How It Works</h3>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="SELECT o.order_id, o.customer_id, p.product_name
FROM Orders o
JOIN Products p ON o.product_id = p.product_id
WHERE o.customer_id = 123;" data-lang="text/x-sql">
<pre><code lang="text/x-sql">SELECT o.order_id, o.customer_id, p.product_name
FROM Orders o
JOIN Products p ON o.product_id = p.product_id
WHERE o.customer_id = 123;</code></pre>
</div>
</div>
</div>
<p data-end="3303" data-start="3188"><br></p>
<p data-end="3303" data-start="3188">Now, because both tables are in the same shard, the join happens locally, avoiding cross-shard data movement.</p>
<h3 data-end="3323" data-start="3305">Benefits</h3>
<ul>
<li>Optimized for queries that frequently join tables based on a shared key.</li>
<li>Works well for applications where customer-specific data is frequently accessed.</li>
</ul>
<h3 data-end="3512" data-start="3487">When NOT to Use</h3>
<ul>
<li>If tables grow at different rates, leading to uneven shard distribution.</li>
<li>If queries involve cross-customer searches, making sharding by <code data-end="3675" data-start="3663">CustomerID</code> inefficient.</li>
</ul>
<h2 data-end="3759" data-start="3697"><strong data-end="3757" data-start="3700">Strategy 3: Using a Mapping Table for Efficient Joins</strong></h2>
<h3 data-end="3778" data-start="3761"><strong data-end="3776" data-start="3765">Concept</strong></h3>
<p data-end="3904" data-start="3779">Instead of performing cross-shard joins, we use a mapping table that stores which shard contains the required data.</p>
<h3 data-end="3928" data-start="3906"><strong data-end="3926" data-start="3910">How It Works</strong></h3>
<p data-end="3978" data-start="3929">We create a customer-product mapping table:</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="CREATE TABLE CustomerProductMap (
customer_id INT,
product_id INT,
shard_id INT,
PRIMARY KEY (customer_id, product_id)
);" data-lang="text/x-sql">
<pre><code lang="text/x-sql">CREATE TABLE CustomerProductMap (
customer_id INT,
product_id INT,
shard_id INT,
PRIMARY KEY (customer_id, product_id)
);</code></pre>
</div>
</div>
</div>
<p><br></p>
<p>Before querying, we first retrieve the <code data-end="4179" data-start="4169">shard_id</code>:</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="SELECT shard_id FROM CustomerProductMap WHERE customer_id = 123;" data-lang="text/x-sql">
<pre><code lang="text/x-sql">SELECT shard_id FROM CustomerProductMap WHERE customer_id = 123;</code></pre>
</div>
</div>
</div>
<p data-end="4306" data-start="4261"><br>
Then, we query only the <strong data-end="4303" data-start="4285">relevant shard</strong>:</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="SELECT o.order_id, o.customer_id, p.product_name
FROM Orders o
JOIN Products p ON o.product_id = p.product_id
WHERE o.customer_id = 123
AND o.shard_id = <retrieved_shard>;" data-lang="text/x-sql">
<pre><code lang="text/x-sql">SELECT o.order_id, o.customer_id, p.product_name
FROM Orders o
JOIN Products p ON o.product_id = p.product_id
WHERE o.customer_id = 123
AND o.shard_id = &lt;retrieved_shard&gt;;</code></pre>
</div>
</div>
</div>
<p><br></p>
<h3 data-end="4510" data-start="4492"><strong data-end="4508" data-start="4496">Benefits</strong></h3>
<ul>
<li>Reduces the number of shards queried, improving performance.</li>
<li>Works well for large dataset<strong data-end="4611" data-start="4593">s</strong> that cannot be replicated.</li>
</ul>
<h3 data-end="4667" data-start="4642"><strong data-end="4665" data-start="4646">When NOT to Use</strong></h3>
<ul>
<li data-end="4750" data-start="4668">If updates to <code data-end="4704" data-start="4684">CustomerProductMap</code> are frequent, causing maintenance overhead.</li>
</ul>
<h2 data-end="4822" data-start="4757"><strong data-end="4820" data-start="4760">Strategy 4: Precomputed Join Tables (Materialized Views)</strong></h2>
<h3 data-end="4841" data-start="4824"><strong data-end="4839" data-start="4828">Concept</strong></h3>
<p data-end="4990" data-start="4842">Instead of executing joins at query time, we precompute and store frequently used join results in a materialized view or a separate table.</p>
<h3 data-end="5014" data-start="4992"><strong data-end="5012" data-start="4996">How It Works</strong></h3>
<p data-end="5093" data-start="5015">We create a <strong data-end="5049" data-start="5027">denormalized table</strong> that precomputes <code data-end="5075" data-start="5067">Orders</code> and <code data-end="5090" data-start="5080">Products</code>:</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="CREATE TABLE Precomputed_Order_Products (
order_id INT PRIMARY KEY,
customer_id INT,
product_id INT,
product_name TEXT,
order_date TIMESTAMP
) SHARDED BY (customer_id);" data-lang="text/x-sql">
<pre><code lang="text/x-sql">CREATE TABLE Precomputed_Order_Products (
order_id INT PRIMARY KEY,
customer_id INT,
product_id INT,
product_name TEXT,
order_date TIMESTAMP
) SHARDED BY (customer_id);</code></pre>
</div>
</div>
</div>
<p data-end="5370" data-start="5296"><br>
A background ETL process <strong data-end="5346" data-start="5321">precomputes the joins</strong> and inserts the data:</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="INSERT INTO Precomputed_Order_Products (order_id, customer_id, product_id, product_name, order_date)
SELECT o.order_id, o.customer_id, p.product_id, p.product_name, o.order_date
FROM Orders o
JOIN Products p ON o.product_id = p.product_id;" data-lang="text/x-sql">
<pre><code lang="text/x-sql">INSERT INTO Precomputed_Order_Products (order_id, customer_id, product_id, product_name, order_date)
SELECT o.order_id, o.customer_id, p.product_id, p.product_name, o.order_date
FROM Orders o
JOIN Products p ON o.product_id = p.product_id;</code></pre>
</div>
</div>
</div>
<p><br>
Querying without joins:</p>
<div class="codeMirror-wrapper" contenteditable="false">
<div contenteditable="false">
<div class="codeHeader">
<div class="nameLanguage">
SQL
</div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
</div>
<div class="codeMirror-code--wrapper" data-code="SELECT order_id, customer_id, product_name, order_date
FROM Precomputed_Order_Products
WHERE customer_id = 123;" data-lang="text/x-sql">
<pre><code lang="text/x-sql">SELECT order_id, customer_id, product_name, order_date
FROM Precomputed_Order_Products
WHERE customer_id = 123;</code></pre>
</div>
</div>
</div>
<h3 data-end="5799" data-start="5781"><br><strong data-end="5797" data-start="5785">Benefits</strong></h3>
<ul>
<li>No joins required at query time, significantly improving performance.</li>
<li>Ideal for read-heavy workloads where query speed is critical.</li>
</ul>
<h3 data-end="5970" data-start="5945">When NOT to Use</h3>
<ul>
<li>If the dataset changes frequently, requiring frequent recomputation.</li>
<li>If storage costs for redundant data are too high.</li>
</ul>
<h2 data-end="6175" data-start="6108"><strong data-end="6173" data-start="6111">Choosing the Right Strategy: Trade-offs and Considerations</strong></h2>
<div class="table-responsive" style="border: none;">
<table data-end="6644" data-start="6177" style="max-width: 100%; width: auto; table-layout: fixed; display: table;" width="auto">
<thead data-end="6203" data-start="6177">
<tr data-end="6203" data-start="6177" style="overflow-wrap: break-word; width: auto;" width="auto">
<th data-end="6188" data-start="6177" style="overflow-wrap: break-word; width: auto;" width="auto">Approach</th>
<th data-end="6195" data-start="6188" style="overflow-wrap: break-word; width: auto;" width="auto">Pros</th>
<th data-end="6203" data-start="6195" style="overflow-wrap: break-word; width: auto;" width="auto">Cons</th>
</tr>
</thead>
<tbody data-end="6644" data-start="6231">
<tr data-end="6336" data-start="6231" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto"><strong data-end="6265" data-start="6233">Replicating Reference Tables</strong></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">Fast joins, eliminates data movement</td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">Only works for small tables</td>
</tr>
<tr data-end="6453" data-start="6337" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto"><strong data-end="6377" data-start="6339">Collocating Data in the Same Shard</strong></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">Efficient joins, avoids movement</td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">Requires careful shard key selection</td>
</tr>
<tr data-end="6549" data-start="6454" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto"><strong data-end="6482" data-start="6456">Mapping Table Approach</strong></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">Efficient query routing</td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">Extra storage &amp; maintenance overhead</td>
</tr>
<tr data-end="6644" data-start="6550" style="overflow-wrap: break-word; width: auto;" width="auto">
<td style="overflow-wrap: break-word; width: auto;" width="auto"><strong data-end="6579" data-start="6552">Precomputed Join Tables</strong></td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">Best for read-heavy workloads</td>
<td style="overflow-wrap: break-word; width: auto;" width="auto">Requires background ETL jobs</td>
</tr>
</tbody>
</table>
</div>
<p data-end="6672" data-start="6646"><br></p>
<h3 data-end="6672" data-start="6646"><strong data-end="6672" data-start="6650">General Guidelines</strong></h3>
<ul data-end="6967" data-start="6673">
<li data-end="6730" data-start="6673"><strong data-end="6694" data-start="6675">Use replication</strong> – For small reference tables</li>
<li data-end="6807" data-start="6731"><strong data-end="6751" data-start="6733">Use colocation</strong> – When queries naturally group by a specific key</li>
<li data-end="6890" data-start="6808"><strong data-end="6832" data-start="6810">Use mapping tables</strong> – When reference tables are too large to replicate</li>
<li data-end="6967" data-start="6891"><strong data-end="6918" data-start="6893">Use precomputed joins</strong> – For high-performance analytical queries</li>
</ul>
<h2 data-end="6993" data-start="6974"><strong data-end="6991" data-start="6977">Conclusion</strong></h2>
<p data-end="6993" data-start="6974"><a href="https://dzone.com/articles/what-is-sharding">Cross-shard data movement</a> is one of the biggest performance challenges in distributed databases. <span style="margin: 0px; padding: 0px;">We can significantly optimize query performance and reduce unnecessary network overhead by applying reference table replication, colocation, mapping tables, and precomputed joins</span>.</p>
<p data-end="7528" data-start="7288">Choosing the right strategy depends on query patterns, data distribution, and storage constraints. With the right approach, you can build highly scalable, performant distributed systems without being hindered by cross-shard joins.</p></div>
</div>
<div id="bottom-bumper-container"></div>
<div class="article-tag-pill-container">
<span class="article-tag-pill">Database</span>
<span class="article-tag-pill">Shard (database architecture)</span>
<span class="article-tag-pill">Data Types</span>
</div>
<div class="attribution">
<p>Opinions expressed by DZone contributors are their own.</p>
</div>
</div>
</article>
</div>
<div class="trending-separator goto"></div>
<aside class="trending goto" aria-labelledby="related-mobile-heading">
<h2 id="related-mobile-heading">Related</h2>
<ul>
<li class="item">
<a href="/articles/mcp-opentelemetry-tracing" class="goto-link related-link">Tracing the Agentic Loop: Monitoring Multi-Round-Trip MCP Calls With OpenTelemetry</a>
</li>
<li class="item">
<a href="/articles/retiring-a-tier-0-legacy-database-without-breaking" class="goto-link related-link">Retiring a Tier-0 Legacy Database Without Breaking the Business</a>
</li>
<li class="item">
<a href="/articles/aggregate-reference-problem" class="goto-link related-link">The Aggregate Reference Problem</a>
</li>
<li class="item">
<a href="/articles/the-serverless-ceiling-designing-write-heavy-backe" class="goto-link related-link">The Serverless Ceiling: Designing Write-Heavy Backends With Aurora Limitless</a>
</li>
</ul>
</aside>
</div>
<div id="div-gpt-ad-1435246566686-11" class="ads-bottom-leaderboard dz2_article_bottom" data-gpt-slot="bottom"></div>
<div class="layout-card widget-top-border partner-resources-block" style="width:100%; margin-bottom: 1em;">
<div class="main-container">
<div class="featured-header">
<h2>
<span>Partner Resources</span>
</h2>
</div>
<div class="partner-resources-container">
<div id="div-gpt-ad-1435246566686-5" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr1"></div>
<div id="div-gpt-ad-1435246566686-6" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr2"></div>
<div id="div-gpt-ad-1435246566686-7" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr3"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="bottom-sticky-ad-container">
<span class="bottom-sticky-ad-close" title="close"
x-on:click="$el.parentElement.classList.add('closed')">×</span>
<div id="div-gpt-ad-1635294790718-12" class="bottom-sticky-ad dz2_sticky_footer_leaderboard" data-gpt-slot="bottomStickyFooter"></div>
</div>
<div class="modal fade bd-example-modal-lg" id="modal-message" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"></div>
<div class="modal-body"></div>
</div>
</div>
</div>
</div>
</div>
<div class="comments-overlay"></div>
<div id="comment-box">
<div class="comment-box-wrapper">
<div id="comment-input-editor"></div>
</div>
<div class="info hidden"></div>
<div class="comments-content" style="display: none;">
<div class="comment-header">
<hr />
<span class="icon-comment">
<span class="numOfComments"></span> Comments
</span>
</div>
<div class="comments"></div>
</div>
</div>
<script async>var articleTitle = 'Avoid Cross-Shard Data Movement in Distributed Databases';
var articleUrl = 'https://dzone.com/articles/avoid-cross-shard-data-movement';
var retweetLink = document.querySelector('#tweet-link');
function retweet(event) {
event.preventDefault();
event.stopPropagation();
var twitter = 'https://twitter.com/intent/tweet';
var params = '?text=' + encodeURIComponent(articleTitle) + '&url=' + articleUrl + '&ref=dzone.com&via=DZoneInc';
var win = window.open(twitter + params, '_blank');
win.focus();
}
retweetLink.addEventListener('click', retweet);
function showStatusMessage(options) {
var modal = document.getElementById('modal-message');
if(modal) {
modal.classList.add(options.type);
var modalBody = modal.querySelector('.modal-content .modal-body');
var modalHeader = modal.querySelector('.modal-content .modal-header');
modalHeader.innerText = options.header ? options.header : '';
modalBody.innerText = options.body ? options.body : '';
$(modal).modal('show');
$(modal).on('hidden.bs.modal', function () {
modal.classList.remove(options.type);
});
}
}
function showConfirmMessage(options) {
var modal = document.getElementById('modal-message');
if(modal) {
modal.classList.add(options.type);
var modalBody = modal.querySelector('.modal-content .modal-body');
var modalHeader = modal.querySelector('.modal-content .modal-header');
modalHeader.innerText = options.header ? options.header : '';
modalBody.innerText = options.body ? options.body : '';
if (options.textarea) {
var textareaDiv = document.createElement('div');
var textareaLabel = document.createElement('label');
textareaLabel.setAttribute('for', 'modal-textarea');
textareaLabel.innerText = options.textarea.label;
var textarea = document.createElement('textarea');
textarea.id = 'modal-textarea';
textarea.placeholder = (options.textarea.placeholder || '');
textarea.setAttribute('rows', (options.textarea.rows || 3));
textarea.classList.add('form-control', 'not-resizable');
if (options.textarea.maxlength) {
textarea.maxLength = options.textarea.maxlength;
}
textareaDiv.appendChild(textareaLabel);
textareaDiv.appendChild(textarea);
modalBody.appendChild(textareaDiv);
}
var btnContainer = document.createElement('div');
btnContainer.classList.add('btn-container');
var noBtn = document.createElement('button');
noBtn.innerText = options.noBtnText ? options.noBtnText : 'No';
noBtn.classList.add('no-btn');
var yesBtn = document.createElement('button');
yesBtn.innerText = options.yesBtnText ? options.yesBtnText : 'Yes';
yesBtn.classList.add('yes-btn');
btnContainer.appendChild(noBtn);
btnContainer.appendChild(yesBtn);
modalBody.appendChild(btnContainer);
$(modal).modal('show');
$(noBtn).one('click', function() {
$(modal).modal('hide');
if(options.noCallback) {
$(modal).one('hidden.bs.modal', function () {
options.noCallback();
});
}
});
$(yesBtn).one('click', function() {
$(modal).modal('hide');
if(options.yesCallback) {
$(modal).one('hidden.bs.modal', function () {
options.yesCallback();
});
}
});
$(modal).on('hidden.bs.modal', function () {
modal.classList.remove(options.type);
});
}
}
function getSuspensionBody() {
return 'We regret to inform you that your DZone account has been suspended for violating our Guidelines. ' +
'Please reach out to editors@dzone.com if you would like additional information.';
}</script>
<style>.engagement-overlay {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgb(0, 0, 0, 0.5);
z-index: 10000;
}
.engagement-modal {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
z-index: 10;
width: 100%;
height: 100%;
}
.engagement-modal .inner {
background-color: white;
border-radius: 0.5em;
margin: auto;
border: 1px solid #cccccc;
}
.engagement-modal .header {
padding: 20px 50px 10px 30px;
position: relative;
}
.engagement-modal .title {
font-size: 20px;
font-weight: bold;
color: #333333;
}
.engagement-modal .title:hover {
text-decoration: none;
}
.engagement-modal .close {
font-size: 18px;
position: absolute;
top: 18px;
right: 20px;
width: 32px;
height: 32px;
background: none;
border: none;
opacity: 0.8;
font-weight: bold;
text-shadow: 0 1px 0 #fff;
}
.engagement-modal .close:hover {
background-color: rgba(146, 148, 151, 0.2);
color: #000;
border-radius: 50%;
}
.engagement-modal .close:after {
content: '\2715';
}
.engagement-modal .content {
padding: 0 30px 20px;
width: min(450px, 90vw);
height: min(450px, 90vw);
scrollbar-width: thin;
overflow: auto;
overscroll-behavior: contain;
}
.engagement-modal .loading-screen,
.engagement-modal .content .center-screen {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
font-size: 18px;
}
.engagement-modal .content .center-screen a {
color: var(--acc-ffffff-blue-1);
font-weight: bold;
}
.engagement-modal .loading-screen i {
font-size: 24px;
}
.engagement-modal .media-left,
.engagement-modal .media-right {
display: table-cell;
vertical-align: top;
}
.engagement-modal .media-left {
padding-right: 10px;
}
.engagement-modal .media-right {
padding-left: 10px;
}
.engagement-modal .media a {
color: black;
font-size: 16px;
}
.engagement-modal .avatar {
border-radius: 50%;
}
.engagement-modal .footer {
margin: 20px 0 0;
display: flex;
justify-content: center;
align-items: center;
background-color: unset !important;
border-top: none !important;
}
.engagement-modal .footer .btn {
border: 1px solid transparent;
}
.engagement-modal .footer .btn-primary {
color: #fff;
border-color: #2e6da4;
}
.engagement-modal .footer button {
background-color: var(--acc-ffffff-blue-2);
padding: 6px 12px;
border-radius: 4px;
}
.engagement-modal .footer button:hover {
filter: brightness(1.2);
}
@keyframes anim-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
.engagement-modal .anim-spin {
display: inline-block;
animation: anim-spin 2s infinite linear;
}</style>
<script>document.addEventListener('alpine:init', () => {
Alpine.data('engagementModal', (nodeId) => ({
nodeId: null,
init() {
this.nodeId = nodeId;
},
open() {
this.updateStore();
this.$store.article.engagement.open = true;
if (this.$store.article.engagement.page === 1 && !this.$store.article.engagement.unauthorized) {
this.$store.article.engagement.initializing = true;
this.fetchEngagements();
}
},
close() {
if (this.$store.article.engagement.open) {
this.$store.article.engagement.open = false;
}
},
updateStore() {
if (this.nodeId !== this.$store.article.id) {
this.$store.article.engagement.reset();
this.$store.article.id = this.nodeId;
}
},
fetchEngagements() {
if (this.$store.article.engagement.loading || !this.$store.article.engagement.additional) {
return;
}
this.$store.article.engagement.loading = true;
this.$store.global.getFromService('/services/nodes/' + this.$store.article.id + '/engagements?page=' + this.$store.article.engagement.page)
.then(res => {
res.json().then(data => {
for (let user of data.engagements) {
this.$store.article.engagement.users.push(user);
}
this.$store.article.engagement.additional = data.additional;
this.$store.article.engagement.page++;
});
})
.catch(err => {
err.json().then(data => {
if (data.error?.code === 4011) {
this.$store.article.engagement.unauthorized = true;
} else {
this.$store.modal_engagement_error.open();
}
});
})
.finally(() => {
// Allow the loader to gracefully exit
setTimeout(() => {
this.$store.article.engagement.loading = false;
this.$store.article.engagement.initializing = false;
}, 200);
});
},
formatJobData(user) {
if (user.profile.jobTitle && user.profile.companyName) {
return user.profile.jobTitle + ', ' + user.profile.companyName;
}
if (user.profile.jobTitle) {
return user.profile.jobTitle;
}
if (user.profile.companyName) {
return user.profile.companyName;
}
return null;
},
isDataUnavailable() {
return !this.$store.article.engagement.initializing && !this.$store.article.engagement.users.length;
},
isFooterShowing() {
return !this.$store.article.engagement.initializing
&& this.$store.article.engagement.additional
&& this.$store.article.engagement.page > 1;
}
}));
});
</script>
<div class="alpine-overlay" x-cloak x-show="$store.modal_engagement_error._open">
<div id="modal_engagement_error"
class="alpine-modal"
role="dialog"
tabindex="-1"
x-show="$store.modal_engagement_error._open"
x-on:click.self="$store.modal_engagement_error.dismissible && $store.modal_engagement_error.close()"
x-cloak
x-transition
>
<div class="dz-style modal-inner centered relative">
<button x-show="$store.modal_engagement_error.closeable"
class="btn-close"
x-on:click="$store.modal_engagement_error.close()"
aria-label="Close">
</button>
<div x-show="$store.modal_engagement_error.title" class="modal-header p-sm mt-sm mb-md">
<div class="title " x-text="$store.modal_engagement_error.title"></div>
</div>
<div class="modal-content py-md px-lg" x-bind:class="{ 'has-top-border': $store.modal_engagement_error.title }">
<p x-show="$store.modal_engagement_error.bodyText" class="my-none" x-text="$store.modal_engagement_error.bodyText"></p>
<p>The likes didn't load as expected. Please refresh the page and try again.</p>
</div>
<div x-show="$store.modal_engagement_error.options.length" class="modal-footer p-sm">
<template x-for="option in $store.modal_engagement_error.options">
<button x-show="option.canDisplay" x-text="option.text"
type="button"
x-bind:id="'button_modal_engagement_error_' + option.index"
x-bind:class="option.classList"
x-on:click="option.onClick"
x-bind:disabled="option.isDisabled"
></button>
</template>
</div>
</div>
</div>
</div>
<script>
document.addEventListener("alpine:init", () => {
Alpine.store("modal_engagement_error", {
_open: false,
title: "Oops! Something Went Wrong",
bodyText: null,
options: [{"action":"dismiss","text":"Close"}],
closeable: true,
dismissible: true,
open(data) {
if (data) {
if (data.title) {
this.title = data.title;
}
if (data.bodyText) {
this.bodyText = data.bodyText;
}
if (data.options) {
this.options = data.options;
}
if (data.dismissAfterMs) {
setTimeout(() => this._open = false, data.dismissAfterMs);
}
}
this.updateOptions();
this._open = true;
},
close() {
// Manually click the buttons in which should run on dismiss.
// This is to keep the context. Calling this[option.action]() will not work.
for (let option of this.options) {
if (option.runOnDismiss) {
const element = document.querySelector('#button_modal_engagement_error_' + option.index);
element.click();
}
}
this._open = false;
},
updateOptions() {
const btnStyle = this.options.length === 2 ? ' btn-default' : '';
this.options = this.options.map((o, idx) => ({
...o,
index: idx,
classList: o.classList ? o.classList : (idx === 0 ? "btn btn-primary hov-brighten" : "btn hov-underline" + btnStyle),
onClick: function() {
if (o.action !== "dismiss") {
this[o.action]();
}
this.$store["modal_engagement_error"].close();
},
isDisabled: function() {
return Object.hasOwn(o, 'disabled') && this[o.disabled]();
},
canDisplay: function() {
return !Object.hasOwn(o, 'condition') || this[o.condition]();
}
}));
},
init() {
this.updateOptions();
}
});
});
</script>
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/footer/styles.css">
<div id="ftl-footer">
<div class="container-fluid footerOuter" style="padding-bottom: 90px;">
<div class="row">
<div class="col-md-12">
<div class="container">
<div class="row footer">
<div class="col-md-12 footerWidget">
<div class="row footerContainer footer">
<div class="left col-xs-12 col-sm-7">
<div class="col-xs-12 social-media-icons footer-mobile">
<ul class="icons-only">
<li class="rss-icon" id="rss-footer-1">
<a href="/pages/feeds" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" class="w-4 h-4 mt-1.75 fill-current" aria-label="Follow our RSS feeds">
<title>RSS</title>
<path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"></path>
</svg>
</a>
</li>
<li class="twitter-icon">
<a href="https://twitter.com/DZoneInc" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on X">
<title>X</title>
<path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"></path>
</svg>
</a>
</li>
<li class="facebook-icon">
<a href="https://www.facebook.com/DZoneInc" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on Facebook">
<title>Facebook</title>
<path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"></path>
</svg>
</a>
</li>
<li class="linkedin-icon">
<a href="https://www.linkedin.com/company/dzone/" target="_blank"
rel="noreferrer noopener">
<svg viewBox="0 0 24 25" fill="none" aria-label="Follow us on LinkedIn">
<path d="M6.20062 21.2143H1.84688V7.194H6.20062V21.2143ZM4.02141 5.2815C2.62922 5.2815 1.5 4.12838 1.5 2.73619C1.5 2.06747 1.76565 1.42614 2.2385 0.953285C2.71136 0.48043 3.35269 0.214783 4.02141 0.214783C4.69012 0.214783 5.33145 0.48043 5.80431 0.953285C6.27716 1.42614 6.54281 2.06747 6.54281 2.73619C6.54281 4.12838 5.413 5.2815 4.02141 5.2815ZM22.4953 21.2143H18.1509V14.3893C18.1509 12.7628 18.1181 10.6768 15.8873 10.6768C13.6237 10.6768 13.2769 12.444 13.2769 14.2721V21.2143H8.92781V7.194H13.1034V9.1065H13.1644C13.7456 8.00494 15.1655 6.84244 17.2838 6.84244C21.69 6.84244 22.5 9.744 22.5 13.5128V21.2143H22.4953Z" fill="currentColor"></path>
</svg>
</a>
</li>
</ul>
</div>
<div class="top-section col-xs-12">
<div class="col-xs-12 col-sm-6">
<p class="section-header">ABOUT US</p>
<ul class="link-group">
<li><a href="/pages/about" rel="noreferrer noopener">About DZone</a></li>
<li><a href="/cdn-cgi/l/email-protection#4e3d3b3e3e213c3a0e2a3421202b602d2123" rel="noreferrer noopener">Support and feedback</a></li>
<li><a href="/pages/dzone-community-research">Community research</a></li>
</ul>
</div>
<div class="col-xs-12 col-sm-6">
<p class="section-header">ADVERTISE</p>
<ul class="link-group">
<li><a href="https://advertise.dzone.com" target="_blank" rel="noreferrer noopener">Advertise with DZone</a></li>
</ul>
</div>
</div>
<div class="bottom-section col-xs-12">
<div class="col-xs-12 col-sm-6">
<p class="section-header">CONTRIBUTE ON DZONE</p>
<ul class="bottom-top-list link-group">
<li><a href="/articles/dzones-article-submission-guidelines">Article Submission Guidelines</a></li>
<li><a href="/pages/contribute" rel="noreferrer noopener">Become a Contributor</a></li>
<li><a href="/pages/core" rel="noreferrer noopener">Core Program</a></li>
<li><a href="/writers-zone" rel="noreferrer noopener">Visit the Writers' Zone</a></li>
</ul>
<p class="section-header">LEGAL</p>
<ul class="link-group">
<li><a href="https://technologyadvice.com/terms-conditions/" target="_blank" rel="noreferrer noopener">Terms of Service</a></li>
<li><a href="https://technologyadvice.com/privacy-policy/" target="_blank" rel="noreferrer noopener">Privacy Policy</a></li>
</ul>
</div>
<div class="col-xs-12 col-sm-6">
<p class="section-header">CONTACT US</p>
<ul class="link-group">
<li>3343 Perimeter Hill Drive</li>
<li>Suite 215</li>
<li>Nashville, TN 37211</li>
<li><a href="/cdn-cgi/l/email-protection#f5868085859a8781b5918f9a9b90db969a98" rel="noreferrer noopener"><span class="__cf_email__" data-cfemail="7c0f090c0c130e083c1806131219521f1311">[email&#160;protected]</span></a></li>
</ul>
</div>
</div>
</div>
<div class="right col-xs-12 col-sm-5">
<p class="connect-text">Let's be friends:</p>
<div class="col-xs-12 social-media-icons footer-wide">
<ul class="icons-only">
<li class="rss-icon" id="rss-footer-1">
<a href="/pages/feeds" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow our RSS feeds">
<title>RSS</title>
<path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"></path>
</svg>
</a>
</li>
<li class="twitter-icon">
<a href="https://twitter.com/DZoneInc" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on X">
<title>X</title>
<path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"></path>
</svg>
</a>
</li>
<li class="facebook-icon">
<a href="https://www.facebook.com/DZoneInc" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on Facebook">
<title>Facebook</title>
<path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"></path>
</svg>
</a>
</li>
<li class="linkedin-icon">
<a href="https://www.linkedin.com/company/dzone/" target="_blank"
rel="noreferrer noopener">
<svg viewBox="0 0 24 25" fill="none" aria-label="Follow us on LinkedIn">
<path d="M6.20062 21.2143H1.84688V7.194H6.20062V21.2143ZM4.02141 5.2815C2.62922 5.2815 1.5 4.12838 1.5 2.73619C1.5 2.06747 1.76565 1.42614 2.2385 0.953285C2.71136 0.48043 3.35269 0.214783 4.02141 0.214783C4.69012 0.214783 5.33145 0.48043 5.80431 0.953285C6.27716 1.42614 6.54281 2.06747 6.54281 2.73619C6.54281 4.12838 5.413 5.2815 4.02141 5.2815ZM22.4953 21.2143H18.1509V14.3893C18.1509 12.7628 18.1181 10.6768 15.8873 10.6768C13.6237 10.6768 13.2769 12.444 13.2769 14.2721V21.2143H8.92781V7.194H13.1034V9.1065H13.1644C13.7456 8.00494 15.1655 6.84244 17.2838 6.84244C21.69 6.84244 22.5 9.744 22.5 13.5128V21.2143H22.4953Z" fill="currentColor"></path>
</svg>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script>
const articleId = 3540645;
const likes = 5;
const assetDomain = 'https://dz2cdn1.dzone.com';
const codemirrorVars = {
modeURI: 'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/mode/',
requiredScripts: [
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/lib/codemirror.js',
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/addon/mode/overlay.js',
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/addon/mode/multiplex.js',
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/mode/meta.js'
]
};
const gptTags = {
'zone': 'Databases',
'topicTag': 'Database,shard,data type',
'company': '',
'siteSection': 'Zones',
'articleCategory': 'tutorial',
'nodeID': '3540645',
'authorID': '5280786',
'publishYear': '2025',
'publishMonth': '03',
'jobRole': '',
'companySize': '',
'env': 'prod'
};
const minCommentChar = 10;
</script>
<script async>const width = window.innerWidth;
const metadata = {
'top': {
'position': 'top',
'slot': 'dz2_article_billboard_new',
},
'sponsorLogo': {
'position': 'zoneHomepage',
'slot': 'dz2_homepage_sponsor_logo',
'refreshable': false
},
'sidebar1': {
'position': 'sidebar',
'slot': 'dz2_article_halfpage_new',
'minWidthToShow': 1024
},
'topBumper': {
'position': 'top',
'slot': 'dz2_bumper_text_ad',
'minWidthToShow': 1024
},
'bottomBumper': {
'position': 'bottom',
'slot': 'dz2_bumper_text_ad',
'minWidthToShow': 1024
},
'bottom': {
'position': 'bottom',
'slot': 'dz2_article_bottom',
},
'bottomStickyFooter': {
'position': 'sticky',
'slot': 'dz2_sticky_footer_leaderboard',
},
'partner': {
'slot': 'dz2_partner_resource_link',
},
'branded': {
'slot': 'dz2_branded_content',
'refreshable': false
},
'topicBillboard': {
'position': ['top', 'zoneHomepage'],
'slot': 'dz2_topic_billboard',
},
'listPageSidebar': {
'position': 'sidebar',
'slot': 'dz2_list_page_sidebar',
'minWidthToShow': 1024
},
'topListPageLeaderboard2': {
'position': ['top', 'zoneList'],
'slot': 'dz2_list_page_leaderboard_2',
},
'bottomListPageLeaderboard2': {
'position': ['bottom', 'zoneList'],
'slot': 'dz2_list_page_leaderboard_2',
},
'homepageLeaderboard': {
'position': 'top',
'slot': 'dz2_homepage_leaderboard',
},
'homepageLeaderboard2': {
'position': 'bottom',
'slot': 'dz2_homepage_leaderboard_2',
},
'skybox': {
'position': 'above nav',
'slot': 'dz_skybox',
'refreshable': false
},
'inline': {
'position': 'inline',
'slot': 'dz2_inline-article-display',
}
};
var campaign = new URLSearchParams(window.location.search).get("adTargeting_campaign");
window.googletag = window.googletag || { cmd: [] };
if (campaign) {
window.googletag.cmd.push(function() {
window.googletag.setConfig({ targeting: { campaign }});
});
}
let lastHeader = null;
const topContainer = document.querySelector('#top-bumper-container');
const bottomContainer = document.querySelector('#bottom-bumper-container');
function GAM_getPersistentValue(key) {
const stored = JSON.parse(localStorage.getItem(key));
if (!stored) {
return null;
}
const { value, expiration } = stored;
if (expiration && Date.now() >= expiration) {
localStorage.removeItem(key);
return null;
}
return value;
}
function GAM_setPersistentValue(key, value, expiration) {
// 5 minutes from now
if (!expiration) {
expiration = Date.now() + 300000;
}
const storedValue = JSON.stringify({
value: value,
expiration: expiration
});
localStorage.setItem(key, storedValue);
return value;
}
function GAM_synchronousRequest(params) {
const xhr = new XMLHttpRequest();
xhr.open('GET', params.url, false);
xhr.setRequestHeader("Content-Type", "application/json");
if (typeof params.auth_header !== "undefined") {
xhr.setRequestHeader("Authorization", params.auth_header);
}
xhr.send(null);
if (xhr.status === 200) {
return xhr.responseText;
} else {
throw new Error('Request failed: ' + xhr.statusText);
}
}
function GAM_fetch_data(params) {
let stored_data = GAM_getPersistentValue(params.storage_key);
if (stored_data === null) {
try {
const response = GAM_synchronousRequest(params);
const data = JSON.parse(response);
// Store and expire after 30 minutes
return GAM_setPersistentValue(params.storage_key, data, Date.now() + 1800000);
} catch (error) {
console.error('Could not get ' + params.storage_key + ' data: ' + error);
return null;
}
} else {
return stored_data;
}
}
function GAM_setUpSixSenseTargeting() {
let meData = GAM_fetch_data({
url: "https://link.technologyadvice.com/_me",
storage_key: "ta_me_data"
});
let sixSenseData = GAM_fetch_data({
url: "https://epsilon.6sense.com/v3/company/details",
auth_header: "Token d20a1b0e892442270cbc4cb6801c0160d28af04c",
storage_key: "ta_6s_data"
});
function meDataIncludes(i) {
return meData.tags.includes(i);
}
if (typeof meData !== "undefined" && meData !== null) {
window.googletag.pubads().setTargeting("visitor_id", meData.vid);
window.googletag.pubads().setTargeting("user_agent", meData.user_agent);
var tags_mapping = {
"is_datacenter": ["site.is-datacenter"],
"is_suspected_bot": ["site.suspected-bad-bot", "site.bad-bot"],
"is_ta_user": ["site.is-ta-user"],
"is_crawler": ["site.user-agent-blocked"],
"is_ad_blocked": ["site.is-ad-blocked"],
};
for (var key in tags_mapping) {
if (tags_mapping[key].some(meDataIncludes)) {
window.googletag.pubads().setTargeting(key, 'true');
}
}
}
if (typeof sixSenseData !== "undefined" && sixSenseData !== null) {
var segment_ids = [];
if (sixSenseData.segments && sixSenseData.segments.ids && sixSenseData.segments.ids.length) {
sixSenseData.segments.ids.forEach(function (v) {
segment_ids.push(v.toString());
});
}
if (typeof segment_ids !== "undefined" && segment_ids.length > 0) {
window.googletag.pubads().setTargeting("segment_ids_6si", segment_ids);
}
}
}
if (width >= 1024 && (topContainer || bottomContainer)) {
// Dynamically create bumper ad slots for non-mobile devices.
// Prevents ugly dividers being rendered on empty ad slots (mobile)
const topBumper = document.createElement('div');
topBumper.id = 'div-gpt-ad-1435246566686-3';
topBumper.classList.add('article-bumper', 'article-bumper-top', 'dz2_bumper_text_ad');
topBumper.setAttribute('data-gpt-slot', 'topBumper');
topContainer.appendChild(topBumper);
const bottomBumper = document.createElement('div');
bottomBumper.id = 'div-gpt-ad-1435246566686-4';
bottomBumper.classList.add('article-bumper', 'article-bumper-bottom', 'dz2_bumper_text_ad');
bottomBumper.setAttribute('data-gpt-slot', 'bottomBumper');
bottomContainer.appendChild(bottomBumper);
}
if (gptTags.zone) {
gptTags.zone = gptTags.zone.replaceAll(/[\s/]/g, '_')
.replaceAll(/[^a-zA-Z0-9_]/g, '')
.toLowerCase();
}
makeAds();
function handleSkybox() {
const skybox = document.querySelector('div.skybox');
if (skybox) {
document.body.classList.add('skybox-auto-collapse');
// observe classlist changes for offsetting sticky ads
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
let offset = 0;
if (!document.body.classList.contains('skybox-closed') && (
document.body.classList.contains('ccad-skybox-manualcollapse')
|| document.body.classList.contains('ccad-skybox-manualexpand')
)) {
offset = skybox.getBoundingClientRect().height;
}
let eligibleAds = [
{ element: document.querySelector('.content-right-images'), offset: 108 },
{ element: document.querySelector('.trending-sidebar'), offset: 88 },
{ element: document.querySelector('.trending'), offset: 88 }
];
for (let ad of eligibleAds) {
if (ad.element) {
ad.element.style.top = (ad.offset + offset) + 'px';
}
}
}
});
});
observer.observe(document.body, { attributes: true });
}
}
function isHeaderEligible(header) {
const range = document.createRange();
range.setStartAfter(lastHeader);
range.setEndBefore(header);
return range.toString().trim().length >= 600;
}
function placeInlineAds() {
const excludedContent = document.querySelectorAll('#ftl-article.branded-content, #ftl-article.sponsored');
if (excludedContent.length > 0) {
return;
}
const headers = Array.from(document.querySelectorAll('.content-html h2')).splice(1);
let globalIndex = 12;
for (let i = 0; i < headers.length; i++) {
if (!lastHeader || isHeaderEligible(headers[i])) {
const element = document.createElement('div');
element.id = 'div-gpt-ad-1435246566686-' + globalIndex;
element.classList.add('inline-display', 'dz2_inline-article-display');
element.setAttribute('data-gpt-slot', 'inline');
headers[i].before(element);
lastHeader = element;
globalIndex++;
}
}
}
function makeAds() {
handleSkybox();
placeInlineAds();
const script = document.createElement('script');
script.src = 'https://i6ByW9Zmz4ncxhHkb.ay.delivery/manager/i6ByW9Zmz4ncxhHkb';
script.type = 'text/javascript';
script.referrerPolicy = 'no-referrer-when-downgrade';
document.head.appendChild(script);
window.googletag.cmd.push(function() {
const containers = document.querySelectorAll('div[data-gpt-slot]');
for (let container of containers) {
const div = container.getAttribute('data-gpt-slot');
const meta = metadata[div];
if (meta.minWidthToShow && width < meta.minWidthToShow) {
continue;
}
window.googletag.pubads().setTargeting('hostname', window.location.hostname);
Object.keys(gptTags).forEach(function(key) {
window.googletag.pubads().setTargeting(key, gptTags[key]);
});
window.googletag.pubads().addEventListener('slotRenderEnded', (event) => {
window.requestAnimationFrame(() => {
var slotId = event.slot.getSlotElementId();
if (!slotId.includes('__ayManagerEnv__')) {
return;
}
var className = slotId.split('__ayManagerEnv__')[0];
var slotName = className.replace('dz2_', '').replace('dz_', '').replace(/_\d+$/, '');
var unitName = meta.slot.replace('dz2_', '').replace('dz_', '').replace(/_\d+$/, '');
if (slotName !== unitName) {
return;
}
var elem = document.getElementById(slotId);
if (!elem) {
console.warn('Ad element missing', slotId);
return;
}
// Ad unit did not fill, collapse slot
if (event.isEmpty && elem.parentElement) {
elem.parentElement.style.display = 'none';
}
});
});
}
GAM_setUpSixSenseTargeting();
});
}
</script>
<script async>// InMobi Choice. Consent Manager Tag v3.0 (for TCF 2.2)
!function(){var e=window.location.hostname,t=document.createElement("script"),n=document.getElementsByTagName("script")[0],a="https://cmp.inmobi.com".concat("/choice/","vPn77x7pBG57Y","/","dzone.com","/choice.js?tag_version=V3"),p=0;t.async=!0,t.type="text/javascript",t.src=a,n.parentNode.insertBefore(t,n),function(){for(var e,t="__tcfapiLocator",n=[],a=window;a;){try{if(a.frames[t]){e=a;break}}catch(e){}if(a===window.top)break;a=a.parent}e||(!function e(){var n=a.document,p=!!a.frames[t];if(!p)if(n.body){var s=n.createElement("iframe");s.style.cssText="display:none",s.name=t,n.body.appendChild(s)}else setTimeout(e,5);return!p}(),a.__tcfapi=function(){var e,t=arguments;if(!t.length)return n;if("setGdprApplies"===t[0])t.length>3&&2===t[2]&&"boolean"==typeof t[3]&&(e=t[3],"function"==typeof t[2]&&t[2]("set",!0));else if("ping"===t[0]){var a={gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"};"function"==typeof t[2]&&t[2](a)}else"init"===t[0]&&"object"==typeof t[3]&&(t[3]=Object.assign(t[3],{tag_version:"V3"})),n.push(t)},a.addEventListener("message",(function(e){var t="string"==typeof e.data,n={};try{n=t?JSON.parse(e.data):e.data}catch(e){}var a=n.__tcfapiCall;a&&window.__tcfapi(a.command,a.version,(function(n,p){var s={__tcfapiReturn:{returnValue:n,success:p,callId:a.callId}};t&&(s=JSON.stringify(s)),e&&e.source&&e.source.postMessage&&e.source.postMessage(s,"*")}),a.parameter)}),!1))}(),function(){const e=["2:tcfeuv2","6:uspv1","7:usnatv1","8:usca","9:usvav1","10:uscov1","11:usutv1","12:usctv1"];window.__gpp_addFrame=function(e){if(!window.frames[e])if(document.body){var t=document.createElement("iframe");t.style.cssText="display:none",t.name=e,document.body.appendChild(t)}else window.setTimeout(window.__gpp_addFrame,10,e)},window.__gpp_stub=function(){var t=arguments;if(__gpp.queue=__gpp.queue||[],__gpp.events=__gpp.events||[],!t.length||1==t.length&&"queue"==t[0])return __gpp.queue;if(1==t.length&&"events"==t[0])return __gpp.events;var n=t[0],a=t.length>1?t[1]:null,p=t.length>2?t[2]:null;if("ping"===n)a({gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}},!0);else if("addEventListener"===n){"lastId"in __gpp||(__gpp.lastId=0),__gpp.lastId++;var s=__gpp.lastId;__gpp.events.push({id:s,callback:a,parameter:p}),a({eventName:"listenerRegistered",listenerId:s,data:!0,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}}},!0)}else if("removeEventListener"===n){for(var i=!1,o=0;o<__gpp.events.length;o++)if(__gpp.events[o].id==p){__gpp.events.splice(o,1),i=!0;break}a({eventName:"listenerRemoved",listenerId:p,data:i,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}}},!0)}else"hasSection"===n?a(!1,!0):"getSection"===n||"getField"===n?a(null,!0):__gpp.queue.push([].slice.apply(t))},window.__gpp_msghandler=function(e){var t="string"==typeof e.data;try{var n=t?JSON.parse(e.data):e.data}catch(e){n=null}if("object"==typeof n&&null!==n&&"__gppCall"in n){var a=n.__gppCall;window.__gpp(a.command,(function(n,p){var s={__gppReturn:{returnValue:n,success:p,callId:a.callId}};e.source.postMessage(t?JSON.stringify(s):s,"*")}),"parameter"in a?a.parameter:null,"version"in a?a.version:"1.1")}},"__gpp"in window&&"function"==typeof window.__gpp||(window.__gpp=window.__gpp_stub,window.addEventListener("message",window.__gpp_msghandler,!1),window.__gpp_addFrame("__gppLocator"))}();var s=function(){var e=arguments;typeof window.__uspapi!==s&&setTimeout((function(){void 0!==window.__uspapi&&window.__uspapi.apply(window.__uspapi,e)}),500)};if(void 0===window.__uspapi){window.__uspapi=s;var i=setInterval((function(){p++,window.__uspapi===s&&p<3?console.warn("USP is not accessible"):clearInterval(i)}),6e3)}}();
</script>
<script async>
(function(w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j,f);
})(window, document, 'script', 'dataLayer', 'GTM-K25QL22');
</script>
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-410289-1', 'auto');
ga('require', 'linkid', 'linkid.js');
ga('require', 'GTM-TSD9TZP');
ga('set', 'siteSpeedSampleRate', 25);
</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>
<script async>var analytics = {
'dimension1': 'Databases',
'dimension2': 'article/tutorial',
'dimension3': '2025-03-26',
'dimension4': '0',
'dimension5': '',
'dimension7': 'Database, shard, data type',
'dimension8': 'udayabaski',
'dimension9': 'undefined',
'dimension10': 'Apple Inc'
};
if (window.ga) {
Object.keys(analytics).forEach(function(key) {
window.ga('set', key, analytics[key]);
});
window.ga('send', 'pageview');
}</script>
<script src="https://dz2cdn1.dzone.com/themes/dz20/lib/static/jquery/jquery.min.js"></script>
<script async src="https://dz2cdn1.dzone.com/themes/dz20/lib/static/bootstrap/bootstrap.min.js"></script>
<script>
function loadScript(src) {
return new Promise(function (resolve, reject) {
const s = document.createElement('script');
s.src = src;
s.onload = resolve;
s.onerror = reject;
document.head.appendChild(s);
});
}
function loadStyle(href) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}
function loadScriptsSync(deferred) {
var p = Promise.resolve();
for (var i = 0; i < deferred.length; i++) {
let script = deferred[i];
p = p.then(function() {
return loadScript(script);
});
}
return p;
}
function loadStyles() {
const deferred = [
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/lib/codemirror.css',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/comments/styles.css',
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/css/froala_editor.pkgd.min.css',
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/css/themes/gray.min.css',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/mini-profile.css'
];
for (var i = 0; i < deferred.length; i++) {
loadStyle(deferred[i]);
}
}
window.addEventListener('load', function(_event) {
loadStyles();
loadScriptsSync([
'https://dz2cdn1.dzone.com/themes/dz20/lib/lazysizes.min.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/codeblocks.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/activity-bar.js',
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/js/froala_editor.pkgd.min.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/froala/content.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/comments/content.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/content.js'
]);
});
</script>
</body>
</html>