# Frequently Asked Questions

Common questions and answers about Biscuit index for PostgreSQL.

---

## General Questions

### What is Biscuit?

Biscuit is a PostgreSQL index access method designed for LIKE and ILIKE pattern matching queries. It uses bitmap-based indexing to accelerate searches with wildcards (`%`, `_`). Performance improvements vary depending on your data characteristics, query patterns, and system configuration.

---

### When should I use Biscuit?

Consider Biscuit when you:
- Run frequent LIKE queries with wildcards
- Need to search across multiple text columns
- Have high-cardinality string columns
- Want to optimize queries with pattern matching
-  Need prefix, suffix, or substring matching

**Other options may be better for**:
- Full-text search with stemming/ranking (use tsvector/GIN)
- Very long strings (>256 chars are truncated)
- Columns with very few distinct values


---

### Is Biscuit production-ready?

Biscuit includes:
- Full CRUD support (INSERT, UPDATE, DELETE)
- Automatic index maintenance
- Multi-column indexes
- Multiple performance optimizations

However, as with any index type, we recommend:
1. Test thoroughly in your staging environment
2. Benchmark with your actual data and queries
3. Monitor performance metrics
4. Have a rollback plan
5. Start with non-critical workloads



---

### How much memory does Biscuit use?

Memory usage depends on:
- Number of records
- Average string length
- Number of indexed columns
- Character distribution in your data

The index is stored in memory for performance. For large tables, ensure you have adequate RAM. Test with your actual data to determine memory requirements.

**Monitor with**:
```sql
SELECT biscuit_size_pretty('idx_name');
```

---

## Installation & Setup

### How do I install Biscuit?

See the [Installation Guide](installation.md) for detailed instructions.

Quick steps:
```bash
# Ubuntu/Debian
sudo apt-get install postgresql-server-dev-16 build-essential
git clone https://github.com/crystallinecore/biscuit.git
cd biscuit
make
sudo make install
```

Then in PostgreSQL:
```sql
CREATE EXTENSION biscuit;
```

---

### Installation fails with "could not load library"

**Problem**: PostgreSQL can't find `biscuit.so`

**Solution**:
```bash
# Find PostgreSQL library directory
pg_config --pkglibdir

# Verify file exists
ls $(pg_config --pkglibdir)/biscuit.so

# If missing, reinstall
cd biscuit
sudo make install
```

---

### Extension creation fails: "extension does not exist"

**Problem**: Extension control files not in correct location

**Solution**:
```bash
# Check extension directory
pg_config --sharedir

# Verify files
ls $(pg_config --sharedir)/extension/biscuit*

# Should see:
# biscuit.control
# biscuit--1.0.sql

# If missing, reinstall
sudo make install
```

---

### Should I install with CRoaring support?

**Yes, recommended** for production use.

CRoaring provides:
- Better memory compression
- More efficient set operations

Install:
```bash
# Ubuntu/Debian
sudo apt-get install libroaring-dev

# Then build Biscuit
make HAVE_ROARING=1
sudo make install
```

Without CRoaring, Biscuit uses a fallback implementation that's slower but still functional.

---

## Index Creation

### How do I create a Biscuit index?

**Single column**:
```sql
CREATE INDEX idx_name ON table_name 
USING biscuit (column_name);
```

**Multiple columns**:
```sql
CREATE INDEX idx_multi ON table_name 
USING biscuit (col1, col2, col3);
```

See [Quick Start Tutorial](quickstart.md) for examples.

---

### How long does index creation take?

Build time varies significantly based on:
- Table size
- Number of columns
- Average string length
- Available memory
- System load

**Benchmark with your data** to determine actual build times.

**For large tables**, use CONCURRENTLY:
```sql
CREATE INDEX CONCURRENTLY idx_name ON table_name 
USING biscuit (column_name);
```

---

### Can I create partial Biscuit indexes?

**Yes!** Use a WHERE clause:

