开源项目
SQL Joins: Understanding How to combine Data from Multiple Tables
When you're diving into databases, you'll quickly notice that data isn't usually crammed into a single table. Take an e-commerce site, for instance, you'd typically find one table for customers, another for orders, a separate one for products and yet another for payments. What are SQL Joins A SQL join is a tool that lets you combine rows from two or more tables based on a shared column between them. For example, suppose we have these two tables: Customers Orders The customer_id column connects the two tables. Instead of looking at customers and orders separately, we can use a join to find out who placed each order. The result would be: Types of SQL Joins INNER JOIN An INNER JOIN returns only records that have a match in both tables. It should be used when you only want records where a relationship exists. For example, if you are generating a report showing customers who have actually placed orders, an INNER JOIN makes sense. Customers who have never placed an order will not appear. LEFT JOIN A LEFT JOIN returns all records from the left table, even when there is no matching record in the right table. This becomes particularly useful when you want to identify customers who have not placed any orders. RIGHT JOIN A RIGHT JOIN works similarly to a LEFT JOIN, except that all records from the right table are returned. In practice, RIGHT JOIN is used less frequently because the same result can usually be achieved by reversing the order of the tables and using a LEFT JOIN. FULL OUTER JOIN A FULL OUTER JOIN returns all records from both tables. Where a matching record doesn't exist, SQL returns NULL for the missing data. This can be useful when comparing two datasets and you want to identify both matching and unmatched records. For example, a company could use it to compare customer records from two different systems and find customers that exist in one system but not the other. Conclusion SQL joins may seem confusing when you first encounter them, but the basic idea is stra
AI 资讯
Why Using FLOAT for Financial Pipelines is a Silent $100k Trap (and How PostgreSQL NUMERIC Saves Your Ledger)
Here is a simple SQL query that should return 0.3: SELECT 0 . 1 :: FLOAT4 + 0 . 2 :: FLOAT4 ; In PostgreSQL, MySQL, and most relational SQL engines, the result is: 0.30000001192092896 If you calculate sales tax, loan interest, or wallet balances across 10,000,000 transactions a day , those tiny fractional drifts accumulate into real cash discrepancies during month-end ledger reconciliation. 🔍 Why Does Binary Floating-Point Drift Happen? Hardware Implementation: Modern computer CPUs represent FLOAT and DOUBLE PRECISION using binary floating-point numbers (IEEE 754 standard). Base-2 vs. Base-10 Math: In base-10, fractions like 0.1 (1/10) and 0.2 (2/10) look clean and simple. But in base-2 binary, 0.1 is an infinite recurring fraction : 0.000110011001100110011... (binary) Because hardware registers have finite bits (32-bit for FLOAT4 , 64-bit for FLOAT8 ), the value is truncated, introducing a tiny approximation error on every calculation. ⚙️ How PostgreSQL NUMERIC Works Under the Hood Unlike FLOAT , PostgreSQL's NUMERIC (or DECIMAL ) data type does NOT use IEEE 754 binary floating-point hardware representation. ┌────────────────────────────────────────────────────────────────────────┐ │ PostgreSQL NUMERIC Internal Memory Representation │ │ 1. Header (4 Bytes): Sign, weight, display scale, digit count │ │ 2. Digits Array: Stores exact base-10000 integer chunks (0000 to 9999) │ │ ➔ 100% Exact Arbitrary-Precision Base-10 Arithmetic │ └────────────────────────────────────────────────────────────────────────┘ It stores exact decimal digits in memory using base-10000 arithmetic . There is ZERO floating-point drift. 10.50 + 20.25 is always 100% exactly 30.75 . 💡 The Senior Data Engineer Production Standard When designing production DDL schemas for transactional, warehousing, or financial pipelines: Never use FLOAT , REAL , or DOUBLE PRECISION for: Product pricing ( unit_price ) Account balances ( wallet_balance , available_funds ) Tax & GST calculations ( tax_amount , discou
AI 资讯
The Database That Tells You What It Knows
“Store the data” is only the beginning of the problem. The difficult questions usually come afterward: What structure does this data actually have? Which fields are missing or inconsistent? Which values are invalid? Which changes are safe to apply automatically? What exactly changed after a repair? Can the system prove that its storage and indexes are still consistent? I built Atlas to answer those questions inside the database engine itself. Atlas is a zero-dependency embedded database for semi-structured data. It stores records, builds a full-text search index, infers schema, analyzes data quality, proposes safe repairs, preserves uncertain records, and records an audit trail of applied changes. It does not use SQLite or SQL. It is not intended to replace SQLite for relational workloads. Instead, Atlas focuses on a gap that is usually handled by external scripts and tools: Data inspection, diagnosis, and safe repair as first-class database capabilities. That is the problem Atlas was built to solve. Why data quality belongs inside the database engine Most databases are very good at storing and retrieving data. That is necessary, but real-world data work rarely stops there.** Operational records, imported JSON, CSV files, event payloads, and semi-structured documents often arrive with problems: { "id" : "T-1" , "title" : " Connection timeout " , "priority" : "HIGH" } { "id" : "T-1" , "title" : "connection timeout" , "priority" : "high" } { "id" : "T-2" , "title" : "Unicode café search" , "priority" : null } These records contain several potential issues: Duplicate logical identifiers Leading or trailing whitespace Inconsistent capitalization Null-like values Missing fields Mixed data types Malformed email addresses Different date formats Inconsistent structures across records A storage engine can preserve these values perfectly while still leaving the data difficult to understand and use. The usual response is to add external tools: A schema profiler A data-quality
AI 资讯
NextAuth / Auth.js Database Schema Explained
The short version NextAuth (now Auth.js) creates 4 tables in your database: users , accounts , sessions , and verification_tokens . The users and accounts tables have a one-to-one relationship via accounts.user_id . Sessions link to users via sessions.user_id . Verification tokens are short-lived and self-cleaning. The 4 tables users Column Type What it means id text / UUID Primary key. Generated by NextAuth. name text Display name from the OAuth provider (Google, GitHub, etc.) email text User's email. May be null if the provider doesn't share it. email_verified timestamp When the email was verified. Null if never verified. image text Profile picture URL from the provider. created_at timestamp When the user first signed in. updated_at timestamp Last profile sync from the provider. accounts This table links a user to an OAuth provider. One user can have multiple accounts (e.g., Google + GitHub). Column Type What it means id text / UUID Primary key. user_id text Foreign key → users.id . type text Always "oauth" or "oidc" . provider text "google" , "github" , "discord" , etc. provider_account_id text The provider's unique ID for this user. refresh_token text OAuth refresh token (encrypted in production). access_token text OAuth access token (encrypted in production). expires_at integer When the access token expires (Unix timestamp). token_type text Usually "Bearer" . scope text Permissions granted by the provider. id_token text OIDC ID token (if using OIDC). session_state text Provider-specific session state. sessions Active sessions for each user. NextAuth creates a new row here on every sign-in. Column Type What it means id text / UUID Primary key. session_token text The session token stored in the user's cookie. user_id text Foreign key → users.id . expires timestamp When this session expires. verification_tokens Short-lived tokens for email verification, password reset, etc. Self-cleaning old tokens are deleted automatically. Column Type What it means identifier te
AI 资讯
Understanding the Replication Queue in ClickHouse
I was testing out CH-Ops - an admin GUI for self-hosted ClickHouse - on a simple setup: 1 shard, 2 replicas. Stumbled onto the replication queue almost by accident. Here's what I did: I stopped one of the nodes (let's call it Node B), then inserted some data through the other one (Node A). Just wanted to see what would happen. Then, while Node B was still down, I checked it in CH-Ops. It had stuff sitting in its replication queue. My first assumption was: okay, this must be showing what's left to replicate across the cluster - the total pending replication work. So I switched over and checked Node A, the one that was actually up and had just received the insert. Its queue was empty. That didn't match what I expected at all. If the queue was a cluster-wide "here's what still needs to replicate" view, Node A should've shown something too - it was the one that had the fresh data now waiting to reach Node B. Instead it was Node B, the down one, sitting there with pending tasks. That mismatch is what sent me digging. Turns out the queue isn't cluster-wide at all - it's specific to each ClickHouse instance. Once I brought Node B back up, its queue drained in seconds and the data showed up. That whole experiment is basically the entire post in miniature. Here's the mental model I ended up with. A Queue Belongs to a Replica, Not to the Table This is the first thing to get straight. With a ReplicatedMergeTree table, you can have multiple replicas holding copies of the same data. It's tempting to think of replication as one shared pipe between them. It isn't. Each replica keeps its own local replication queue . So if you see: Replica 1 → queue_size = 0 Replica 2 → queue_size = 25 that doesn't mean 25 operations are waiting somewhere in the middle for both replicas to pick up. It means Replica 2, specifically, has 25 tasks it hasn't finished yet. Once that clicked for me, the rest of the system made a lot more sense. So Where Do These Tasks Come From? Replication in ClickHouse
AI 资讯
AI React Native Form Builder: The Complete Data-Entry Stack in 2026
TL;DR Every mobile app is forms underneath: signup, checkout, onboarding, KYC. The UI is an afternoon; the invisible stack (keyboard geometry, validation, migrations, RLS, typed writes) is where weeks disappear. Most AI form builders generate a pretty <TextInput> and stop. The useful pattern is generating the whole pipeline from one prompt: SQL migration, RLS policies, regenerated types, controlled state, visible errors, and a real Supabase insert. Five silent-failure patterns ship broken forms constantly: Alert.alert on web, unchecked { error } , RLS with no policy, stale generated types, and guard clauses that swallow crashes. Iterate additively (point-and-edit, follow-up prompts) instead of regenerating. Full regenerations lose per-field polish. Why "just add a form" is never just a form Ask any React Native developer what's slow about mobile development and forms will be near the top of the list. Not for the reasons the UI suggests. The visible part (labels, inputs, a submit button) is an afternoon. The invisible part is where the calendar goes: Keyboard geometry. iOS pushes content up; Android resizes; the submit button ends up under the keyboard on one platform and floats wrong on the other. Every screen with a TextInput needs a KeyboardAvoidingView with the correct behavior prop and a ScrollView with keyboardShouldPersistTaps="handled" , or it ships broken. Controlled state. Every field wants a useState slice, an onChangeText handler, a value prop, and a clean way to reset. Formik and react-hook-form abstract this, but they add a dependency graph, and neither handles the mobile-specific ergonomics. Validation with visible errors. A validator that fails silently is worse than none. Errors have to render on the correct field, at the correct time. The database half. A form that doesn't persist is a demo. Persisting means a table, columns of the right type, RLS policies (or every query returns zero rows with no error), a typed client, and error handling on the mu
AI 资讯
How Cobrainer built graph-based agent memory on one engine
Author: Ignacio Paz An AI agent is only as useful as what it can remember - and how well it can connect the things it remembers. Most teams hand their agent a memory by reaching for a vector store: embed everything, retrieve by similarity, hope the relevant context comes back. It works, until you notice the agent keeps surfacing things that are near the question but not actually connected to it. Cobrainer , a skills-intelligence company based in Munich, took a different route. They gave their AI agent a memory that lives in the database as a graph, where the agent builds the relationships between nodes as it goes. They did it without adding a graph database, a vector engine, or a search engine to their stack. It all runs on SurrealDB, alongside a Rust-native agentic graph RAG built on the same store. Here's how, and why a single engine made the difference. The problem with flat memory Cobrainer runs a skills-intelligence platform - the kind of system that reasons about how people, roles, skills, and capabilities relate to one another. That's an inherently graph-shaped problem. But their first retrieval setup wasn't graph-shaped at all. It pulled context through flat vector retrieval over an S3-and-OpenSearch pipeline, which carried two recurring costs: Accuracy . Flat vector matches returned context that was loosely related - semantically near, but not necessarily connected in any meaningful way. The team wanted the agent to follow real relationships between entities, so its answers were grounded rather than approximate. Tokens . Broad vector matches meant stuffing a lot of marginally relevant context into every prompt - expensive, and more so with every call. The team wanted to fetch only the context that mattered. The obvious fix - adding a graph database on top of the vector and search systems they already ran - would have meant more infrastructure to operate. For a startup moving fast, that fragmentation was the thing to avoid, not embrace. What they wanted inst
AI 资讯
Why Adding an Index Won't Fix Your Slow COUNT(*) in PostgreSQL
COUNT(*) looks like a trivial operation: SELECT COUNT ( * ) FROM orders ; The query asks for a single number, but that doesn't mean PostgreSQL can produce it with a constant-time read from some internal counter. When we need an exact count, PostgreSQL has to determine how many rows are actually part of the visible result set for that query. On large tables, that work can become a meaningful chunk of total execution time. And the problem doesn't just go away by throwing an index at it. The useful question isn't "do I have an index?" It's: How many rows does PostgreSQL actually need to examine to compute this count — and can that work be reduced? Why COUNT(*) Can Be Expensive in PostgreSQL PostgreSQL uses MVCC — Multi-Version Concurrency Control — to manage concurrent access to data. That's what lets multiple transactions work at the same time while each sees a consistent view of the database. But it also means row visibility depends on the snapshot the query is running under. That's why PostgreSQL can't answer: SELECT COUNT ( * ) FROM orders ; by simply reading an exact counter stored somewhere in the table's metadata. To return an exact result, it has to process the rows — or an index structure representing those rows — and determine which ones are part of the visible result. On a small table, that cost is invisible. On a table with millions of rows, the amount of work starts to matter. Which leads to an important distinction: returning a single row from COUNT(*) does not mean processing a single row. How to Analyze a COUNT with EXPLAIN ANALYZE Before reaching for an index, it's worth looking at what PostgreSQL is actually doing. Say we have this query: SELECT COUNT ( * ) FROM orders WHERE status = 'completed' ; We can analyze it with: EXPLAIN ( ANALYZE , BUFFERS ) SELECT COUNT ( * ) FROM orders WHERE status = 'completed' ; The goal isn't to hunt for an Index Scan by default. Worth checking instead: the scan type estimated rows vs. actual rows processed rows discard
AI 资讯
A Straightforward Guide for MVCC in Postgres
Overview In this article, I'll introduce the concept of Multi-Version Concurrency Control (MVCC) and explain how Postgres implements this protocol across different isolation levels. I'm assuming you already have a basic understanding of isolation levels, database locks, and concurrency in general. I won't cover those concepts here, so if you're not familiar with them, I highly recommend checking out A Straightforward Guide for Isolation Levels first before continuing. The goal of this article is to help you understand: What Multi-Version Concurrency Control is How Postgres implements MVCC across different isolation levels Multi-Version Concurrency Control High-Level Concept The idea behind MVCC is simple: it's a protocol designed to accomplish one goal — when two or more transactions run concurrently on the same data, the end result should look as if those transactions ran one after another, in sequence. Take a look at the diagram above. Two transactions are running concurrently, and we want the end result to look as if either the first transaction ran and committed before the second one started, or vice versa. MVCC guarantees there are only two possible outcomes — never a third. But in reality, these transactions are running at the same time, so this is exactly the core idea of MVCC: it's a protocol that gives us this guarantee even though the transactions genuinely overlap in time. Note that other protocols aim for the same goal, like Two-Phase Locking and Optimistic Concurrency Control. They all take different approaches, but they're all working toward the same thing. The core idea of MVCC is that whenever a transaction updates a row, it doesn't mutate the value in place. Instead, it creates a new record as the latest version and links it back to the old version. After the update, the row has a new version, and the old version is never changed. This version chain exists per record — every update to a row creates a new version, and since each version is linked to
AI 资讯
What It Actually Takes to Run a Cross-Border Marketplace: Six Years of Shpper
Shpper is a cross-border personal-shopping marketplace. A buyer wants something they cannot get where they live. A traveller is already flying that route with unused luggage space. The platform introduces them, holds the money until the item arrives, and turns an empty few kilos in someone's suitcase into a delivery network. I am the CTO. I own the platform end to end — the Flutter apps for both sides, the backend, payments and escrow, identity verification, and the release pipeline. We are on version 14.2.0, rated 4.64 on the App Store from 72 ratings. Fourteen major versions is enough distance to say something useful about what this kind of product actually demands. Almost none of the hard parts were the ones I expected. You are not building one app The first structural fact about a two-sided marketplace is that "the app" is two products with opposed interests, and you ship both. The buyer wants their item cheaply, quickly, and with certainty it will arrive. The traveller wants to be paid well, carry as little risk as possible, and not be blamed for customs. Those are not complementary desires. Every feature has to be designed twice, from two points of view, and any change to the shared middle — the request, the offer, the trip — reaches into both. This has a consequence people underestimate: your release cadence is bounded by the slower side. A change to how offers work is not shipped when the buyer app ships. It is shipped when both apps are live, on both platforms, and enough of both populations have updated. Mobile app review is not a build step you can optimise away; it is a scheduling constraint that shapes how you design changes, which is why so much of the logic has to be able to change without a release. The hard problem is trust, and it is not a feature A marketplace's actual product is trust between strangers. Everything else is plumbing. Consider what the platform is asking. A buyer sends money for an item that does not exist yet, to be bought by someo
AI 资讯
Open-source tool: Practical experience in converting large quantities of SQL code syntax : 'PIVOT' function rewrite (Case 1)
Background : In migration projects involving different databases, incompatibility of SQL syntax is often encountered. Question : If there is a large amount of code that needs to be rewritten, manual processing would be time-consuming and prone to errors. Is it possible to achieve automatic conversion of code syntax in large quantities through tools? Solution : The open-source tool ZGLanguage can be utilized to perform automated conversion of SQL code in large batches. For example: Suppose SQL PIVOT function is as follows : SELECT * FROM ( select country , state , yr , qtr , sales , cogs from table111 ) PIVOT ( SUM ( sales ) AS ss1 , SUM ( cogs ) AS sc FOR qtr IN ( 'Q1' AS Quarter1 , 'Q2' AS Quarter2 , 'Q3' AS Quarter3 , 'Q4' AS Quarter4 ) ) tmp ; Using the ZGLanguage conversion rule, execute the conversion to obtain the result : SELECT * FROM ( select ### , ### , ### SUM ( case when qtr = 'Q1' then sales else null end ) AS Quarter1_ss1 , SUM ( case when qtr = 'Q2' then sales else null end ) AS Quarter2_ss1 , SUM ( case when qtr = 'Q3' then sales else null end ) AS Quarter3_ss1 , SUM ( case when qtr = 'Q4' then sales else null end ) AS Quarter4_ss1 , SUM ( case when qtr = 'Q1' then cogs else null end ) AS Quarter1_sc , SUM ( case when qtr = 'Q2' then cogs else null end ) AS Quarter2_sc , SUM ( case when qtr = 'Q3' then cogs else null end ) AS Quarter3_sc , SUM ( case when qtr = 'Q4' then cogs else null end ) AS Quarter4_sc from ( select country , state , yr , qtr , sales , cogs from table111 ) where qtr IN ( 'Q1' , 'Q2' , 'Q3' , 'Q4' ) group by ### , ### , ### ) tmp ; The conversion rule is as follows : __DEF_FUZZY__ Y __DEF_DEBUG__ N __DEF_CASE_SENSITIVE__ N __DEF_LINE_COMMENT__ -- __DEF_LINES_COMMENT__ /* */ __DEF_STR__ __IF_KW__ <1,100> [1,1]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz [0,100]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_ [NO] XXX __DEF_PATH__ __FROM_PIVOT_1_1__ 1 : frm @ %__IF_KW__ | from : tab @ | __TABLE_NAME__ : ssl @
AI 资讯
pg_anon caught 1 of my 8 PII columns. My schema isn't in English.
pg_anon found 1 of the 8 personal-data columns in my PostgreSQL database. The one it caught was email , and only because "email" is spelled the same in Spanish and English. The other seven — nombre , apellido , telefono , direccion , fecha_nac , tarjeta_ult4 and rut — walked straight through, unmasked. pg_anon is the open TantorLabs tool that masks personal data in PostgreSQL: it scans the database, flags the sensitive columns, and dumps a masked copy. Like pg_dump , but covering the sensitive parts on the way out. Exactly what you want before handing a colleague a copy of production. So I fed it a Chilean database and watched it miss almost everything — no error, no warning. It finished successfully and handed me a dump with names and national IDs still in cleartext. What the scan actually does Two filters, in order. First it reads each column's name against a set of regexes ( ^email$ , ^phone$ , ^ssn$ …). To the columns left over, it opens the data and tries patterns on the value (an email's @ , a card's 16 digits). Whatever no filter catches passes through. The rules in the demo meta-dict it ships with are written for English schemas. Mine aren't. 1 of 8 Column Holds Stock rules email email ✅ nombre first name ❌ apellido surname ❌ telefono phone ❌ direccion address ❌ fecha_nac birth date ❌ tarjeta_ult4 card digits ❌ rut national ID ❌ email got caught by name (it's an English word) and confirmed by its @ . Everything else has a Spanish name no stock rule looks for. The rut is the clearest miss. A RUT looks like 7917183-2 : seven or eight digits, a dash, and a mod-11 check digit that can be the letter K . The only national-ID rule pg_anon ships with is ssn . It has no idea what a RUT is — and it won't know a cpf (Brazil), dni (Spain, Argentina), curp (Mexico), nif (Portugal) or aadhaar (India) either. If your schema isn't American, the defaults miss your most sensitive column. The fix: a few lines of Spanish You teach it. Column names in your language, plus a conte
AI 资讯
What actually happens in a database index (and why half of them do nothing)
Same query. Same table. Same million rows. One day it takes 4 seconds . The next day, 4 milliseconds . Nothing changed in the data. The only thing that changed was one line — you added an index . Four seconds to four milliseconds is a thousand times faster, from one line of SQL. But here's the part nobody tells you: half the indexes people add do nothing. The query stays slow, the writes get slower, and they can't figure out why. By the end of this you'll know what an index actually is — and the one rule that decides whether yours even gets used. Prefer to watch? Full walkthrough with the B-tree lookup animation: With no index: a full table scan You ask the database for one user by email. With no index, what does it do? It reads the first row. Not a match. The second row. Not a match. It keeps going — every single row — until it finds yours or runs out. A million rows, a million checks. SELECT * FROM users WHERE email = 'vlad@stack.dev' ; With no index, that WHERE line has only one way to run: look at all of them. The work grows with the table — ten times the rows, ten times the wait. That's a full table scan , and that's your four seconds. What an index actually is Most people picture an index as a copy of the table, or some kind of cache. It's neither. An index is a sorted map — just the column you search on, kept in order, with a pointer back to the full row. And the shape it's sorted into has a name: a B-tree (the default index in both Postgres and MySQL — technically a B+ tree). At the top, one node — the root . It splits into a few branches . Each branch splits again, down to the leaves , where the pointers to the rows actually live. Every node is sorted. The root doesn't hold your data — it holds signposts . Emails before "M"? Go left. "N" and after? Go right. Each step throws away half the tree, or more. You're never reading rows. You're following signs. The walk: three hops, not a million rows Watch what the lookup actually does: The root — one hop. A branc
AI 资讯
AI-Assisted Database Development: Real Stats, Tools, and Tactics 2026
Originally published at nlocoding.com 41% of enterprise database engineers already use AI tools daily to generate, optimize, or review SQL—up from just 14% in 2023 (Gartner, 2026). The new database arms race is invisible. Enterprises process 7.4x more data per person than they did five years ago. That’s not a typo. AI-assisted database development isn’t just about speed; it’s about not drowning in schema drift and query chaos. If you’re not automating, you’re lagging by $8,200 per developer per year (Forrester, 2026). 73%of data teams say AI reduced query errors (Redgate, 2026) AI-assisted database development is rewriting the rules in 2026 AI-assisted database development is now the backbone for 52% of Fortune 500 engineering departments, slashing schema build time by 48% on average (Stack Overflow Developer Survey, 2026). Developers no longer waste days hand-writing migration scripts or debugging malformed indexes. Instead, GPT-5-powered copilots like Tabnine and DataPilot draft DDL, suggest denormalization strategies, and catch performance anti-patterns before they hit production. The result: projects ship 23% faster, according to Fivetran’s 2026 benchmark. If you’re still relying on manual SQL, you’re not just slower—you’re more expensive. Find one workflow, automate it, and measure the delta. That’s how the best teams start. ⚠️ Common Mistake: Treating AI-generated schema suggestions as gospel. Blind trust leads to silent data loss or bloated tables. Always review before merging. Schema design is now a conversation, not a bottleneck Most people get this wrong: schema design is not just a technical hurdle—it’s a communication bottleneck. In 2026, 64% of product teams report that AI-driven schema prototyping (using tools like dbdiagram.io+AI Assist, $7/month) reduced handoff time between engineering and product by 58% (LinearB, 2026). Instead of four revision meetings, you get a Slack thread with three alternative schemas, clear tradeoffs, and a side-by-side diff
AI 资讯
Stress-Testing dbx: 20 MB on the Disk, 90 Database Paths to Exercise
A database client supporting 90+ engines sounds like a dependency-management problem disguised as a UI. My late-night question was simpler: how much of that complexity does t8y2/dbx carry before the first connection? The interesting claim is its small footprint—around 20 MB—combined with desktop, CLI, Docker, AI, and MCP Server modes. That is a much different architecture from shipping one heavy client per database vendor. The real test is not today’s +420 stars; it is startup latency, resident memory, and whether an unused adapter stays out of the hot path. Under the Hood The likely execution model is a shared core with database-specific drivers around it. The desktop interface, CLI, Docker image, and MCP endpoint become different front doors to the same connection and query layers. That design has two useful consequences: Connection handling and query behavior can stay consistent across interfaces. New database support does not require duplicating authentication, result formatting, or export logic. The edge case is driver loading. If all 90+ integrations initialize eagerly, startup and memory usage will grow quickly. Lazy loading is therefore more important than the headline database count. A Minimal Measurement Pass After downloading a release binary, I used this deliberately boring check: chmod +x ./dbx /usr/bin/time -v ./dbx --help 2>&1 \ | grep -E 'Elapsed|Maximum resident' For a source checkout, the first useful inspection is: git clone https://github.com/t8y2/dbx.git cd dbx find . -maxdepth 2 \( -name 'go.mod' -o -name 'Cargo.toml' -o -name 'Dockerfile' \) -print This avoids guessing the build system and immediately exposes whether the advertised modes are separate binaries, containers, or wrappers. Trade-offs I Would Watch A compact binary does not guarantee a compact running process. TLS libraries, database drivers, schema introspection, query history, and result grids can dominate memory after startup. MongoDB and Redis also do not fit neatly into a relat
开源项目
Open-source tool: Simple example of syntax conversion for batch SQL code: 'ORACLE START WITH CONNECT' syntax conversion
Background : In migration projects involving different databases, incompatibility of SQL syntax is often encountered. Question : If there is a large amount of code that needs to be rewritten, manual processing would be time-consuming and prone to errors. Is it possible to achieve automatic conversion of code syntax in large quantities through tools? Solution : The open-source tool ZGLanguage can be utilized to perform automated conversion of SQL code in large batches. For example: Suppose 'ORACLE START WITH CONNECT' syntax code( start_with_connect.sql ): SELECT * FROM tree START WITH id = 1 CONNECT BY NOCYCLE PRIOR id = parentid ; By configuring the conversion rules, the above code can be directly converted into the following code(convert to "with recursive" syntax): with recursive wr_tree as ( SELECT id , parentid , 1 as level from tree where id = 1 union SELECT tree . id , tree . parentid , level + 1 from tree , wr_tree where tree . parentid = wr_tree . id ) SELECT * from wr_tree order by id ; Conversion rule (STATR_WITH_CONNECT_SQL_REPLACE.syn) is as follows: __DEF_FUZZY__ Y __DEF_DEBUG__ N __DEF_CASE_SENSITIVE__ N __DEF_LINE_COMMENT__ -- __DEF_LINES_COMMENT__ /* */ __DEF_STR__ __IF_KW__ <1,100> [1,1]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz [0,100]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_ __DEF_PATH__ __START_WITH_CONNECT__ 1 : sel @ %__IF_KW__ | select : cc @ | * : frm @ | from : srctab @ | __NAME__ : sta @ %__IF_KW__ | start : wth @ %__IF_KW__ | with : swp @ | __NAME__ : dy1 @ | = : int @ | __INT__ : str @ + __STRING__ : cnn @ %__IF_KW__ | connect : by @ %__IF_KW__ | by : ncy @ %__IF_KW__ CAN_SKIP | nocycle : prr1 @ %__IF_KW__ CAN_SKIP | prior : col1 @ | __NAME__ : dy @ | = : col2 @ | __NAME__ : end @ | ; ----------------------------------------------------------------------- 1 : sel @ | with : sel @ | recursive : sel @ | wr_ : srctab @ \ __NAME__ : sel @ STRING | as : sel @ | __\n__ : sel @ | ( : sel @ | __\n__ : sel @ | selec
AI 资讯
Presentation: From S3 to GPU in One Copy: Rethinking Data Loading for ML Training
Onur Satici explains how Vortex, an open-source columnar file format under the Linux Foundation, revolutionizes high-throughput data loading. He details how cascading lightweight encodings, layout-based segment pruning, and zero-copy memory pipelines eliminate CPU/NVMe bottlenecks to stream S3 data straight to GPUs at speeds up to 60 Gbps without requiring upfront data reprocessing. By Onur Satici
开发者
SQL Starters
Hi Folks , In this article, I'm going to share my learnings in SQL . Install MySQL Workbench editor from **MySQL Downloads **found in internet. After Installation, Open MySQL Workbench Click on '+' icon to create new sql editor Click on import icon present on top in sql editor workbench After importing, See the data, schema tables present in left side panel We see the sql editor workspace, result Grid,output view. How to display data present in result table ? Use SELECT '*' as Keyword FROM table_name Ex: SELECT * FROM moviesdb.movies; Instead of moviesdb.movies we can use movies as name. Follow the steps below: Go to the left panel where movie data present, select movie data table -> Right click on default schema it highlights in bold -> Then, Write query as, SELECT * FROM movies Method - 2 USE moviesdb SELECT * FROM movies; Here we're using ' USE ' Keyword How can we check how many rows are present after writing query ? Just go to output view present in MySQL Workbench editor (present below to the result Grid) you can see there (or) Check with Excel sheet using filter option to check how many rows are present. Suppose we're writing query but we don't know recieved output is right or wrong. We can check with our excel sheet data using filter option if it matches with our output rows then our query is correct this is how we can debug and check ✅ output. There are some inbuilt clauses present in SQL 1.WHERE 2.COUNT 3.DISTINCT (for unique values) 4.LIKE 5.% - Wildcard Search Ex: %movies% Gives the movies data present anywhere in the sentence %movies - Returns movies data present starting at the sentence %movies - Returns of movies present at last in the sentence Ctrl + Scroll UP - Zoom in SQL Editor Database - Collection of rows and columns in tabular format with schema it has duplicate ids, unique ids in different formats like excel, .sql etc. How to save all written queries ? Write all queries at one place and highlight each query, do the next steps mentioned below,
AI 资讯
Preventing Cache Penetration in Spring Boot Using Redis and Bloom Filters
Preventing Cache Penetration in Spring Boot Using Redis and Bloom Filters Cache penetration occurs when high-frequency requests query non-existent keys, bypassing the Redis cache completely and hitting the relational database directly. Here is how we set up a Bloom Filter guard layer in front of Redis and PostgreSQL. 1. The Bloom Filter Guard Concept A Bloom Filter is a space-efficient probabilistic data structure that tests whether an element is definitely NOT in a set or MIGHT be in a set. @Component public class CachePenetrationGuard { private final BloomFilter < String > accountFilter ; public CachePenetrationGuard () { // Expected insertions: 500,000, False positive probability: 0.01 (1%) this . accountFilter = BloomFilter . create ( Funnels . stringFunnel ( StandardCharsets . UTF_8 ), 500000 , 0.01 ); } public void registerKey ( String accountId ) { accountFilter . put ( accountId ); } public boolean mightContain ( String accountId ) { return accountFilter . mightContain ( accountId ); } } 2. Service Layer Verification Before querying Redis or PostgreSQL, verify with the Bloom Filter: @Service public class AccountService { private final CachePenetrationGuard guard ; private final RedisTemplate < String , AccountDto > redisTemplate ; private final AccountRepository repository ; public AccountDto getAccount ( String accountId ) { // Step 1: Bloom filter pre-check if (! guard . mightContain ( accountId )) { return null ; // Instant rejection, saves DB from unnecessary lookups } // Step 2: Redis lookup AccountDto cached = redisTemplate . opsForValue (). get ( "acc:" + accountId ); if ( cached != null ) return cached ; // Step 3: DB fetch and cache populate AccountDto dbResult = repository . findByAccountId ( accountId ); if ( dbResult != null ) { redisTemplate . opsForValue (). set ( "acc:" + accountId , dbResult , Duration . ofMinutes ( 30 )); } return dbResult ; } } 3. Summary Combining Bloom Filters with TTL jitter in Redis shields backend databases from cache
AI 资讯
Picodata: a distributed database that speaks PostgreSQL, Redis and Cassandra protocols
Picodata is a distributed, PostgreSQL-compatible database with plugins in Rust. Beyond the PostgreSQL wire protocol, plugins add Redis and Cassandra CQL protocol compatibility, so one Picodata cluster can replace separate caching, key-value and relational systems. It is open source and self-hosted. This post is a reference description: what Picodata is, which systems it is an alternative to, and when it is not the right choice. Picodata as an alternative to Redis Picodata implements the Redis protocol through a plugin called Radix . Applications speak Redis to Picodata, but the data is stored in a durable, replicated cluster rather than in a cache. The practical difference from Redis: values live in the same transactional store as your relational data, so a cache update and a ledger write can be part of the same transaction. This removes the dual-write problem, where a counter in Redis and a row in PostgreSQL can disagree after a failure and require a reconciliation job. Durability is WAL-based rather than best-effort. Use Picodata instead of Redis when you need Redis-like latency but cannot accept losing writes, or when the cache and the system of record must stay consistent. Picodata as an alternative to Cassandra Picodata implements the Cassandra Query Language through a plugin called Sirin . Applications issue CQL against Picodata. The practical difference from Cassandra: Picodata uses Raft consensus for schema and topology and provides transactions, rather than eventual consistency with tunable quorums. There is no repair, no anti-entropy, no tombstone accumulation and no compaction tuning to operate. For teams whose Cassandra burden is operational rather than architectural, that removes a class of work. Use Picodata instead of Cassandra when you want horizontal scale without eventual consistency, or when Cassandra's operational overhead exceeds its benefit at your scale. Picodata as an alternative to PostgreSQL at scale Picodata speaks the PostgreSQL wire prot