blob: ef6ace1bd0db4aac3e99a2270eb1ff20bd7aff85 [file] [log] [blame]
<!doctype html>
<html lang="zh-Hans-CN" dir="ltr" class="blog-wrapper blog-post-page plugin-blog plugin-id-default" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<meta name="generator" content="Docusaurus v2.4.3">
<link rel="alternate" type="application/rss+xml" href="/zh-CN/blog/rss.xml" title="Apache Doris RSS Feed">
<link rel="alternate" type="application/atom+xml" href="/zh-CN/blog/atom.xml" title="Apache Doris Atom Feed">
<link rel="preconnect" href="https://www.google-analytics.com">
<link rel="preconnect" href="https://www.googletagmanager.com">
<script async src="https://www.googletagmanager.com/gtag/js?id=G-DT7W9E9722"></script>
<script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-DT7W9E9722",{anonymize_ip:!0})</script>
<link rel="preconnect" href="https://analytics.apache.org/">
<script>var _paq=window._paq=window._paq||[];_paq.push(["setRequestMethod","POST"]),_paq.push(["trackPageView"]),_paq.push(["enableLinkTracking"]),_paq.push(["enableHeartBeatTimer"]),function(){var e="https://analytics.apache.org/";_paq.push(["setRequestMethod","POST"]),_paq.push(["setTrackerUrl",e+"matomo.php"]),_paq.push(["setSiteId","43"]);var a=document,t=a.createElement("script"),p=a.getElementsByTagName("script")[0];t.type="text/javascript",t.async=!0,t.src=e+"matomo.js",p.parentNode.insertBefore(t,p)}()</script>
<link rel="icon" href="/zh-CN/images/logo-only.png">
<link rel="manifest" href="/zh-CN/manifest.json">
<meta name="theme-color" content="#FFFFFF">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#000">
<link rel="apple-touch-icon" href="/zh-CN/img/docusaurus.png">
<link rel="mask-icon" href="/zh-CN/img/docusaurus.svg" color="rgb(37, 194, 160)">
<meta name="msapplication-TileImage" content="/zh-CN/img/docusaurus.png">
<meta name="msapplication-TileColor" content="#000">
<link rel="stylesheet" href="https://cdn-font.hyperos.mi.com/font/css?family=MiSans:100,200,300,400,450,500,600,650,700,900:Chinese_Simplify,Latin&display=swap">
<link rel="stylesheet" href="https://cdn-font.hyperos.mi.com/font/css?family=MiSans_Latin:100,200,300,400,450,500,600,650,700,900:Latin&display=swap">
<script src="/js/custom-script.js"></script><title data-rh="true">How We increased database query concurrency by 20 times - Apache Doris</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://doris.apache.org/zh-CN/blog/How-We-Increased-Database-Query-Concurrency-by-20-Times"><meta data-rh="true" name="docusaurus_locale" content="zh-CN"><meta data-rh="true" name="docusaurus_tag" content="default"><meta data-rh="true" name="docsearch:language" content="zh-CN"><meta data-rh="true" name="docsearch:docusaurus_tag" content="default"><meta data-rh="true" property="og:title" content="How We increased database query concurrency by 20 times - Apache Doris"><meta data-rh="true" name="description" content="In the upcoming Apache Doris 2.0, we have optimized it for high-concurrency point queries. Long story short, it can achieve over 30,000 QPS for a single node."><meta data-rh="true" property="og:description" content="In the upcoming Apache Doris 2.0, we have optimized it for high-concurrency point queries. Long story short, it can achieve over 30,000 QPS for a single node."><meta data-rh="true" property="og:image" content="https://doris.apache.org/zh-CN/images/how-we-increased-database-query-concurrency-by-20-times.jpg"><meta data-rh="true" name="twitter:image" content="https://doris.apache.org/zh-CN/images/how-we-increased-database-query-concurrency-by-20-times.jpg"><meta data-rh="true" property="og:type" content="article"><meta data-rh="true" property="article:published_time" content="2023-04-14T00:00:00.000Z"><meta data-rh="true" property="article:tag" content="Tech Sharing"><link data-rh="true" rel="icon" href="/zh-CN/images/favicon.ico"><link data-rh="true" rel="canonical" href="https://doris.apache.org/zh-CN/blog/How-We-Increased-Database-Query-Concurrency-by-20-Times"><link data-rh="true" rel="alternate" href="https://doris.apache.org/blog/How-We-Increased-Database-Query-Concurrency-by-20-Times" hreflang="en-US"><link data-rh="true" rel="alternate" href="https://doris.apache.org/zh-CN/blog/How-We-Increased-Database-Query-Concurrency-by-20-Times" hreflang="zh-Hans-CN"><link data-rh="true" rel="alternate" href="https://doris.apache.org/blog/How-We-Increased-Database-Query-Concurrency-by-20-Times" hreflang="x-default"><link rel="stylesheet" href="https://cdnd.selectdb.com/zh-CN/assets/css/styles.6c1d6100.css">
<link rel="preload" href="https://cdnd.selectdb.com/zh-CN/assets/js/runtime~main.ea863d93.js" as="script">
<link rel="preload" href="https://cdnd.selectdb.com/zh-CN/assets/js/main.bda5da23.js" as="script">
</head>
<body class="navigation-with-keyboard">
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}return t}()||function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}(),document.documentElement.setAttribute("data-announcement-bar-initially-dismissed",function(){try{return"true"===localStorage.getItem("docusaurus.announcement.dismiss")}catch(t){}return!1}())</script><div id="__docusaurus">
<div role="region" aria-label="跳到主要内容"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">跳到主要内容</a></div><div class="announcementBar_s0pr" style="background-color:#3C2FD4;color:#FFFFFF" role="banner"><div class="announcementBarPlaceholder_qxfj"></div><div class="announcementBarContent_dpRF"><a href="https://github.com/apache/doris" target="_blank" style="display: flex; width: 100%; align-items: center; justify-content: center; margin-left: 4px; text-decoration: none; color: white">Do you ❤️ Doris? Give us a 🌟 on GitHub
<img style="width: 1.2rem; height: 1.2rem; margin-left: 0.4rem;" src="/images/github-white-icon.svg">
</a></div><button type="button" class="clean-btn close announcementBarClose_iXyO" aria-label="关闭"><svg viewBox="0 0 15 15" width="14" height="14" style="color:white"><g stroke="currentColor" stroke-width="3.1"><path d="M.75.75l13.5 13.5M14.25.75L.75 14.25"></path></g></svg></button></div><nav aria-label="主导航" class="navbar navbar--fixed-top"><div class="navbar__inner" style="padding:"><div class="navbar__items"><div class="navbar-left"><div class="navbar-logo-wrapper flex items-center"><a class="navbar__brand" href="/zh-CN/"><div class="navbar__logo"><img src="https://cdnd.selectdb.com/images/logo.svg" alt="Apache Doris" class="themedImage_ToTc themedImage--light_HNdA"><img src="https://cdnd.selectdb.com/images/logo.svg" alt="Apache Doris" class="themedImage_ToTc themedImage--dark_i4oU"></div><b class="navbar__title text--truncate"></b></a></div><a class="navbar__item navbar__link" style="text-align:center" href="/zh-CN/docs/get-starting/quick-start">Docs</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" style="text-align:center" href="/zh-CN/blog">Blog</a><a class="navbar__item navbar__link" style="text-align:center" href="/zh-CN/users">Users</a><a href="https://github.com/apache/doris/discussions" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link" style="text-align:center">Discussions</a><a class="navbar__item navbar__link" style="text-align:center" href="/zh-CN/ecosystem/cluster-management">Ecosystem</a><a class="navbar__item navbar__link" style="text-align:center" href="/zh-CN/community/join-community">Community</a></div></div><div class="navbar__items navbar__items--right"><button aria-label="切换导航栏" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><div class="docs-search searchBox_H2mL"><div class="navbar__search searchBarContainer_PzyC"><input placeholder="搜索" aria-label="Search" class="navbar__search-input navbarSearchInput_tb6T"><div class="loadingRing__K5d searchBarLoadingRing_e2f0"><div></div><div></div><div></div><div></div></div><div class="searchHintContainer_m7ml"><kbd class="searchHint_zuPL">ctrl</kbd><kbd class="searchHint_zuPL">K</kbd></div></div></div><div class="custom-navbar-item navbar__item dropdown dropdown--hoverable dropdown--right"><a class="navbar__link" aria-haspopup="true" aria-expanded="false" role="button" href="/zh-CN/docs/get-starting/what-is-apache-doris"><span class="text-sm">Versions: </span></a><ul class="dropdown__menu"><li><a class="dropdown__link" style="text-align:center" href="/zh-CN/docs/dev/get-starting/what-is-apache-doris">dev</a></li><li><a class="dropdown__link" style="text-align:center" href="/zh-CN/docs/get-starting/what-is-apache-doris">2.1</a></li><li><a class="dropdown__link" style="text-align:center" href="/zh-CN/docs/2.0/get-starting/what-is-apache-doris">2.0</a></li><li><a class="dropdown__link" style="text-align:center" href="/zh-CN/docs/1.2/get-starting/">1.2</a></li></ul></div><a class="navbar__item navbar__link header-right-button-primary navbar-download-mobile" style="text-align:center" href="/zh-CN/download">Download</a><a href="https://github.com/apache/doris" target="_blank" rel="noopener noreferrer" class="github-btn desktop header-right-button-github"></a><a href="https://join.slack.com/t/apachedoriscommunity/shared_invite/zt-2kl08hzc0-SPJe4VWmL_qzrFd2u2XYQA" target="_blank" rel="noopener noreferrer" class="slack-btn desktop header-right-button-slack"></a><a class="header-right-button-primary navbar-download-desktop" href="/zh-CN/download">Download</a></div></div><div class="navbar__bottom"></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="main-wrapper mainWrapper_z2l0"><div role="region" aria-label="跳到主要内容"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">跳到主要内容</a></div><div class="main-wrapper"><div class="mb-[4.875rem] container"><div class="lg:row lg:flex"><main class="col col--9 col--offset-1" itemscope="" itemtype="http://schema.org/Blog"><article class="blog-article-content" itemprop="blogPost" itemscope="" itemtype="http://schema.org/BlogPosting"><header><div class="text-center mb-4"><a class="text-[#8592A6] cursor-pointer hover:no-underline" href="/zh-CN/blog">Blog</a><span class="px-2 text-[#8592A6]">/</span><span><span class="s-tags"><span class="s-tag">Tech Sharing</span></span></span></div><h1 class="blog-post-title text-[2rem] leading-normal lg:text-[2.5rem] text-center" itemprop="headline">How We increased database query concurrency by 20 times</h1><div class="blog-info text-center flex justify-center text-sm text-black"><span class="authors"><span class="s-author text-black">Apache Doris</span></span><time datetime="2023-04-14T00:00:00.000Z" itemprop="datePublished" class="text-black ml-4">2023年4月14日</time></div></header><div id="__blog-post-container" class="markdown" itemprop="articleBody"><p>A unified analytic database is the holy grail for data engineers, but what does it look like specifically? It should evolve with the needs of data users.</p><p>Vertically, companies now have an ever enlarging pool of data and expect a higher level of concurrency in data processing. Horizontally, they require a wider range of data analytics services. Besides traditional OLAP scenarios such as statistical reporting and ad-hoc queries, they are also leveraging data analysis in recommender systems, risk control, customer tagging and profiling, and IoT.</p><p>Among all these data services, point queries are the most frequent operations conducted by data users. Point query means to retrieve one or several rows from the database based on the Key. A point query only returns a small piece of data, such as the details of a shopping order, a transaction, a consumer profile, a product description, logistics status, and so on. Sounds easy, right? But the tricky part is, <strong>a database often needs to handle tens of thousands of point queries at a time and respond to all of them in milliseconds</strong>.</p><p>Most current OLAP databases are built with a columnar storage engine to process huge data volumes. They take pride in their high throughput, but often underperform in high-concurrency scenarios. As a complement, many data engineers invite Key-Value stores like Apache HBase for point queries, and Redis as a cache layer to ease the burden. The downside is redundant storage and high maintenance costs.</p><p>Since Apache Doris was born, we have been striving to make it a unified database for data queries of all sizes, including ad-hoc queries and point queries. Till now, we have already taken down the monster of high-throughput OLAP scenarios. In the upcoming Apache Doris 2.0, we have optimized it for high-concurrency point queries. Long story short, it can achieve over 30,000 QPS for a single node. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="five-ways-to-accelerate-high-concurrency-queries">Five Ways to Accelerate High-Concurrency Queries<a href="#five-ways-to-accelerate-high-concurrency-queries" class="hash-link" aria-label="Five Ways to Accelerate High-Concurrency Queries的直接链接" title="Five Ways to Accelerate High-Concurrency Queries的直接链接"></a></h2><p>High-concurrency queries are thorny because you need to handle high loads with limited system resources. That means you have to reduce the CPU, memory and I/O overheads of a single SQL as much as possible. The key is to minimize the scanning of underlying data and follow-up computing. </p><p>Apache Doris uses five methods to achieve higher QPS.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="partioning-and-bucketing">Partioning and Bucketing<a href="#partioning-and-bucketing" class="hash-link" aria-label="Partioning and Bucketing的直接链接" title="Partioning and Bucketing的直接链接"></a></h3><p>Apache Doris shards data into a two-tiered structure: Partition and Bucket. You can use time information as the Partition Key. As for bucketing, you distribute the data into various nodes after data hashing. A wise bucketing plan can largely increase concurrency and throughput in data reading. </p><p>This is an example:</p><div class="language-SQL codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-SQL codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">select * from user_table where id = 5122 and create_date = &#x27;2022-01-01&#x27;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>In this case, the user has set 10 buckets. <code>create_date</code> is the Partition Key and <code>id</code> is the Bucket Key. After dividing the data into partitions and buckets, the system only needs to scan one bucket in one partition before it can locate the needed data. This is a huge time saver.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="index">Index<a href="#index" class="hash-link" aria-label="Index的直接链接" title="Index的直接链接"></a></h3><p>Apache Doris uses various data indexes to speed up data reading and filtering, including smart indexes and secondary indexes. Smart indexes are auto-generated by Doris upon data ingestion, which requires no action from the user&#x27;s side. </p><p>There are two types of smart indexes:</p><ul><li><strong>Sorted Index</strong>: Apache Doris stores data in an orderly way. It creates a sorted index for every 1024 rows of data. The Key in the index is the value of the sorted column in the first row of the current 1024 rows. If the query involves the sorted column, the system will locate the first row of the relevant 1024 row group and start scanning there.</li><li><strong>ZoneMap Index</strong>: These are indexes on the Segment and Page level. The maximum and minimum values of each column within a Page will be recorded, so are those within a Segment. Hence, in equivalence queries and range queries, the system can narrow down the filter range with the help of the MinMax indexes.</li></ul><p>Secondary indexes are created by users. These include Bloom Filter indexes, Bitmap indexes, <a href="https://doris.apache.org/docs/dev/data-table/index/inverted-index/" target="_blank" rel="noopener noreferrer">Inverted indexes</a>, and <a href="https://doris.apache.org/docs/dev/data-table/index/ngram-bloomfilter-index/" target="_blank" rel="noopener noreferrer">NGram Bloom Filter indexes</a>. (If you are interested, I will go into details about them in future articles.)</p><p>Example:</p><div class="language-SQL codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-SQL codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">select * from user_table where id &gt; 10 and id &lt; 1024</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Suppose that the user has designated <code>id</code> as the Key during table creation, the data will be sorted by <code>id</code> on Memtable and the disks. So any queries involving <code>id</code> as a filter condition will be executed much faster with the aid of sorted indexes. Specifically, the data in storage will be put into multiple ranges based on <code>id</code>, and the system will implement binary search to locate the exact range according to the sorted indexes. But that could still be a large range since the sorted indexes are sparse. You can further narrow it down based on ZoneMap indexes, Bloom Filter indexes, and Bitmap indexes. </p><p>This is another way to reduce data scanning and improve overall concurrency of the system.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="materialized-view">Materialized View<a href="#materialized-view" class="hash-link" aria-label="Materialized View的直接链接" title="Materialized View的直接链接"></a></h3><p>The idea of materialized view is to trade space for time: You execute pre-computation with pre-defined SQL statements, and perpetuate the results in a table that is visible to users but occupies some storage space. In this way, Apache Doris can respond much faster to queries for aggregated data and breakdown data and those involve the matching of sorted indexes once it hits a materialized view. This is a good way to lessen computation, improve query performance, and reduce resource consumption.</p><div class="language-SQL codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-SQL codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">// For an aggregation query, the system reads the pre-aggregated columns in the materialized view.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">create materialized view store_amt as select store_id, sum(sale_amt) from sales_records group by store_id;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT store_id, sum(sale_amt) FROM sales_records GROUP BY store_id;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">// For a query where k3 matches the sorted column in the materialized view, the system directly performs the query on the materialized view. </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">CREATE MATERIALIZED VIEW mv_1 as SELECT k3, k2, k1 FROM tableA ORDER BY k3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">select k1, k2, k3 from table A where k3=3;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="runtime-filter">Runtime Filter<a href="#runtime-filter" class="hash-link" aria-label="Runtime Filter的直接链接" title="Runtime Filter的直接链接"></a></h3><p>Apart from filtering data by indexes, Apache Doris has a dynamic filtering mechanism: Runtime Filter. </p><p>In multi-table Join queries, the left table is usually called ProbeTable while the right one is called BuildTable, with the former much bigger than the latter. In query execution, firstly, the system reads the right table and creates a HashTable (Build) in the memory. Then, it starts reading the left table row by row, during which it also compares data between the left table and the HashTable and returns the matched data (Probe). </p><p>So what&#x27;s new about that in Apache Doris? During the creation of HashTable, Apache Doris generates a filter for the columns. It can be a Min/Max filter or an IN filter. Then it pushes down the filter to the left table, which can use the filter to screen out data and thus reduces the amount of data that the Probe node has to transfer and compare. </p><p>This is how the Runtime Filter works. In most Join queries, the Runtime Filter can be automatically pushed down to the most underlying scan nodes or to the distributed Shuffle Join. In other words, Runtime Filter is able to reduce data reading and shorten response time for most Join queries.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="top-n-optimization">TOP-N Optimization<a href="#top-n-optimization" class="hash-link" aria-label="TOP-N Optimization的直接链接" title="TOP-N Optimization的直接链接"></a></h3><p>TOP-N query is a frequent scenario in data analysis. For example, users want to fetch the most recent 100 orders, or the 5 highest/lowest priced products. The performance of such queries determines the quality of real-time analysis. For them, Apache Doris implements TOP-N optimization. Here is how it goes:</p><ol><li>Apache Doris reads the sorted fields and query fields from the Scanner layer, reserves only the TOP-N pieces of data by means of Heapsort, updates the real-time TOP-N results as it continues reading, and dynamically pushes them down to the Scanner. </li><li>Combing the received TOP-N range and the indexes, the Scanner can skip a large proportion of irrelevant files and data chunks and only read a small number of rows.</li><li>Queries on flat tables usually mean the need to scan massive data, but TOP-N queries only retrieve a small amount of data. The strategy here is to divide the data reading process into two stages. In stage one, the system sorts the data based on a few columns (sorted column, or condition column) and locates the TOP-N rows. In stage two, it fetches the TOP-N rows of data after data sorting, and then it retrieves the target data according to the row numbers. </li></ol><p>To sum up, Apache Doris prunes the data that needs to be read and sorted, and thus substantially reduces consumption of I/O, CPU, and memory resources.</p><p>In addition to the foregoing five methods, Apache Doris also improves concurrency by SQL Cache, Partition Cache, and a variety of Join optimization techniques.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-we-bring-concurrency-to-the-next-level">How We Bring Concurrency to the Next Level<a href="#how-we-bring-concurrency-to-the-next-level" class="hash-link" aria-label="How We Bring Concurrency to the Next Level的直接链接" title="How We Bring Concurrency to the Next Level的直接链接"></a></h2><p>By adopting the above methods, Apache Doris was able to achieve thousands of QPS per node. However, in scenarios requiring tens of thousands of QPS, it was still bottlenecked by several issues:</p><ul><li>With Doris&#x27; columnar storage engine, it was inconvenient to read rows. In flat table models, columnar storage could result in much larger I/O usage.</li><li>The execution engine and query optimizer of OLAP databases were sometimes too complicated for simple queries (point queries, etc.). Such queries needed to be processed with a shorter pipeline, which should be considered in query planning.</li><li>FE modules of Doris, implementing Java, were responsible for interfacing with SQL requests and parsing query plans. These processes could produce high CPU overheads in high-concurrency scenarios.</li></ul><p>We optimized Apache Doris to solve these problems. (<a href="https://github.com/apache/doris/pull/15491" target="_blank" rel="noopener noreferrer">Pull Request on Github</a>)</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="row-storage-format">Row Storage Format<a href="#row-storage-format" class="hash-link" aria-label="Row Storage Format的直接链接" title="Row Storage Format的直接链接"></a></h3><p>As we know, row storage is much more efficient when the user only queries for a single row of data. So we introduced row storage format in Apache Doris 2.0. Users can enable row storage by specifying the following property in the table creation statement.</p><div class="language-SQL codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-SQL codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;store_row_column&quot; = &quot;true&quot;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>We chose JSONB as the encoding format for row storage for three reasons:</p><ul><li><strong>Flexible schema change</strong>: If a user has added or deleted a field, or modified the type of a field, these changes must be updated in row storage in real time. So we choose to adopt the JSONB format and encode columns into JSONB fields. This makes changes in fields very easy.</li><li><strong>High performance</strong>: Accessing rows in row-oriented storage is much faster than doing that in columnar storage, and it requires much less disk access in high-concurrency scenarios. Also, in some cases, you can map the column ID to the corresponding JSONB value so you can quickly access a certain column.</li><li><strong>Less storage space</strong>: JSONB is a compacted binary format. It consumes less space on the disk and is more cost-effective.</li></ul><p>In the storage engine, row storage will be stored as a hidden column (DORIS_ROW_STORE_COL). During Memtable Flush, the columns will be encoded into JSONB and cached into this hidden column. In data reading, the system uses the Column ID to locate the column, finds the target row based on the row number, and then deserializes the relevant columns.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="short-circuit">Short-Circuit<a href="#short-circuit" class="hash-link" aria-label="Short-Circuit的直接链接" title="Short-Circuit的直接链接"></a></h3><p>Normally, an SQL statement is executed in three steps:</p><ol><li>SQL Parser parses the statement to generate an abstract syntax tree (AST).</li><li>The Query Optimizer produces an executable plan.</li><li>Execute the plan and return the results.</li></ol><p>For complex queries on massive data, it is better to follow the plan created by the Query Optimizer. However, for high-concurrency point queries requiring low latency, that plan is not only unnecessary but also brings extra overheads. That&#x27;s why we implement a short-circuit plan for point queries. </p><p><img loading="lazy" alt="short-circuit-plan" src="https://cdnd.selectdb.com/zh-CN/assets/images/high-concurrency_1-90fb6261659bb3cce5ad8076fa9dc65d.png" width="1606" height="778" class="img_ev3q"></p><p>Once the FE receives a point query request, a short-circuit plan will be produced. It is a lightweight plan that involves no equivalent transformation, logic optimization or physical optimization. Instead, it conducts some basic analysis on the AST, creates a fixed plan accordingly, and finds ways to reduce overhead of the optimizer.</p><p>For a simple point query involving primary keys, such as <code>select * from tbl where pk1 = 123 and pk2 = 456</code>, since it only involves one single Tablet, it is better to use a lightweight RPC interface for interaction with the Storage Engine. This avoids the creation of a complicated Fragment Plan and eliminates the performance overhead brought by the scheduling under the MPP query framework.</p><p>Details of the RPC interface are as follows:</p><div class="language-Java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-Java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PTabletKeyLookupRequest {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> required int64 tablet_id = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated KeyTuple key_tuples = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> optional Descriptor desc_tbl = 4;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> optional ExprList output_expr = 5;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PTabletKeyLookupResponse {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> required PStatus status = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> optional bytes row_batch = 5;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> optional bool empty_batch = 6;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">rpc tablet_fetch_data(PTabletKeyLookupRequest) returns (PTabletKeyLookupResponse);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>tablet_id</code> is calculated based on the primary key column, while <code>key_tuples</code> is the string format of the primary key. In this example, the <code>key_tuples</code> is similar to <!-- -->[&#x27;123&#x27;, &#x27;456&#x27;]<!-- -->. As BE receives the request, <code>key_tuples</code> will be encoded into primary key storage format. Then, it will locate the corresponding row number of the Key in the Segment File with the help of the primary key index, and check if that row exists in <code>delete bitmap</code>. If it does, the row number will be returned; if not, the system returns NotFound. The returned row number will be used for point query on <code>__DORIS_ROW_STORE_COL__</code>. That means we only need to locate one row in that column, fetch the original value of the JSONB format, and deserialize it.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="prepared-statement">Prepared Statement<a href="#prepared-statement" class="hash-link" aria-label="Prepared Statement的直接链接" title="Prepared Statement的直接链接"></a></h3><p>In high-concurrency queries, part of the CPU overhead comes from SQL analysis and parsing in FE. To reduce such overhead, in FE, we provide prepared statements that are fully compatible with MySQL protocol. With prepared statements, we can achieve a four-time performance increase for primary key point queries.</p><p><img loading="lazy" alt="prepared-statement-map" src="https://cdnd.selectdb.com/zh-CN/assets/images/high-concurrency_2-24db356001a7e9c6276202b59ce09d03.png" width="1280" height="775" class="img_ev3q"></p><p>The idea of prepared statements is to cache precomputed SQL and expressions in HashMap in memory, so they can be directly used in queries when applicable.</p><p>Prepared statements adopt MySQL binary protocol for transmission. The protocol is implemented in the mysql_row_buffer.<!-- -->[h|cpp]<!-- --> file, and uses MySQL binary encoding. Under this protocol, the client (for example, JDBC Client) sends a pre-compiled statement to FE via <code>PREPARE</code> MySQL Command. Next, FE will parse and analyze the statement and cache it in the HashMap as shown in the figure above. Next, the client, using <code>EXECUTE</code> MySQL Command, will replace the placeholder, encode it into binary format, and send it to FE. Then, FE will perform deserialization to obtain the value of the placeholder, and generate query conditions.</p><p><img loading="lazy" alt="prepared-statement-execution" src="https://cdnd.selectdb.com/zh-CN/assets/images/high-concurrency_3-78f37932ab22095589cd35e1829eba6b.png" width="1134" height="904" class="img_ev3q"></p><p>Apart from caching prepared statements in FE, we also cache reusable structures in BE. These structures include pre-allocated computation blocks, query descriptors, and output expressions. Serializing and deserializing these structures often cause a CPU hotspot, so it makes more sense to cache them. The prepared statement for each query comes with a UUID named CacheID. So when BE executes the point query, it will find the corresponding class based on the CacheID, and then reuse the structure in computation.</p><p>The following example demonstrates how to use a prepared statement in JDBC:</p><ol><li>Set a JDBC URL and enable prepared statement at the server end.</li></ol><div class="language-Bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-Bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">url = jdbc:mysql://127.0.0.1:9030/ycsb?useServerPrepStmts=true</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ol><li>Use a prepared statement.</li></ol><div class="language-Java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-Java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">// Use `?` as placeholder, reuse readStatement.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PreparedStatement readStatement = conn.prepareStatement(&quot;select * from tbl_point_query where key = ?&quot;);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">readStatement.setInt(1234);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ResultSet resultSet = readStatement.executeQuery();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">readStatement.setInt(1235);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">resultSet = readStatement.executeQuery();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="row-storage-cache">Row Storage Cache<a href="#row-storage-cache" class="hash-link" aria-label="Row Storage Cache的直接链接" title="Row Storage Cache的直接链接"></a></h3><p>Apache Doris has a Page Cache feature, where each page caches the data of one column. </p><p><img loading="lazy" alt="page-cache" src="https://cdnd.selectdb.com/zh-CN/assets/images/high-concurrency_4-3a2f6a6b077605a579c5b00560e0cffb.png" width="568" height="540" class="img_ev3q"></p><p>As mentioned above, we have introduced row storage in Doris. The problem with this is, one row of data consists of multiple columns, so in the case of big queries, the cached data might be erased. Thus, we also introduced row cache to increase row cache hit rate.</p><p>Row cache reuses the LRU Cache mechanism in Apache Doris. When the caching starts, the system will initialize a threshold value. If that threshold is hit, the old cached rows will be phased out. For a primary key query statement, the performance gap between cache hit and cache miss can be huge (we are talking about dozens of times less disk I/O and memory access here). So the introduction of row cache can remarkably enhance point query performance.</p><p><img loading="lazy" alt="row-cache" src="https://cdnd.selectdb.com/zh-CN/assets/images/high-concurrency_5-91a7b2adc421fb31c47d89f638adecf6.png" width="468" height="500" class="img_ev3q"></p><p>To enable row cache, you can specify the following configuration in BE:</p><div class="language-JSON codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-JSON codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">disable_storage_row_cache=false // This specifies whether to enable row cache; it is set to false by default.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">row_cache_mem_limit=20% // This specifies the percentage of row cache in the memory; it is set to 20% by default.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="benchmark-performance">Benchmark Performance<a href="#benchmark-performance" class="hash-link" aria-label="Benchmark Performance的直接链接" title="Benchmark Performance的直接链接"></a></h2><p>We tested Apache Doris with YCSB (Yahoo! Cloud Serving Benchmark) to see how all these optimizations work.</p><p><strong>Configurations and data size:</strong></p><ul><li>Machines: a single 16 Core 64G cloud server with 4×1T hard drives</li><li>Cluster size: 1 Frontend + 2 Backends</li><li>Data volume: 100 million rows of data, with each row taking 1KB to store; preheated</li><li>Table schema and query statement:</li></ul><div class="language-JavaScript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-JavaScript codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">// Table creation statement:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">CREATE TABLE `usertable` (</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `YCSB_KEY` varchar(255) NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD0` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD1` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD2` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD3` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD4` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD5` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD6` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD7` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD8` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD9` text NULL</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">) ENGINE=OLAP</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">UNIQUE KEY(`YCSB_KEY`)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">COMMENT &#x27;OLAP&#x27;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">DISTRIBUTED BY HASH(`YCSB_KEY`) BUCKETS 16</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PROPERTIES (</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;replication_allocation&quot; = &quot;tag.location.default: 1&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;in_memory&quot; = &quot;false&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;persistent&quot; = &quot;false&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;storage_format&quot; = &quot;V2&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;enable_unique_key_merge_on_write&quot; = &quot;true&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;light_schema_change&quot; = &quot;true&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;store_row_column&quot; = &quot;true&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;disable_auto_compaction&quot; = &quot;false&quot;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">// Query statement:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT * from usertable WHERE YCSB_KEY = ?</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>We run the test with the optimizations (row storage, short-circuit, and prepared statement) enabled, and then did it again with all of them disabled. Here are the results:</p><p><img loading="lazy" alt="performance-before-and-after-concurrency-optimization" src="https://cdnd.selectdb.com/zh-CN/assets/images/high-concurrency_6-6c3bbd4d2c6e6a54db40297c2154a9da.png" width="1280" height="653" class="img_ev3q"></p><p>With optimizations enabled, <strong>the average query latency decreased by a whopping 96%, the 99th percentile latency was only 1/28 of that without optimizations, and it has achieved a query concurrency of over 30,000 QPS.</strong> This is a huge leap in performance and an over 20-time increase in concurrency.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="best-practice">Best Practice<a href="#best-practice" class="hash-link" aria-label="Best Practice的直接链接" title="Best Practice的直接链接"></a></h2><p>It should be noted that these optimizations for point queries are implemented in the Unique Key model of Apache Doris, and you should enable Merge-on-Write and Light Schema Change for this model.</p><p>This is a table creation statement example for point queries:</p><div class="language-undefined codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-undefined codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">CREATE TABLE `usertable` (</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `USER_KEY` BIGINT NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD0` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD1` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD2` text NULL,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> `FIELD3` text NULL</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">) ENGINE=OLAP</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">UNIQUE KEY(`USER_KEY`)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">COMMENT &#x27;OLAP&#x27;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">DISTRIBUTED BY HASH(`USER_KEY`) BUCKETS 16</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PROPERTIES (</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;enable_unique_key_merge_on_write&quot; = &quot;true&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;light_schema_change&quot; = &quot;true&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&quot;store_row_column&quot; = &quot;true&quot;,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">); </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>Note:</strong></p><ul><li>Enable <code>light_schema_change</code> to support JSONB row storage for encoding ColumnID</li><li>Enable <code>store_row_column</code> to store row storage format</li></ul><p>For a primary key-based point query like the one below, after table creation, you can use row storage and short-circuit execution to improve performance to a great extent.</p><div class="language-SQL codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-SQL codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">select * from usertable where USER_KEY = xxx;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="复制代码到剪贴板" title="复制" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>To further unleash performance, you can apply prepared statement. If you have enough memory space, you can also enable row cache in the BE configuration.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="#conclusion" class="hash-link" aria-label="Conclusion的直接链接" title="Conclusion的直接链接"></a></h2><p>In high-concurrency scenarios, Apache Doris realizes over 30,000 QPS per node after optimizations including row storage, short-circuit, prepared statement, and row cache. Also, Apache Doris is easily scaled out since it is built on MPP architecture, on top of which you can scale it up by upgrading the hardware and machine configuration. This is how Apache Doris manages to achieve both high throughput and high concurrency. It allows you to deal with various data analytic workloads on one single platform and experience quick data analytics for various scenarios. Thanks to the great efforts of the Apache Doris community and a group of excellent SelectDB engineers, Apache Doris 2.0 is about to be released soon.</p></div></article><div class="pl-4 mt-20 text-[#1D1D1D]"><div class="text-[2rem] leading-[3.25rem]">Recent posts</div><div class="mt-4 flex flex-col"><a href="https://doris.apache.org/blog/evolution-of-the-apache-doris-execution-engine" target="_blank" rel="noopener noreferrer" class="text-lg leading-10 hover:no-underline hover:text-[#444FD9]">Steps to industry-leading query speed: evolution of the Apache Doris execution engine</a><a href="https://doris.apache.org/blog/job-scheduler-for-task-automation" target="_blank" rel="noopener noreferrer" class="text-lg leading-10 hover:no-underline hover:text-[#444FD9]">Another lifesaver for data engineers: Apache Doris Job Scheduler for task automation</a><a href="https://doris.apache.org/blog/release-note-2.0.11" target="_blank" rel="noopener noreferrer" class="text-lg leading-10 hover:no-underline hover:text-[#444FD9]">Apache Doris version 2.0.11 has been released</a><a href="https://doris.apache.org/blog/apache-doris-for-log-and-time-series-data-analysis-in-netease" target="_blank" rel="noopener noreferrer" class="text-lg leading-10 hover:no-underline hover:text-[#444FD9]">Apache Doris for log and time series data analysis in NetEase, why not Elasticsearch and InfluxDB?</a></div><a class="flex group text-primary items-center text-base cursor-pointer hover:no-underline mt-4" href="/zh-CN/blog"><span class="mr-2">View all blogs</span><span class="transition-slide"><svg xmlns="http://www.w3.org/2000/svg" class="transition-slide" width="1em" height="1em" viewBox="0 0 16 14" fill="none"><path d="M9.37549 12.3542L14.8755 6.85419L9.37549 1.35419" stroke="currentColor" stroke-width="1.65" stroke-linecap="round" stroke-linejoin="round"></path><path d="M1.12549 6.85419L14.8755 6.85419" stroke="currentColor" stroke-width="1.65" stroke-linecap="round" stroke-linejoin="round"></path></svg></span></a></div></main><div class="col col--2"><div class="tableOfContents_jeP5 thin-scrollbar"><a href="https://ask.selectdb.com" target="_blank" rel="noopener noreferrer" class="ml-4 mb-8 flex items-center hover:no-underline"><span class="pr-2">问答论坛</span><svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8500" id="mx_n_1711090272569" width="16" height="16"><path d="M522.24 896.512c-25.6 4.608-51.712 7.168-78.336 7.168-79.36 0-157.696-21.504-225.792-62.464l-18.432-10.752-103.936 28.16c-28.672 7.68-54.784-18.432-47.104-47.104l28.16-103.936c-10.752-17.92-17.408-30.208-20.992-36.864C20.992 607.232 3.072 536.064 3.584 463.36c0-243.2 197.12-440.32 440.32-440.32 221.696 0 405.504 164.352 435.712 377.856 90.112 55.808 144.896 154.112 144.896 260.096 0 51.2-12.8 100.352-36.352 144.384-2.048 4.096-6.144 10.752-11.776 20.48l17.408 64c7.68 28.672-18.432 54.784-47.104 47.104l-64-17.408-7.68 4.608c-47.616 28.672-101.888 43.52-157.184 43.52-71.68-0.512-140.8-25.088-195.584-71.168z m95.232-28.672c31.232 15.36 65.536 23.04 100.352 23.04 41.472 0 82.432-11.264 117.76-32.768 2.56-1.536 9.728-5.632 22.016-12.8 8.704-5.12 19.456-6.656 29.184-3.584l14.848 4.096-4.096-14.848c-2.56-10.24-1.536-20.48 4.096-29.696 6.144-10.24 12.288-20.992 18.432-31.232 17.92-33.28 27.136-70.656 27.136-108.544 0-59.904-23.552-117.76-65.536-160.256-13.312 164.352-118.272 303.616-264.192 366.592z m-462.848-155.648l-14.848 54.784 54.784-14.848c9.728-2.56 20.48-1.536 29.184 4.096 18.432 10.752 29.184 16.896 32.768 19.456 56.32 33.792 120.832 51.712 186.88 51.712 200.704 0 363.52-162.816 363.52-363.52s-162.816-363.52-363.52-363.52-363.52 162.816-363.52 363.52c0 60.928 14.848 119.296 43.008 171.52 3.584 7.168 13.312 23.04 27.648 47.616 5.632 8.704 6.656 19.456 4.096 29.184z m448.512-382.976c20.992 0 38.4 16.896 38.4 38.4 0 20.992-16.896 38.4-38.4 38.4H284.16c-20.992 0-38.4-16.896-38.4-38.4 0-20.992 16.896-38.4 38.4-38.4h318.976z m-153.088 191.488c20.992 0 38.4 16.896 38.4 38.4 0 20.992-16.896 38.4-38.4 38.4H284.16c-20.992 0-38.4-16.896-38.4-38.4 0-20.992 16.896-38.4 38.4-38.4h165.888z m0 0" p-id="8501" fill="currentColor"></path></svg></a><span class="ml-4">本页导航</span><ul class="table-of-contents table-of-contents__left-border"><li><a href="#five-ways-to-accelerate-high-concurrency-queries" class="table-of-contents__link toc-highlight">Five Ways to Accelerate High-Concurrency Queries</a><ul><li><a href="#partioning-and-bucketing" class="table-of-contents__link toc-highlight">Partioning and Bucketing</a></li><li><a href="#index" class="table-of-contents__link toc-highlight">Index</a></li><li><a href="#materialized-view" class="table-of-contents__link toc-highlight">Materialized View</a></li><li><a href="#runtime-filter" class="table-of-contents__link toc-highlight">Runtime Filter</a></li><li><a href="#top-n-optimization" class="table-of-contents__link toc-highlight">TOP-N Optimization</a></li></ul></li><li><a href="#how-we-bring-concurrency-to-the-next-level" class="table-of-contents__link toc-highlight">How We Bring Concurrency to the Next Level</a><ul><li><a href="#row-storage-format" class="table-of-contents__link toc-highlight">Row Storage Format</a></li><li><a href="#short-circuit" class="table-of-contents__link toc-highlight">Short-Circuit</a></li><li><a href="#prepared-statement" class="table-of-contents__link toc-highlight">Prepared Statement</a></li><li><a href="#row-storage-cache" class="table-of-contents__link toc-highlight">Row Storage Cache</a></li></ul></li><li><a href="#benchmark-performance" class="table-of-contents__link toc-highlight">Benchmark Performance</a></li><li><a href="#best-practice" class="table-of-contents__link toc-highlight">Best Practice</a></li><li><a href="#conclusion" class="table-of-contents__link toc-highlight">Conclusion</a></li></ul></div></div></div></div></div></div><div class="footer pt-16 pb-10"><div class="container"><div class="footer-box"><div class="left"><img src="/zh-CN/images/asf_logo_apache.svg" alt="" class="themedImage_ToTc themedImage--light_HNdA footer__logo"><img src="/zh-CN/images/asf_logo_apache.svg" alt="" class="themedImage_ToTc themedImage--dark_i4oU footer__logo"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">ASF</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://www.apache.org/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Foundation<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.apache.org/licenses/" target="_blank" rel="noopener noreferrer" class="footer__link-item">License<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.apache.org/events/current-event" target="_blank" rel="noopener noreferrer" class="footer__link-item">Events<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.apache.org/foundation/sponsorship.html" target="_blank" rel="noopener noreferrer" class="footer__link-item">Sponsorship<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://privacy.apache.org/policies/privacy-policy-public.html" target="_blank" rel="noopener noreferrer" class="footer__link-item">Privacy<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.apache.org/security/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Security<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.apache.org/foundation/thanks.html" target="_blank" rel="noopener noreferrer" class="footer__link-item">Thanks<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">Resources</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/zh-CN/download">Download</a></li><li class="footer__item"><a class="footer__link-item" href="/zh-CN/docs/get-starting/quick-start">Docs</a></li><li class="footer__item"><a class="footer__link-item" href="/zh-CN/blog">Blog</a></li><li class="footer__item"><a class="footer__link-item" href="/zh-CN/ecosystem/cluster-management">Ecosystem</a></li><li class="footer__item"><a class="footer__link-item" href="/zh-CN/users">Users</a></li><li class="footer__item"><a href="https://github.com/apache/doris/discussions" target="_blank" rel="noopener noreferrer" class="footer__link-item">Discussions<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">Community</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/zh-CN/community/how-to-contribute/">How to contribute</a></li><li class="footer__item"><a href="https://github.com/apache/doris/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Source code<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://cwiki.apache.org/confluence/display/DORIS/Doris+Improvement+Proposals" target="_blank" rel="noopener noreferrer" class="footer__link-item">Improvement proposal<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a class="footer__link-item" href="/zh-CN/community/team">Doris team</a></li><li class="footer__item"><a href="https://github.com/apache/doris/issues/30669" target="_blank" rel="noopener noreferrer" class="footer__link-item">Roadmap<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div></div></div><div class="right"><div class="footer__title">Join the community</div><div class="social-list"><div class="social"><a href="mailto:dev@doris.apache.org" target="_blank" title="mail" class="item"><svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" viewBox="0 0 32 32" fill="none"><path d="M5.6003 6H26.3997C27.8186 6 28.982 7.10964 29 8.46946L16.0045 15.454L3.01202 8.47829C3.02405 7.11258 4.1784 6 5.6003 6ZM3.01202 11.1508L3 23.5011C3 24.8756 4.16938 26 5.6003 26H26.3997C27.8306 26 29 24.8756 29 23.5011V11.145L16.3111 17.8028C16.1157 17.9058 15.8813 17.9058 15.6889 17.8028L3.01202 11.1508Z" fill="currentColor"></path></svg></a><a href="https://github.com/apache/doris" target="_blank" title="github" class="item"><svg width="2em" height="2em" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.0001 2.66675C8.63342 2.66675 2.66675 8.63341 2.66675 16.0001C2.66524 18.7991 3.54517 21.5276 5.1817 23.7983C6.81824 26.0691 9.12828 27.7668 11.7841 28.6508C12.4508 28.7668 12.7001 28.3668 12.7001 28.0161C12.7001 27.7001 12.6828 26.6508 12.6828 25.5334C9.33342 26.1508 8.46675 24.7174 8.20008 23.9668C8.04942 23.5828 7.40008 22.4001 6.83342 22.0828C6.36675 21.8334 5.70008 21.2161 6.81608 21.2001C7.86675 21.1828 8.61608 22.1668 8.86675 22.5668C10.0668 24.5828 11.9841 24.0161 12.7494 23.6668C12.8668 22.8001 13.2161 22.2174 13.6001 21.8841C10.6334 21.5508 7.53342 20.4001 7.53342 15.3001C7.53342 13.8494 8.04942 12.6507 8.90008 11.7161C8.76675 11.3827 8.30008 10.0161 9.03342 8.18275C9.03342 8.18275 10.1494 7.83342 12.7001 9.55075C13.7855 9.2495 14.907 9.09787 16.0334 9.10008C17.1668 9.10008 18.3001 9.24942 19.3668 9.54942C21.9161 7.81608 23.0334 8.18408 23.0334 8.18408C23.7668 10.0174 23.3001 11.3841 23.1668 11.7174C24.0161 12.6507 24.5334 13.8334 24.5334 15.3001C24.5334 20.4174 21.4174 21.5508 18.4508 21.8841C18.9334 22.3001 19.3508 23.1001 19.3508 24.3508C19.3508 26.1334 19.3334 27.5668 19.3334 28.0174C19.3334 28.3668 19.5841 28.7828 20.2508 28.6494C22.8975 27.7558 25.1973 26.0547 26.8266 23.7856C28.4559 21.5165 29.3327 18.7936 29.3334 16.0001C29.3334 8.63341 23.3668 2.66675 16.0001 2.66675V2.66675Z" fill="currentColor"></path></svg></a><a href="https://twitter.com/doris_apache" target="_blank" title="twitter" class="item"><svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" viewBox="0 0 32 32" fill="none"><path d="M4.625 4.625H11.2809L27.375 27.375H20.7191L4.625 4.625ZM7.52549 6.10639L21.5236 25.8936H24.4746L10.4764 6.10639H7.52549Z" fill="currentColor"></path><path d="M14.4268 18.4803L6.53447 27.375H4.625L13.5581 17.2525L14.4268 18.4803ZM18.1299 14.3066L26.7203 4.625H24.7017L17.2525 13.0662L18.1299 14.3066Z" fill="currentColor"></path></svg></a><a href="https://join.slack.com/t/apachedoriscommunity/shared_invite/zt-2kl08hzc0-SPJe4VWmL_qzrFd2u2XYQA" title="slack" target="_blank" class="item"><svg width="2em" height="2em" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_125_278)"><path d="M12.5875 16.6906C11.0844 16.6906 9.86562 17.9094 9.86562 19.4125V26.2375C9.86562 26.9594 10.1524 27.6517 10.6628 28.1622C11.1733 28.6726 11.8656 28.9594 12.5875 28.9594C13.3094 28.9594 14.0017 28.6726 14.5122 28.1622C15.0226 27.6517 15.3094 26.9594 15.3094 26.2375V19.4531C15.3094 17.9094 14.0906 16.6906 12.5875 16.6906ZM3 19.4531C3 20.175 3.28677 20.8673 3.79722 21.3778C4.30767 21.8882 4.99999 22.175 5.72187 22.175C6.44376 22.175 7.13608 21.8882 7.64653 21.3778C8.15698 20.8673 8.44375 20.175 8.44375 19.4531V16.7312H5.7625C4.25938 16.6906 3 17.9094 3 19.4531ZM12.5875 3C11.8656 3 11.1733 3.28677 10.6628 3.79722C10.1524 4.30767 9.86562 4.99999 9.86562 5.72187C9.86562 6.44376 10.1524 7.13608 10.6628 7.64653C11.1733 8.15698 11.8656 8.44375 12.5875 8.44375H15.3094V5.72187C15.3094 4.21875 14.0906 3 12.5875 3ZM5.72187 15.3094H12.5469C13.2688 15.3094 13.9611 15.0226 14.4715 14.5122C14.982 14.0017 15.2688 13.3094 15.2688 12.5875C15.2688 11.8656 14.982 11.1733 14.4715 10.6628C13.9611 10.1524 13.2688 9.86562 12.5469 9.86562H5.72187C4.99999 9.86562 4.30767 10.1524 3.79722 10.6628C3.28677 11.1733 3 11.8656 3 12.5875C3 13.3094 3.28677 14.0017 3.79722 14.5122C4.30767 15.0226 4.99999 15.3094 5.72187 15.3094ZM26.2375 9.86562C24.7344 9.86562 23.5156 11.0844 23.5156 12.5875V15.3094H26.2375C26.9594 15.3094 27.6517 15.0226 28.1622 14.5122C28.6726 14.0017 28.9594 13.3094 28.9594 12.5875C28.9594 11.8656 28.6726 11.1733 28.1622 10.6628C27.6517 10.1524 26.9594 9.86562 26.2375 9.86562ZM16.6906 5.72187V12.5875C16.6906 13.3094 16.9774 14.0017 17.4878 14.5122C17.9983 15.0226 18.6906 15.3094 19.4125 15.3094C20.1344 15.3094 20.8267 15.0226 21.3372 14.5122C21.8476 14.0017 22.1344 13.3094 22.1344 12.5875V5.72187C22.1344 4.99999 21.8476 4.30767 21.3372 3.79722C20.8267 3.28677 20.1344 3 19.4125 3C18.6906 3 17.9983 3.28677 17.4878 3.79722C16.9774 4.30767 16.6906 4.99999 16.6906 5.72187ZM22.1344 26.2781C22.1344 24.775 20.9156 23.5562 19.4125 23.5562H16.6906V26.2781C16.6906 27 16.9774 27.6923 17.4878 28.2028C17.9983 28.7132 18.6906 29 19.4125 29C20.1344 29 20.8267 28.7132 21.3372 28.2028C21.8476 27.6923 22.1344 27 22.1344 26.2781ZM26.2781 16.6906H19.4125C18.6906 16.6906 17.9983 16.9774 17.4878 17.4878C16.9774 17.9983 16.6906 18.6906 16.6906 19.4125C16.6906 20.1344 16.9774 20.8267 17.4878 21.3372C17.9983 21.8476 18.6906 22.1344 19.4125 22.1344H26.2375C27.7406 22.1344 28.9594 20.9156 28.9594 19.4125C29 17.9094 27.7812 16.6906 26.2781 16.6906Z" fill="currentColor"></path></g><defs><clipPath id="clip0_125_278"><rect width="26" height="26" fill="currentColor" transform="translate(3 3)"></rect></clipPath></defs></svg></a></div><div class="social"><a href="https://www.youtube.com/@apachedoris/channels" title="youtube" target="_blank" class="item"><svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" viewBox="0 0 32 32" fill="none"><path d="M28.5167 7.83429C28.9436 8.25423 29.2532 8.77539 29.4154 9.34742C29.8205 11.5462 30.0159 13.7775 29.999 16.0121C30.0144 18.2382 29.819 20.4609 29.4154 22.6515C29.2532 23.2235 28.9436 23.7446 28.5167 24.1645C28.0898 24.5845 27.5601 24.889 26.9785 25.0486C24.7728 25.625 16.0124 25.625 16.0124 25.625C16.0124 25.625 7.22652 25.625 5.04638 25.0486C4.46489 24.889 3.9351 24.5845 3.5082 24.1645C3.08132 23.7446 2.77176 23.2235 2.60948 22.6515C2.19736 20.4617 1.9934 18.239 2.00025 16.0121C1.9918 13.7767 2.19577 11.5455 2.60948 9.34742C2.77176 8.77539 3.08132 8.25423 3.5082 7.83429C3.9351 7.41436 4.46489 7.10985 5.04638 6.95021C7.25103 6.36354 16.0124 6.37502 16.0124 6.37502C16.0124 6.37502 24.796 6.37502 26.9785 6.95021C27.5601 7.10985 28.0898 7.41436 28.5167 7.83429ZM12.5 21.25L21.25 16.008L12.5 10.75V21.25Z" fill="currentColor"></path></svg></a><a href="https://www.linkedin.com/company/doris-apache/" title="linkedin" target="_blank" class="item"><svg width="2rem" height="2rem" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4.29925 26.9996H9.66738V11.6781H4.29925V26.9996ZM22.1628 11.1949C19.9409 11.1949 18.7157 11.9388 17.3054 13.7407V11.6777H11.9459V26.9996H17.305V18.6738C17.305 16.9168 18.145 15.1982 20.1535 15.1982C22.162 15.1982 22.6559 16.9164 22.6559 18.632V27H28V18.2902C28 12.2386 24.3854 11.1949 22.1628 11.1949ZM6.99325 4C5.3395 4 4 5.21047 4 6.7046C4 8.19759 5.3395 9.40617 6.99325 9.40617C8.6455 9.40617 9.985 8.19722 9.985 6.7046C9.985 5.21047 8.6455 4 6.99325 4Z" fill="white"></path></svg></a><a href="https://medium.com/@ApacheDoris" title="medium" target="_blank" class="item"><svg width="2em" height="2em" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="Frame"><path id="Vector" d="M17.7967 16.5385C17.8029 18.53 16.9746 20.4425 15.4937 21.8559C14.0128 23.2693 12.0004 24.0681 9.89836 24.0769C7.79633 24.0681 5.78391 23.2693 4.30302 21.8559C2.82212 20.4425 1.99383 18.53 2.00003 16.5385C1.99383 14.5469 2.82212 12.6344 4.30302 11.221C5.78391 9.80759 7.79633 9.00878 9.89836 9C12.0004 9.00878 14.0128 9.80759 15.4937 11.221C16.9746 12.6344 17.8029 14.5469 17.7967 16.5385ZM26.4533 16.5385C26.4533 20.4514 24.6917 23.6348 22.51 23.6348C20.3283 23.6348 18.555 20.4514 18.555 16.5385C18.555 12.6255 20.3283 9.44214 22.51 9.44214C24.6917 9.44214 26.4533 12.6255 26.4533 16.5385ZM30 16.5385C30 20.0424 29.3817 22.8942 28.6117 22.8942C27.8417 22.8942 27.2233 20.0424 27.2233 16.5385C27.2233 13.0345 27.8417 10.1827 28.6117 10.1827C29.3817 10.1827 30 13.0345 30 16.5385Z" fill="currentColor"></path></g></svg></a><a class="item wechat"><svg width="2em" height="2em" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20.7578 11.5169C21.0708 11.5169 21.3795 11.5398 21.6851 11.573C20.8524 7.73517 16.7052 4.88306 11.9718 4.88306C6.67951 4.88306 2.34412 8.45283 2.34412 12.9854C2.34412 15.6013 3.78679 17.7498 6.19667 19.4161L5.2339 22.2827L8.59917 20.6122C9.80411 20.8478 10.7698 21.0906 11.9718 21.0906C12.2738 21.0906 12.5728 21.0759 12.8703 21.0523C12.682 20.4159 12.5728 19.7485 12.5728 19.0566C12.5728 14.8947 16.1847 11.5169 20.7578 11.5169ZM15.5822 8.9335C16.3072 8.9335 16.7871 9.40601 16.7871 10.1229C16.7871 10.8369 16.3072 11.3153 15.5822 11.3153C14.8601 11.3153 14.1365 10.8369 14.1365 10.1229C14.1365 9.40601 14.8601 8.9335 15.5822 8.9335ZM8.84429 11.3153C8.12218 11.3153 7.3942 10.8368 7.3942 10.1229C7.3942 9.40597 8.12218 8.93346 8.84429 8.93346C9.56559 8.93346 10.0463 9.40597 10.0463 10.1229C10.0463 10.8369 9.56559 11.3153 8.84429 11.3153ZM29.5453 18.9422C29.5453 15.1332 25.6935 12.0285 21.3677 12.0285C16.7871 12.0285 13.1797 15.1332 13.1797 18.9422C13.1797 22.7567 16.7871 25.8547 21.3677 25.8547C22.326 25.8547 23.2932 25.6169 24.2559 25.3777L26.897 26.8086L26.1726 24.4282C28.1056 22.993 29.5453 21.0906 29.5453 18.9422ZM18.7126 17.7498C18.2335 17.7498 17.7499 17.278 17.7499 16.7966C17.7499 16.3219 18.2335 15.8442 18.7126 15.8442C19.4406 15.8442 19.9176 16.3219 19.9176 16.7966C19.9176 17.278 19.4406 17.7498 18.7126 17.7498ZM24.0079 17.7498C23.5324 17.7498 23.0518 17.278 23.0518 16.7966C23.0518 16.3219 23.5324 15.8442 24.0079 15.8442C24.73 15.8442 25.2128 16.3219 25.2128 16.7966C25.2128 17.278 24.73 17.7498 24.0079 17.7498Z" fill="currentColor"></path></svg><div class="wechat-dropdown"><p class="text-[#4c576c] text-xs">Connect on WeChat</p><img src="https://cdnd.selectdb.com/zh-CN/assets/images/doris-wechat-b949e908a3bc2776d824f79a9100bd4b.png" alt=""></div></a></div></div></div></div><div class="footer__copyright">Copyright © 2024 The Apache Software Foundation,Licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0" target="_blank">Apache License, Version 2.0</a>. Apache, Doris, Apache Doris, the Apache feather logo and the Apache Doris logo are trademarks of The Apache Software Foundation.</div></div></div></div>
<script src="https://cdnd.selectdb.com/zh-CN/assets/js/runtime~main.ea863d93.js"></script>
<script src="https://cdnd.selectdb.com/zh-CN/assets/js/main.bda5da23.js"></script>
</body>
</html>