```sql
-- Index only active users
CREATE INDEX idx_active_users ON users 
USING biscuit (username, email)
WHERE status = 'active';

-- Index only recent orders
CREATE INDEX idx_recent_orders ON orders 
USING biscuit (customer_name)
WHERE created_at > '2024-01-01';
```

**Benefits**:
- Smaller index size
- Faster queries on filtered data
- Reduced maintenance overhead

---

### How many columns can I index?

While there's no hard limit enforced, indexing many columns increases:
- Index size
- Build time
- Memory usage
- Maintenance overhead

**Recommendation**: Index only columns you frequently query with LIKE patterns.

**Test performance** with your specific column combinations.

---

## Query Performance

### Why is my query not using the index?

**Check with EXPLAIN**:
```sql
EXPLAIN ANALYZE
SELECT * FROM products WHERE name LIKE '%laptop%';
```

**Common causes**:

1. **Statistics out of date**
   ```sql
   ANALYZE products;
   ```

2. **Pattern matches too many rows**
   ```sql
   -- Check selectivity
   SELECT COUNT(*) FROM table WHERE col LIKE '%pattern%';
   ```

3. **Wrong column indexed**
   ```text
   -- Check which columns are indexed
   \d products
   ```

4. **Planner estimates sequential scan is faster**
   ```sql
   -- Test with index forced (testing only!)
   SET enable_seqscan = off;
   ```

Always verify index usage with EXPLAIN ANALYZE before and after creating indexes.

---

### How can I measure query performance?

**Use EXPLAIN ANALYZE**:
```sql
EXPLAIN ANALYZE
SELECT * FROM products WHERE name LIKE '%pattern%';
```

Look for:
- Execution time
- Index scan vs sequential scan
- Rows processed
- Planning time

**Compare before and after** creating the index to measure improvement.

Performance varies based on:
- Data characteristics
- Pattern selectivity
- System resources
- Concurrent load

Always benchmark with your actual workload.

---

### Does Biscuit support case-insensitive search?

**Yes**, from versions >= 2.1.0:

```sql
-- Create index 
CREATE INDEX idx_name ON products USING biscuit (name);

-- Query
SELECT * FROM products WHERE name ILIKE '%wireless%';
```

---

### Can I use OR conditions with Biscuit?

**Yes**, but be aware of performance:

```sql
-- Uses Biscuit (efficient)
SELECT * FROM products 
WHERE name LIKE '%laptop%'
   OR name LIKE '%desktop%';

-- Better: Combine patterns when possible
SELECT * FROM products 
WHERE name LIKE '%laptop%' 
   OR name LIKE '%desktop%'
   OR name LIKE '%tablet%';
```

PostgreSQL will use bitmap OR to combine results.

---

### Does Biscuit support regular expressions?

**No.** Biscuit only supports SQL LIKE/ILIKE patterns (`%`, `_`).

For regex, use:
- PostgreSQL's `~` operator with GIN trigram index
- Full-text search with tsvector

**Example**:
```sql
-- Regex (not Biscuit)
SELECT * FROM products WHERE name ~ 'laptop|desktop';

-- LIKE (uses Biscuit)
SELECT * FROM products WHERE name LIKE '%laptop%';
```

---

### Does Biscuit optimize COUNT(*) queries?

Biscuit includes optimizations for aggregate queries like COUNT(*):

```sql
-- May benefit from aggregate optimizations
SELECT COUNT(*) FROM products WHERE name LIKE '%laptop%';
```

The index can process bitmap operations without fetching tuples, which can improve performance for certain query patterns.

**Test with your queries** to measure the actual benefit.

---

### Can I use LIMIT with Biscuit?

**Yes**. Biscuit works with LIMIT clauses:

```sql
SELECT * FROM products 
WHERE name LIKE '%gaming%'
LIMIT 10;
```

The index includes optimizations for queries with LIMIT, though the actual performance benefit depends on your data and query patterns.

---

## Index Maintenance

