QoreDB LogoQoreDB
Back to blog
ProduitTechnical journal

Full-Text Search in QoreDB: Scanning Every Table in a Database

When you're working on a database you don't know well yet, or when you're looking for a specific value without knowing which table it's in, searching manually table by table is slow and frustrating. It's a common need among developers who debug in production or take over an…

Raphaël – Creator of QoreDBRaphaël – Creator of QoreDB
5 min readUpdated Jul 18, 2026
Full-Text Search in QoreDB: Scanning Every Table in a Database

When you're working on a database you don't know well yet, or when you're looking for a specific value without knowing which table it's in, searching manually table by table is slow and frustrating. It's a common need among developers who debug in production or take over an existing project.

QoreDB includes a global full-text search that scans every table in a connected database to find a string. The mechanism relies on per-driver strategies, parallel execution with timeouts, and automatic detection of existing full-text indexes.

A search strategy per engine

Each database engine has its own capabilities when it comes to text search. PostgreSQL exposes tsvector and GIN/GiST indexes. MySQL offers FULLTEXT indexes. MongoDB provides $text indexes and pattern matching via $regex. SQLite, for its part, can use the FTS extensions if they are enabled.

Rather than imposing a single abstraction, QoreDB defines a Rust FulltextSearchStrategy trait that each driver implements. This trait exposes four responsibilities: detecting the full-text indexes on a table, analyzing the available text columns, building the optimal search query, and providing a fallback based on LIKE or ILIKE when no native index is available.

On PostgreSQL, if the table has a GIN index on a tsvector column, QoreDB generates a query using to_tsquery with the :* prefix for partial matching. Otherwise, it builds a series of ILIKE conditions on the text columns. On MySQL, the logic is identical: MATCH...AGAINST in boolean mode if a FULLTEXT index exists, LIKE otherwise. On MongoDB, the search goes through a $text if a text index is present, or through a $regex on each string field of the document.

Parallel execution and timeouts

Scanning every table in a database can be expensive. A database with 200 tables and millions of rows can't be traversed sequentially without freezing the interface. QoreDB uses the tokio runtime to launch the searches in parallel, in batches of 5 concurrent tables (configurable). Each search on an individual table is bounded by a 5-second timeout. If a table doesn't respond within that window, it's marked as timed out and the search continues on the others.

The results arrive progressively thanks to the Tauri event mechanism. The frontend receives progress events indicating how many tables have been scanned, how many results have been found, and which table is currently being processed. The user sees the results appear as they come in, without waiting for the full scan to finish.

Capability detection and caching

Before running the search on a table, QoreDB executes a detection query to identify the full-text indexes present. On PostgreSQL, it queries pg_class, pg_index, and pg_am to find the GIN or GiST indexes associated with tsvector columns. On MySQL, it reads the INFORMATION_SCHEMA metadata to spot FULLTEXT indexes.

These detections are cached for 5 minutes in a global CapabilityCache, protected by an asynchronous RwLock. As long as the cache is valid, subsequent searches on the same table reuse the already-computed strategy without re-querying the metadata. This cache is invalidated automatically after expiry or when it exceeds 1000 entries.

Smart column filtering

To avoid scanning columns where a text search makes no sense, QoreDB filters columns by type. Only columns whose type contains char, text, varchar, json, xml, uuid, or enum are included in the scan. Numeric, binary, or date columns are excluded. System tables (pg_catalog, information_schema, mysql, sys) and tables whose name begins with pg_ or _ are also ignored.

SQLite is an exception: because its types are flexible and any column can contain text, all columns are included in the search. It's a pragmatic choice suited to the reality of the engine.

The search interface

On the frontend, full-text search opens in a dedicated modal panel. The input is debounced at 300 ms to avoid overloading the backend while typing. The results are grouped by table, with a match counter per group. Each result displays the column name, a preview of the found value with the searched term highlighted, and an excerpt of the row's other columns to provide context.

A click on a result opens the relevant table directly, with a pre-filled filter on the column and the searched value. The statistics bar at the bottom of the panel shows the total number of matches, the number of tables scanned, and the execution time. If the results are truncated (beyond 100 results by default), a visual indicator signals it.

A switch enables case-sensitive search, which changes both the backend query (LIKE instead of ILIKE on PostgreSQL, for example) and the highlighting on the frontend.

In practice

On an 80-table PostgreSQL database, a typical full-text search takes between 1 and 3 seconds. Tables with GIN indexes respond in a few milliseconds; tables without an index are slower but stay within the timeout budget. The most relevant results arrive first thanks to parallelism: the fast tables surface their results before the slow tables have finished.

The search is deliberately bounded: 10 results maximum per table, 100 in total, a 5-second timeout per table. These limits are there to ensure the interface stays responsive, even on large databases. If a user wants to explore more deeply, clicking on a result redirects them to the table with the filter applied, where they can paginate normally.

QoreDB's full-text search is designed as a quick exploration tool, not as an exhaustive search engine. It takes advantage of each engine's native capabilities when they exist, and falls back to simple pattern matching when they don't. The result is a tool that works everywhere, across all supported drivers, with a predictable cost and a clear interface.

Newsletter

Stay updated on new releases

Subscribe to get product releases, new drivers notifications, and technical tutorials.

🎁 Bonus: Get our free SQL Performance Cheat Sheet — 9 pages, PostgreSQL / MySQL / SQLite (PDF)!
Share
Full-Text Search in QoreDB: Scanning Every Table in a Database - Blog - QoreDB