### Do I need to manually maintain the index?

**No.** Biscuit automatically maintains itself:
- INSERT: Adds new records
- UPDATE: Removes old, adds new
- DELETE: Marks as tombstone

PostgreSQL's VACUUM handles cleanup.

---

### What are tombstones?

**Tombstones** are deleted records tracked in memory until cleanup.

Check tombstone count:
```sql
SELECT biscuit_index_stats('idx_name'::regclass);
```

Output:
```
Tombstones: 245
```

**Automatic cleanup** triggers at 1000 tombstones.

**Manual cleanup**:
```sql
VACUUM table_name;
-- or
REINDEX INDEX idx_name;
```

---

### When should I rebuild the index?

Consider rebuilding when:
- ✅ Significant data changes have occurred
- ✅ Index statistics show high tombstone counts
- ✅ Query performance has degraded
- ✅ After major PostgreSQL version upgrades

**How to rebuild**:
```sql
-- Non-blocking rebuild
CREATE INDEX CONCURRENTLY idx_new ON table_name 
USING biscuit (column_name);

DROP INDEX idx_old;
ALTER INDEX idx_new RENAME TO idx_old;
```

Monitor index health regularly to determine when rebuilding is beneficial.

---

### How do I monitor index health?

**Use the diagnostic function**:
```sql
SELECT biscuit_index_stats('idx_name'::regclass);
```

**Key metrics provided**:
- **Active records**: Current valid records
- **Total slots**: Allocated memory slots
- **Free slots**: Reusable slots from deletes
- **Tombstones**: Deleted but not cleaned records
- **Max length**: Longest indexed string
- **CRUD statistics**: Insert/update/delete counts

**Create monitoring view**:
```sql
CREATE VIEW biscuit_health AS
SELECT 
    indexrelid::regclass as index_name,
    biscuit_index_stats(indexrelid) as stats
FROM pg_index
WHERE indexrelid::regclass::text LIKE '%biscuit%';
```

Monitor these metrics over time to understand index behavior and maintenance needs.

---

### Does Biscuit support parallel operations?

Biscuit includes support for parallel bitmap scans during query execution. Parallel index building is not currently implemented.

Whether parallel queries are used depends on PostgreSQL's query planner and your configuration settings.

---

## Troubleshooting

### Queries are slower than expected

**Debug checklist**:

1. **Verify index is being used**
   ```sql
   EXPLAIN ANALYZE SELECT * FROM table WHERE col LIKE '%pattern%';
   -- Should show: Index Scan using idx_name
   ```

2. **Check pattern selectivity**
   ```sql
   -- How many rows match?
   SELECT COUNT(*) FROM table WHERE col LIKE '%pattern%';
   -- High match percentage may make index less beneficial
   ```

3. **Update statistics**
   ```sql
   ANALYZE table_name;
   ```

4. **Check index health**
   ```sql
   SELECT biscuit_index_stats('idx_name'::regclass);
   ```

5. **Review memory settings**
   ```sql
   SHOW work_mem;
   SHOW shared_buffers;
   -- See [Performance Tuning](performance.md)
   ```

6. **Compare with baseline**
   - Measure query time without the index
   - Document before/after performance
   - Consider data characteristics

---

### Index build fails with out of memory

**Problem**: Not enough RAM for index construction

**Solutions**:

1. **Increase maintenance_work_mem**
   ```sql
   SET maintenance_work_mem = '2GB';
   CREATE INDEX ...
   ```

2. **Build during low-traffic period**

3. **Consider partial index**
   ```sql
   -- Index subset of data
   CREATE INDEX idx_recent ON table 
   USING biscuit (col)
   WHERE created_at > '2024-01-01';
   ```

4. **Add more RAM to server**

---

### Crashes or unexpected restarts

Index state is WAL-logged, so after an abrupt shutdown PostgreSQL replays WAL
on startup and the index is recovered along with the heap. Committed changes
are present, uncommitted ones are not, and **no manual rebuild is expected**.

If an index does appear inconsistent after a restart, that is worth reporting.

**Possible causes**:

1. **Memory corruption**: Ensure CRoaring is properly installed
2. **PostgreSQL crash**: Check PostgreSQL logs
3. **Extension bug**: Report at GitHub Issues

**If a rebuild is needed anyway**:
```sql
-- Drop and rebuild index
DROP INDEX idx_name;
CREATE INDEX idx_name ON table USING biscuit (col);

-- Or reindex
REINDEX INDEX idx_name;
```

---

### "Index is not valid" error

**Cause**: Index build failed or was interrupted

**Solution**:
```sql
-- Drop invalid index
DROP INDEX idx_name;

-- Rebuild
CREATE INDEX CONCURRENTLY idx_name ON table 
USING biscuit (col);
```

---

### Pattern not matching expected rows

**Check pattern syntax**:
```sql
-- Case-sensitive!
SELECT * FROM products WHERE name LIKE '%Mouse%';  -- Matches "Mouse"
SELECT * FROM products WHERE name LIKE '%mouse%';  -- Matches "mouse"

-- Underscore is single-character wildcard
SELECT * FROM products WHERE sku LIKE 'PROD-___';  -- Exactly 3 chars
```

**Test without index**:
```sql
SET enable_indexscan = off;
SELECT * FROM products WHERE name LIKE '%pattern%';
-- Compare results
```

---

## Advanced Topics

### Can I use Biscuit with partitioned tables?

**Yes!** Create indexes on each partition:

```sql
-- Create partitioned table
CREATE TABLE orders (
    id SERIAL,
    customer_name TEXT,
    created_at DATE
) PARTITION BY RANGE (created_at);

-- Create partitions
CREATE TABLE orders_2024_q1 PARTITION OF orders
    FOR VALUES FROM ('2024-01-01') TO ('2024-04-01');

-- Create Biscuit index on partition
CREATE INDEX idx_orders_2024_q1 ON orders_2024_q1
USING biscuit (customer_name);
```

**Note**: Each partition needs its own index.

---

### Does Biscuit work with replication?

**Yes.** Biscuit indexes work with:
- ✅ Streaming replication
- ✅ Logical replication
- ✅ Hot standby

**Caveat**: Indexes are built independently on each server.

---

### Can I use Biscuit in read replicas?

**Yes.** Create the index on the primary; it reaches physical standbys through
the ordinary WAL stream, with no Biscuit-specific step required.

```sql
-- On primary
CREATE INDEX idx_name ON table USING biscuit (col);

-- On a physical standby, once replay catches up, the index is present
-- and available to index scans. No REINDEX is required.
```

Hot standbys serve index scans from the replicated index. Point-in-time
recovery restores index state to the recovery target in the same way.

---

### How does Biscuit handle NULL values?

**NULL values are not indexed.**

```sql
-- Create index
CREATE INDEX idx_name ON users USING biscuit (middle_name);

-- This uses index
SELECT * FROM users WHERE middle_name LIKE '%Smith%';

-- This does NOT use index (NULL check)
SELECT * FROM users WHERE middle_name IS NULL;
```

**For NULL queries**, add separate condition:
```sql
WHERE middle_name IS NULL
   OR middle_name LIKE '%pattern%'
```


---

### Does Biscuit support multi-byte characters (Unicode)?

**Yes**, Biscuit supports UTF-8 encoding:

```sql
-- Japanese, Chinese, Arabic, emoji, etc.
CREATE INDEX idx_name ON products USING biscuit (name);

-- Query with multi-byte characters
SELECT * FROM products WHERE name LIKE '%日本%';
```

---

## Migration & Compatibility

### How do I migrate from GIN trigram?

**Evaluate first**:

```sql
-- 1. Create Biscuit index alongside GIN
CREATE INDEX idx_biscuit ON table USING biscuit (col);

-- 2. Test queries with both
EXPLAIN ANALYZE SELECT * FROM table WHERE col LIKE '%pattern%';

-- 3. Compare performance with your actual queries
-- Document query times, index sizes, and maintenance costs

-- 4. If Biscuit meets your needs better, consider transition
DROP INDEX idx_gin_trigram;

-- 5. Keep Biscuit
```

Different index types have different strengths. Choose based on your specific workload requirements.

---

### Can I have both B-tree and Biscuit on same column?

**Yes**, and it's often beneficial:

```sql
-- B-tree for exact matches and ORDER BY
CREATE INDEX idx_name_btree ON products (name);

-- Biscuit for LIKE patterns
CREATE INDEX idx_name_biscuit ON products USING biscuit (name);
```

PostgreSQL will choose the appropriate index automatically.

---

### How do I uninstall Biscuit?

```sql
-- 1. Drop all Biscuit indexes
DROP INDEX idx1, idx2, idx3;

-- 2. Drop extension (drops any remaining indexes)
DROP EXTENSION biscuit CASCADE;
```

```bash
# 3. Remove files
sudo rm $(pg_config --pkglibdir)/biscuit.so
sudo rm $(pg_config --sharedir)/extension/biscuit*
```

---

## Getting Help

### Where can I get support?

-  **Documentation**: [ReadTheDocs](https://biscuit.readthedocs.io)
-  **Discussions**: [GitHub Discussions](https://github.com/crystallinecore/biscuit/discussions)
-  **Bug Reports**: [GitHub Issues](https://github.com/crystallinecore/biscuit/issues)
-  **Email**: sivaprasad.off@gmail.com

---

### How do I report a bug?

**Include in your report**:
1. PostgreSQL version: `SELECT version();`
2. Biscuit version: `SELECT * FROM pg_extension WHERE extname = 'biscuit';`
3. Table schema: `\d table_name`
4. Index definition: `\d+ index_name`
5. Query that fails: `EXPLAIN ANALYZE ...`
6. Error messages from PostgreSQL logs

**Submit at**: [GitHub Issues](https://github.com/crystallinecore/biscuit/issues)

---

### How can I contribute?

We welcome contributions!

- **Code**: Submit pull requests
-  **Documentation**: Improve docs
-  **Testing**: Test with your data
-  **Ideas**: Suggest features
-  **Bugs**: Report issues

---

### Is there a Slack/Discord community?

**Not yet!** 

---

## Roadmap

### What features are being considered?

Future development may include:
- Enhanced parallel index builds
- Additional compression options
- Extended monitoring capabilities

**Long-term possibilities**:
- Incremental cache refresh in place of full reload on invalidation
- Reduced write amplification
- Approximate matching capabilities
- Additional pattern matching features
- Enhanced cloud optimizations

Development priorities are based on community feedback and usage patterns. Features listed here are under consideration but not guaranteed for any specific timeline.

---

## Performance Comparisons

### How does Biscuit compare to other indexes?

Performance characteristics vary significantly based on:
- Data distribution
- Query patterns
- Hardware specifications
- PostgreSQL configuration
- Concurrent workload

**General considerations**:

**B-tree**:
- Excellent for exact matches and range queries
- Good for prefix patterns with concrete characters
- Not suitable for suffix or substring patterns

**GIN (trigram)**:
- Designed for full-text and trigram matching
- Larger index size
- Different optimization characteristics

**Biscuit**:
- Optimized for LIKE/ILIKE pattern matching
- Bitmap-based approach
- In-memory index structures
- Multi-column query optimization

**Always benchmark with your specific workload** to make informed decisions. Test with:
- Your actual data
- Representative queries
- Expected query volume
- Production-like hardware

---

## Still Have Questions?

Can't find your answer? 

- Check the [Installation Guide](installation.md)
- Read the [Quick Start](quickstart.md)
- Browse [Performance Tuning](performance.md)
- Contact us: sivaprasad.off@gmail.com

---

**Happy pattern matching! 🚀**

