# SingleStore Helios Documentation
---
# AI
SingleStore’s AI Services offer a comprehensive set of features that bring built-in intelligence, seamless AI/ML model integration, and scalable AI-powered workflows directly to SingleStore databases.
These features include:
* **Database Integration**: AI Services connect directly to SingleStore, eliminating data movement while enabling models and functions to execute with low latency on real-time data. They provide easy integration with SingleStore pipelines and notebooks.
* **In-Database Analytics**: AI Services run alongside SQL queries, enabling inference, real-time insights, multi-database integration, and LLM-powered workflows directly in SingleStore.
* **Secure Isolation**: AI services provide role-based access control (RBAC) at the database level, securing both data and the associated AI applications.
* **Scalability**: AI applications scale automatically based on their workload.
* **Monitoring**: Built-in logging and metrics track workload performance, inference latency, and model accuracy for full observability.
## In this section
* [Aura Analyst](https://docs.singlestore.com/cloud/ai/aura-analyst.md)
* [AI & ML Functions](https://docs.singlestore.com/cloud/ai/ai-ml-functions.md)
* [Models](https://docs.singlestore.com/cloud/ai/models.md)
* [SingleStore MCP Server](https://docs.singlestore.com/cloud/ai/singlestore-mcp-server.md)
* [SingleStore AI Rules](https://docs.singlestore.com/cloud/ai/singlestore-ai-rules.md)
***
Modified at: August 4, 2026
Source: [/cloud/ai/](https://docs.singlestore.com/cloud/ai/)
(An index of the documentation is available at /llms.txt)
---
# AI & ML Functions
> **📝 Note**: This is a Preview feature.
## Overview
AI & ML Functions enable running generative AI models, embedding models, and machine learning (ML) models directly on the data using simple SQL commands in SingleStore. This eliminates the need for data movement, reducing latency, cost, and complexity.
AI & ML Functions are delivered as preconfigured, managed Python User-Defined Functions (UDFs) that run in optimized containers within [SingleStore Aura](https://docs.singlestore.com/cloud/container-services.md). This containerized design provides a secure, fully managed execution environment for building and running AI & ML workloads.
AI & ML Functions enable SQL-based execution tasks such as sentiment analysis, summarization, and translation without requiring additional frameworks, external API integrations, or complex pipelines.
AI & ML Functions run alongside SingleStore Helios, delivering results in milliseconds. Combined with SingleStore’s HTAP architecture, these functions run on real-time operational data as soon as it is created.
## In this section
* [AI Functions](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ai-functions.md)
* [ML Functions](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ml-functions.md)
* [Shared Embedding Model Service](https://docs.singlestore.com/cloud/ai/ai-ml-functions/shared-embedding-model-service.md)
***
Modified at: August 4, 2026
Source: [/cloud/ai/ai-ml-functions/](https://docs.singlestore.com/cloud/ai/ai-ml-functions/)
(An index of the documentation is available at /llms.txt)
---
# AI Functions
## Install AI Functions
To install AI Functions, navigate to **AI > AI & ML Functions**, select the cluster on which to install AI Functions. In the **AI Functions** tab, select **Install**, review the **AI Functions Summary** and then select **Deploy**.
Once the AI Functions are installed, query them in the SQL Editor or SingleStore notebooks. SingleStore provides the following AI Functions:
| **Category** | **Function** |
| --------------------------------------------------------------- | -------------------------- |
| Text Processing Functions | `AI_COMPLETE(text, model)` |
| `AI_SENTIMENT(text, model)` | |
| `AI_TRANSLATE(text, source_languages, target_languages, model)` | |
| `AI_SUMMARIZE(text, model, max_lengths)` | |
| `AI_CLASSIFY(text, categories, model)` | |
| `AI_EXTRACT(text, questions, model)` | |
| Embedding Function | |
| `EMBED_TEXT(text, model)` | |
## Edit AI Functions
To edit AI Functions, navigate to **Settings** in the right navigation of the **AI Functions** tab and select **Edit**. Alternatively, select the ellipsis (vertical three dots) in the right and select **Edit AI Functions**. On the **Edit AI Functions** page, view or select the following:
| **ClusterGroup** | Theclustergroup in which the AI Function is installed and running. |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Models** | Default models used by AI Functions for inference and embedding.
- LLM Model: Uses Anthropic’s Claude model family for inference.
- Embedding Model: Uses an optimized embedding model for text vectorization. Supported models include the Qwen and Amazon Titan embedding families.
|
| **Settings** | - Container Region: Select the region of your container.
- Scaling: Select the minimum and maximum active replica.
📝 Note:
Auto-scale depends upon the container load.
|
| **Cost Estimation** | View the cost estimation of LLM Model, Embedding Model, and Compute. In Compute, runtime cost scales with the replica count. |
| **Region** | View the region of the following: - Cluster Group
- Container
- LLM Model
- Embedding Model
|
Select **Next**, review the changes, and select **Save** to save your settings.
## Uninstall AI Functions
To uninstall AI Functions, select the ellipsis (vertical three dots) in the right and then select **Uninstall AI Functions**. Confirm the uninstallation and select **Uninstall**.
## Text Processing Functions
## AI\_COMPLETE
Provides batched LLM powered completion of every input text. Used for general purpose text generation, completion, and complex reasoning.
## Syntax
```sql
AI_COMPLETE(text, model)
```
## Arguments
* `text`: A prompt.
* `model`: An LLM model.
## Return Type
`string`
## Usage
| Basic usage with the default model | `SELECT cluster.AI_COMPLETE('Life is like a box of') AS completion;` |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Basic usage with a specific model | `SELECT cluster.AI_COMPLETE('Life is like a box of', model => 'anthropic-claude-3-5-haiku') as completion;` |
| Input example on database | `SELECT cluster.AI_COMPLETE(column_1) FROM table;` |
## AI\_SENTIMENT
Provides sentiment classification and score for all user-defined inputs.
## Syntax
```sql
AI_SENTIMENT(text, model)
```
## Arguments
* `text`: A prompt.
* `model`: An LLM model.
## Return Type
`string`
## Usage
| Basic usage with default model | `SELECT cluster.AI_SENTIMENT('The migration tool saved us hours, but the error messages were completely cryptic and we had to open three support tickets just to get past the setup.') AS sentiment;` |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic usage with selected model | `SELECT cluster.AI_SENTIMENT('The migration tool saved us hours, but the error messages were completely cryptic and we had to open three support tickets just to get past the setup.', 'anthropic-claude-3-5-haiku') as sentiment;` |
| Input example on database | `SELECT cluster.AI_SENTIMENT(column_1) FROM table;` |
## AI\_TRANSLATE
Provides translation of user-provided documents from source language to target language. Supports multi-language translation.
## Syntax
```sql
AI_TRANSLATE(text, source_languages, target_languages, model)
```
## Arguments
* `text`: A prompt.
* `source_languages`: The language in which the prompt is written.
* `target_languages`: The language to which the prompt gets translated.
* `model`: An LLM model.
## Return Type
`string`
## Usage
| Basic usage with default model | `SELECT cluster.AI_TRANSLATE( '平素より大変お世話になっております。株式会社テクノソリューションズの田中と申します。先日よりご利用いただいておりますデータ移行サービスについて、 重大な問題が発生しておりますため、緊急のご連絡を差し上げております。昨日の午後3時頃より、移行ジョブが途中で停止し、エラーログには「接続タイムアウト」 と記録されております。弊社のシステム管理者が調査いたしましたが、原因の特定には至っておりません。本件は弊社の本番環境に影響を及ぼしており、 業務に支障をきたしております。至急、担当エンジニアよりご連絡いただけますようお願い申し上げます。何卒よろしくお願いいたします。','Japanese','English') AS translated_escalation;` |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic usage with selected model | `SELECT cluster.AI_TRANSLATE('平素より大変お世話になっております。株式会社テクノソリューションズの田中と申します。 先日よりご利用いただいておりますデータ移行サービスについて、重大な問題が発生しておりますため、緊急のご連絡を差し上げております。 昨日の午後3時頃より、移行ジョブが途中で停止し、エラーログには「接続タイムアウト」と記録されております。弊社のシステム管理者が調査いたしましたが、 原因の特定には至っておりません。本件は弊社の本番環境に影響を及ぼしており、業務に支障をきたしております。至急、 担当エンジニアよりご連絡いただけますようお願い申し上げます。何卒よろしくお願いいたします。','Japanese','English', 'anthropic-claude-3-5-haiku') as translation;` |
| Input example on database | `SELECT cluster.AI_TRANSLATE(column_1, "source_language", "target_language") FROM table;` |
## AI\_SUMMARIZE
Provides summary of user-provided documents within the specified length.
## Syntax
```sql
AI_SUMMARIZE(text, model, max_lengths)
```
## Arguments
* `text`: A prompt.
* `model`: An LLM model.
* `max_lengths`: Maximum length of the summary.
## Return Type
`string`
## Usage
| Basic usage with default model and length | `SELECT cluster.AI_SUMMARIZE( 'At 14:32 UTC, our monitoring system detected elevated error rates on the primary ingestion pipeline. The on-call engineer was paged at 14:35. Initial investigation pointed to a misconfigured rate limit introduced during the 14:00 deployment. A rollback was initiated at 14:50 and completed at 15:02. Error rates returned to baseline by 15:05. Total customer-facing impact: approximately 33 minutes of degraded write throughput.') AS incident_one_liner;` |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic usage with selected model | `SELECT cluster.AI_SUMMARIZE( 'At 14:32 UTC, our monitoring system detected elevated error rates on the primary ingestion pipeline. The on-call engineer was paged at 14:35. Initial investigation pointed to a misconfigured rate limit introduced during the 14:00 deployment. A rollback was initiated at 14:50 and completed at 15:02. Error rates returned to baseline by 15:05. Total customer-facing impact: approximately 33 minutes of degraded write throughput.','anthropic-claude-3-5-haiku',15) AS incident_one_liner;` |
| Input example on database | `SELECT cluster.AI_SUMMARIZE(column_1) FROM table;` |
## AI\_CLASSIFY
Provides classification of each input text into one of the given categories or labels.
## Syntax
```sql
AI_CLASSIFY(text, categories, model)
```
## Arguments
* `text`: A prompt.
* `categories`: Categories for classification.
* `model`: An LLM model.
## Return Type
`string`
## Usage
| Basic usage with default model | `SELECT cluster.AI_CLASSIFY( 'Hi, I was charged twice for my subscription this month. I have already checked my payment history and both transactions are showing as completed.', '["billing", "technical_issue", "account_access", "feature_request", "abuse_report"]') AS assigned_queue;` |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic usage with selected model | `SELECT cluster.AI_CLASSIFY( 'Hi, I was charged twice for my subscription this month. I have already checked my payment history and both transactions are showing as completed.', '["billing", "technical_issue", "account_access", "feature_request", "abuse_report"]','anthropic-claude-3-5-haiku') AS assigned_queue;` |
| Input example on database | `SELECT cluster.AI_CLASSIFY(column_1, categories) FROM table;` |
## AI\_EXTRACT
Extracts information from a block or text based on the specified natural language question.
## Syntax
```sql
AI_EXTRACT(text, questions, model)
```
## Arguments
* `text`: A prompt.
* `questions`: Input natural language question on which the LLM model extracts information.
* `model`: An LLM model.
## Return Type
`string`
## Usage
| Basic usage with default model | `SELECT cluster.AI_EXTRACT( 'This Service Agreement is entered into on March 1, 2025 between Acme Corp and DataStream Inc. The total contract value is $240,000 USD, payable in quarterly installments. The agreement expires on February 28, 2027, with a 60-day written notice required for termination.', 'What is the contract expiration date?' ) AS expiration_date, cluster.AI_EXTRACT( 'This Service Agreement is entered into on March 1, 2025 between Acme Corp and DataStream Inc. The total contract value is $240,000 USD, payable in quarterly installments. The agreement expires on February 28, 2027, with a 60-day written notice required for termination.', 'What is the total contract value?' ) AS contract_value, cluster.AI_EXTRACT( 'This Service Agreement is entered into on March 1, 2025 between Acme Corp and DataStream Inc. The total contract value is $240,000 USD, payable in quarterly installments. The agreement expires on February 28, 2027, with a 60-day written notice required for termination.', 'How many days notice is required for termination?' ) AS termination_notice;` |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic usage with selected model | `SELECT cluster.AI_EXTRACT( 'This Service Agreement is entered into on March 1, 2025 between Acme Corp and DataStream Inc. The total contract value is $240,000 USD, payable in quarterly installments. The agreement expires on February 28, 2027, with a 60-day written notice required for termination.', 'What is the contract expiration date?' ) AS expiration_date, cluster.AI_EXTRACT( 'This Service Agreement is entered into on March 1, 2025 between Acme Corp and DataStream Inc. The total contract value is $240,000 USD, payable in quarterly installments. The agreement expires on February 28, 2027, with a 60-day written notice required for termination.', 'What is the total contract value?' ) AS contract_value, cluster.AI_EXTRACT( 'This Service Agreement is entered into on March 1, 2025 between Acme Corp and DataStream Inc. The total contract value is $240,000 USD, payable in quarterly installments. The agreement expires on February 28, 2027, with a 60-day written notice required for termination.', 'How many days notice is required for termination?', 'anthropic-claude-3-5-haiku' ) AS termination_notice;` |
| Input example on database | `SELECT cluster.AI_EXTRACT(column_1, question) FROM table;` |
## Embedding Function
## EMBED\_TEXT
Provides batched embeddings of all input text. Converts text into high-dimensional vector embeddings for semantic search and RAG applications.
## Syntax
```sql
EMBED_TEXT(text, model)
```
## Arguments
* `text`: A prompt.
* `model`: An embedding model.
## Return Type
`bytes`
## Usage
| Basic usage with default model | `SELECT cluster.EMBED_TEXT('Lightweight running shoes with breathable mesh fabric, cushioned soles, and flexible support designed for daily workouts and long-distance comfort.') AS embedding;` |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic usage with selected embedding model | `SELECT cluster.EMBED_TEXT('Lightweight running shoes with breathable mesh fabric, cushioned soles, and flexible support designed for daily workouts and long-distance comfort.', 'shared-qwen3-embed-0-6b') as embedding;` |
| Input example on database | `SELECT cluster.EMBED_TEXT(column_1) FROM table;` |
## Examples
The following examples demonstrate how to use AI functions with the following `customer_reviews` table.
```sql
CREATE DATABASE reviews;
USE reviews;
CREATE TABLE customer_reviews (
review_id INT PRIMARY KEY,
product_id VARCHAR(50),
product_name VARCHAR(255),
customer_name VARCHAR(100),
review_text TEXT,
rating INT,
review_date DATETIME,
language VARCHAR(20) DEFAULT 'English',
response_text TEXT,
review_embedding BLOB
);
-- Insert data
INSERT INTO customer_reviews (
review_id,
product_id,
product_name,
customer_name,
review_text,
rating,
review_date,
language
) VALUES
(1, 'PROD-101', 'Wireless Headphones', 'John Smith',
'These headphones are amazing! The sound quality is crystal clear and the battery lasts for days. Highly recommend for anyone looking for quality audio.',
5, '2026-05-01', 'English'),
(2, 'PROD-101', 'Wireless Headphones', 'Maria Garcia',
'Disappointed with the build quality. They broke after just two weeks of normal use. Customer service was unhelpful.',
1, '2026-05-02', 'English'),
(3, 'PROD-102', 'Smart Watch', 'David Lee',
'Great fitness tracker, but the battery life is shorter than advertised. Overall, good value for the price.',
4, '2026-05-03', 'English'),
(4, 'PROD-101', 'Wireless Headphones', 'Sophie Martin',
'Excellente qualité sonore! Je les utilise tous les jours pour le travail et les loisirs.',
5, '2026-05-04', 'French'),
(5, 'PROD-103', 'Laptop Stand', 'Ahmed Hassan',
'Perfect ergonomic solution for my home office. Sturdy construction and adjustable height. Worth every penny.',
5, '2026-05-05', 'English');
```
## Generate Follow-up Questions for Negative Reviews
The following example uses the `AI_COMPLETE` function to generate follow-up questions for negative reviews:
```sql
SELECT
review_id,
customer_name,
product_name,
review_text,
cluster.AI_COMPLETE(
CONCAT(
'Based on this negative review: "',
review_text,
'", generate three specific follow-up questions to better understand the issue.'
)
) AS follow_up_questions
FROM customer_reviews
WHERE rating <= 2;
```
```output
+-----------+----------------+----------------------+--------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| review_id | customer_name | product_name | review_text | follow_up_questions |
+-----------+----------------+----------------------+--------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 2 | Maria Garcia | Wireless Headphones | Disappointed with the build quality. They broke after just | 1. Can you describe exactly how the product broke and in what specific way? |
| | | | two weeks of normal use. Customer service was unhelpful. | 2. Did you contact customer service through phone, email, or another method, and what precisely did they say that made you feel they were unhelpful? |
| | | | | 3. What type of normal use were you subjecting the product to when it broke? |
+-----------+----------------+----------------------+--------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```
## Compare Customer Ratings with AI Sentiment
The following example uses the `AI_SENTIMENT` function to compare customer ratings with AI-generated sentiment analysis:
```sql
SELECT
review_id,
customer_name,
product_name,
rating AS star_rating,
review_text,
cluster.AI_SENTIMENT(review_text) AS ai_sentiment
FROM customer_reviews
ORDER BY review_date DESC;
```
```output
+-----------+----------------+----------------------+-------------+---------------------------------------------------------------------------------------------------------------------+----------------------------------------------+
| review_id | customer_name | product_name | star_rating | review_text | ai_sentiment |
+-----------+----------------+----------------------+-------------+---------------------------------------------------------------------------------------------------------------------+----------------------------------------------+
| 3 | David Lee | Smart Watch | 4 | Great fitness tracker, but the battery life is shorter than advertised. Overall, good value for the price. | {'sentiment': 'neutral', 'score': '0.5'} |
| 1 | John Smith | Wireless Headphones | 5 | These headphones are amazing! The sound quality is crystal clear and the battery lasts for days. | {'sentiment': 'positive', 'score': '0.9'} |
| 5 | Ahmed Hassan | Laptop Stand | 5 | Perfect ergonomic solution for my home office. Sturdy construction and adjustable height. Worth every penny. | {'sentiment': 'positive', 'score': '0.95'} |
| 4 | Sophie Martin | Wireless Headphones | 5 | Excellente qualité sonore! Je les utilise tous les jours pour le travail et les loisirs. | {'sentiment': 'positive', 'score': '0.90'} |
| 2 | Maria Garcia | Wireless Headphones | 1 | Disappointed with the build quality. They broke after just two weeks of normal use. Customer service was unhelpful. | {'sentiment': 'negative', 'score': '0.85'} |
+-----------+----------------+----------------------+-------------+---------------------------------------------------------------------------------------------------------------------+----------------------------------------------+
```
## Standardize Reviews in English
The following example uses the `AI_TRANSLATE` function to standardize the reviews in English language:
```sql
SELECT
review_id,
customer_name,
product_name,
language AS original_language,
review_text AS original_review,
CASE
WHEN language = 'English' THEN review_text
ELSE cluster.AI_TRANSLATE(
review_text,
language,
'English'
)
END AS standardized_review_english
FROM customer_reviews
ORDER BY review_date DESC;
```
```output
+-----------+----------------+----------------------+-------------------+---------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------+
| review_id | customer_name | product_name | original_language | original_review | standardized_review_english |
+-----------+----------------+----------------------+-------------------+---------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------+
| 3 | David Lee | Smart Watch | English | Great fitness tracker, but the battery life is shorter than advertised. Overall, good value for the price. | Great fitness tracker, but the battery life is shorter than advertised. Overall, good value for the price. |
| 1 | John Smith | Wireless Headphones | English | These headphones are amazing! The sound quality is crystal clear and the battery lasts for days. | These headphones are amazing! The sound quality is crystal clear and the battery lasts for days. |
| 5 | Ahmed Hassan | Laptop Stand | English | Perfect ergonomic solution for my home office. Sturdy construction and adjustable height. Worth every penny. | Perfect ergonomic solution for my home office. Sturdy construction and adjustable height. Worth every penny. |
| 4 | Sophie Martin | Wireless Headphones | French | Excellente qualité sonore! Je les utilise tous les jours pour le travail et les loisirs. | Excellent sound quality! I use them every day for work and leisure. |
| 2 | Maria Garcia | Wireless Headphones | English | Disappointed with the build quality. They broke after just two weeks of normal use. Customer service was unhelpful. | Disappointed with the build quality. They broke after just two weeks of normal use. Customer service was unhelpful. |
+-----------+----------------+----------------------+-------------------+---------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------+
```
## Generate Product-Level Summaries
The following example uses the `AI_SUMMARIZE` function to generate product-level summaries from customer reviews:
```sql
SELECT
product_id,
product_name,
COUNT(*) AS review_count,
AVG(rating) AS avg_rating,
cluster.AI_SUMMARIZE(
GROUP_CONCAT(review_text SEPARATOR '. ')
) AS product_summary
FROM customer_reviews
GROUP BY product_id, product_name;
```
```output
+------------+----------------------+--------------+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| product_id | product_name | review_count | avg_rating | product_summary |
+------------+----------------------+--------------+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PROD-103 | Laptop Stand | 1 | 5.0000 | Excellent ergonomic home office solution with sturdy construction and adjustable height, providing good value. |
| PROD-101 | Wireless Headphones | 3 | 3.6667 | Mixed reviews for headphones: praised for excellent sound quality and long battery life, but criticized for poor durability and potential customer service issues.|
| PROD-102 | Smart Watch | 1 | 4.0000 | Fitness tracker offers good value, though battery life is shorter than expected. |
+------------+----------------------+--------------+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```
## Classify Review Intent
The following example uses the `AI_CLASSIFY` function to classify the review intent:
```sql
SELECT
review_id,
customer_name,
product_name,
rating,
review_text,
cluster.AI_CLASSIFY(
review_text,
'[praise, complaint, suggestion, question, comparison]'
) AS review_intent
FROM customer_reviews
ORDER BY review_date DESC;
```
```output
+-----------+----------------+----------------------+--------+---------------------------------------------------------------------------------------------------------------------+---------------+
| review_id | customer_name | product_name | rating | review_text | review_intent |
+-----------+----------------+----------------------+--------+---------------------------------------------------------------------------------------------------------------------+---------------+
| 3 | David Lee | Smart Watch | 4 | Great fitness tracker, but the battery life is shorter than advertised. Overall, good value for the price. | complaint |
| 1 | John Smith | Wireless Headphones | 5 | These headphones are amazing! The sound quality is crystal clear and the battery lasts for days. | praise |
| 5 | Ahmed Hassan | Laptop Stand | 5 | Perfect ergonomic solution for my home office. Sturdy construction and adjustable height. Worth every penny. | praise |
| 4 | Sophie Martin | Wireless Headphones | 5 | Excellente qualité sonore! Je les utilise tous les jours pour le travail et les loisirs. | praise |
| 2 | Maria Garcia | Wireless Headphones | 1 | Disappointed with the build quality. They broke after just two weeks of normal use. Customer service was unhelpful. | complaint |
+-----------+----------------+----------------------+--------+---------------------------------------------------------------------------------------------------------------------+---------------+
```
## Extract Multiple Insights
The following example uses the `AI_EXTRACT` function to extract multiple insights from customer reviews:
```sql
SELECT
review_id,
product_name,
review_text,
cluster.AI_EXTRACT(
review_text,
'What product features are mentioned?'
) AS features_mentioned,
cluster.AI_EXTRACT(
review_text,
'How long has the customer used this product?'
) AS usage_duration
FROM customer_reviews;
```
```output
+-----------+----------------------+--------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------+-----------------------------+
| review_id | product_name | review_text | features_mentioned | usage_duration |
+-----------+----------------------+--------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------+-----------------------------+
| 5 | Laptop Stand | Perfect ergonomic solution for my home office. Sturdy construction and adjustable height. Worth every penny. | Sturdy construction, adjustable height | Not specified in the review |
| 2 | Wireless Headphones | Disappointed with the build quality. They broke after just two weeks of normal use. Customer service | Build quality issues, broke after two weeks was unhelpful. | Two weeks |
| 4 | Wireless Headphones | Excellente qualité sonore! Je les utilise tous les jours pour le travail et les loisirs. | Sound quality | Daily (ongoing) |
| 3 | Smart Watch | Great fitness tracker, but the battery life is shorter than advertised. Overall, good value for the price. | Battery life (shorter than advertised), good value for price. | Not specified in the review |
| 1 | Wireless Headphones | These headphones are amazing! The sound quality is crystal clear and the battery lasts for days. | Sound quality (crystal clear), long battery life | Not specified in the review |
+-----------+----------------------+--------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------+-----------------------------+
```
## Perform Semantic Search
The following example uses the `EMBED_TEXT` function to perform semantic search on customer reviews.
```sql
SET batch_external_functions = AUTO;
SELECT
review_id,
product_name,
review_text,
cluster.EMBED_TEXT(review_text) AS review_embedding
FROM customer_reviews;
UPDATE customer_reviews
SET review_embedding = cluster.EMBED_TEXT(review_text)
WHERE review_embedding IS NULL;
WITH search_query AS (
SELECT cluster.EMBED_TEXT(
'battery problems and short lifespan'
) AS query_embedding
)
SELECT
cr.review_id,
cr.product_name,
cr.review_text,
cr.rating,
DOT_PRODUCT(
cr.review_embedding,
sq.query_embedding
) AS relevance_score
FROM customer_reviews cr,
search_query sq
WHERE cr.review_embedding IS NOT NULL
ORDER BY relevance_score DESC;
```
```output
+-----------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+--------+-----------------+
| review_id | product_name | review_text | rating | relevance_score |
+-----------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+--------+-----------------+
| 3 | Smart Watch | Great fitness tracker, but the battery life is shorter than advertised. Overall, good value for the price. | 4 | NULL |
| 1 | Wireless Headphones | These headphones are amazing! The sound quality is crystal clear and the battery lasts for days. Highly recommend for anyone looking for quality audio.| 5 | NULL |
| 2 | Wireless Headphones | Disappointed with the build quality. They broke after just two weeks of normal use. Customer service was unhelpful. | 1 | NULL |
| 4 | Wireless Headphones | Excellente qualité sonore! Je les utilise tous les jours pour le travail et les loisirs. | 5 | NULL |
| 5 | Laptop Stand | Perfect ergonomic solution for my home office. Sturdy construction and adjustable height. Worth every penny. | 5 | NULL |
+-----------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+--------+-----------------+
```
## Generate Embeddings at Load Time Using a Pipeline
The following example uses a pipeline and the `EMBED_TEXT` AI function to generate embeddings for new customer reviews loaded from the AWS S3 bucket. The pipeline loads rows into a staging table and an `UPDATE … JOIN` statement then populates `review_embedding` in batches instead of one row at a time.
Create a staging table that mirrors `customer_reviews` without the embedding column:
```sql
DROP TABLE IF EXISTS customer_reviews_staging;
CREATE TABLE customer_reviews_staging (
review_id INT PRIMARY KEY,
product_id VARCHAR(50),
product_name VARCHAR(255),
customer_name VARCHAR(100),
review_text TEXT,
rating INT,
review_date DATETIME,
language VARCHAR(20) DEFAULT 'English'
);
```
Create a pipeline named `customer_reviews_pipeline` and start the pipeline:
```sql
CREATE PIPELINE customer_reviews_pipeline
AS LOAD DATA S3 's3://singlestore-docs-example-datasets/reviews/customer_reviews.csv'
SKIP DUPLICATE KEY ERRORS INTO TABLE customer_reviews_staging
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES;
START PIPELINE customer_reviews_pipeline;
```
Insert the new rows into `customer_reviews`, then generate embeddings in a single batched operation:
```sql
INSERT INTO customer_reviews
(review_id, product_id, product_name, customer_name, review_text,
rating, review_date, language)
SELECT s.review_id,
s.product_id,
s.product_name,
s.customer_name,
s.review_text,
s.rating,
s.review_date,
s.language
FROM customer_reviews_staging s
LEFT JOIN customer_reviews r ON r.review_id = s.review_id
WHERE r.review_id IS NULL;
CREATE TEMPORARY TABLE review_embeddings_scratch AS
SELECT review_id,
cluster.EMBED_TEXT(review_text) AS review_embedding
FROM customer_reviews
WHERE review_embedding IS NULL;
UPDATE customer_reviews r
JOIN review_embeddings_scratch s ON r.review_id = s.review_id
SET r.review_embedding = s.review_embedding;
DROP TABLE review_embeddings_scratch;
```
Calling `EMBED_TEXT` inside a `SELECT` allows the engine to send rows to the embedding model in batches (default `512` rows per request). The `UPDATE … JOIN` statement then writes the embeddings back to `customer_reviews` in a single set-oriented statement.
Verify the results:
```sql
SELECT review_id,
product_name,
LEFT(review_text, 40) AS review_preview,
LENGTH(review_embedding) AS embedding_bytes
FROM customer_reviews
WHERE review_id BETWEEN 6 AND 10
ORDER BY review_id;
```
```output
+-----------+----------------------+--------------------------------------------------------------------+-----------------+
| review_id | product_name | review_preview | embedding_bytes |
+-----------+----------------------+--------------------------------------------------------------------+-----------------+
| 6 | Smart Watch | Love the sleep tracking and heart rate a | 8192 |
| 7 | Laptop Stand | Decent stand but the height adjustment i | 8192 |
| 8 | Wireless Headphones | ノイズキャンセリングがとても効果的で、通勤中の電車でも音楽がクリアに聞こえます。 | 8192 |
| 9 | Mechanical Keyboard | Die Tastatur fühlt sich hochwertig an, a | 8192 |
| 10 | Smart Watch | Battery dies in under a day with GPS on. | 8192 |
+-----------+----------------------+--------------------------------------------------------------------+-----------------+
```
## Generate Embeddings at Load Time Using a Pipeline and Stored Procedure
The following example uses a pipeline that calls a stored procedure to generate embeddings on each batch as it arrives. The stored procedure inserts the batch into `customer_reviews` with embeddings generated inline using `EMBED_TEXT` in a singles-set oriented operation.
Create the stored procedure named `load_customer_reviews_with_embeddings`:
```sql
DELIMITER //
CREATE OR REPLACE PROCEDURE load_customer_reviews_with_embeddings(
batch QUERY(
review_id INT,
product_id VARCHAR(50),
product_name VARCHAR(255),
customer_name VARCHAR(100),
review_text TEXT,
rating INT,
review_date DATETIME,
language VARCHAR(20)
)
)
AS BEGIN
INSERT INTO customer_reviews
(review_id, product_id, product_name, customer_name, review_text,
rating, review_date, language, review_embedding)
SELECT review_id,
product_id,
product_name,
customer_name,
review_text,
rating,
review_date,
language,
cluster.EMBED_TEST(review_text)
FROM batch;
END //
DELIMITER ;
```
Create a pipeline named `customer_reviews_sp_pipeline` and start the pipeline:
```sql
CREATE OR REPLACE PIPELINE customer_reviews_sp_pipeline
AS LOAD DATA S3 's3://singlestore-docs-example-datasets/reviews/customer_reviews.csv'
BATCH_INTERVAL 2500
INTO PROCEDURE load_customer_reviews_with_embeddings
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
START PIPELINE customer_reviews_sp_pipeline;
```
Verify that the pipeline loaded the rows and populated the embeddings:
```sql
SELECT review_id,
product_name,
LEFT(review_text, 40) AS review_preview,
LENGTH(review_embedding) AS embedding_bytes
FROM customer_reviews
WHERE review_id BETWEEN 6 AND 10
ORDER BY review_id;
```
```output
+-----------+----------------------+--------------------------------------------------------------------------------------------------------------------------+-----------------+
| review_id | product_name | review_text | embedding_bytes |
+-----------+----------------------+--------------------------------------------------------------------------------------------------------------------------+-----------------+
| 6 | Smart Watch | Love the sleep tracking and heart rate accuracy. The strap is comfortable enough to wear overnight without irritation. | 8192 |
| 7 | Laptop Stand | Decent stand but the height adjustment is wobbly under heavier laptops. Works fine for an ultrabook. | 8192 |
| 8 | Wireless Headphones | ノイズキャンセリングがとても効果的で、通勤中の電車でも音楽がクリアに聞こえます。 | 8192 |
| 9 | Mechanical Keyboard | Die Tastatur fühlt sich hochwertig an, aber die Beleuchtung ist zu hell und lässt sich nicht ausschalten. | 8192 |
| 10 | Smart Watch | Battery dies in under a day with GPS on. Returning it. The app is also buggy on Android. | 8192 |
+-----------+----------------------+--------------------------------------------------------------------------------------------------------------------------+-----------------+
```
Each pipeline batch invokes the stored procedure with up to `512` rows. `EMBED_TEXT` is called inside a `SELECT` so the rows are sent to the embedding model as a single batched request, and the `UPDATE … JOIN` statement writes the results back in one set-oriented statement.
## Complete Customer Insights
The following example uses the `AI_SUMMARIZE` and `AI_EXTRACT` functions to generate complete customer insights for each product:
```sql
SELECT
product_id,
product_name,
COUNT(*) AS total_reviews,
AVG(rating) AS avg_rating,
cluster.AI_SUMMARIZE(
GROUP_CONCAT(review_text SEPARATOR '. ')
) AS overview,
cluster.AI_EXTRACT(
GROUP_CONCAT(review_text SEPARATOR '. '),
'What are the top three issues customers mention?'
) AS top_issues,
cluster.AI_EXTRACT(
GROUP_CONCAT(review_text SEPARATOR '. '),
'What do customers love most about this product?'
) AS top_strengths
FROM customer_reviews
GROUP BY product_id, product_name;
```
```output
+------------+----------------------+---------------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------+---------------------------------------------+
| product_id | product_name | total_reviews | avg_rating | overview | top_issues | top_strengths |
+------------+----------------------+---------------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------+---------------------------------------------+
| PROD-103 | Laptop Stand | 1 | 5.0000 | Excellent ergonomic home office solution with sturdy construction and adjustable height, providing good value. | 1. Sturdy construction 2. Adjustable height 3. Good value for money | Sturdy construction and adjustable height |
| PROD-101 | Wireless Headphones | 3 | 3.6667 | Mixed reviews for headphones: praised for excellent sound quality and long battery life, but criticized for poor durability and potential customer service issues. | 1. Sound quality 2. Battery life 3. Build quality (durability) | Sound quality and battery life | | |
| PROD-102 | Smart Watch | 1 | 4.0000 | Fitness tracker offers good value, though battery life is shorter than expected. | 1. Battery life 2. Price 3. Functionality | Good value for the price |
+------------+----------------------+---------------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------+---------------------------------------------+
```
## Example Notebook
The following notebook demonstrates AI Functions:
## Usage Recommendations for AI Functions
To optimize performance and control costs when using AI Functions, SingleStore recommends the following:
* Use Common Table Expressions (CTEs) to filter rows before making calls to large language models (LLMs). The query engine currently sends data to the LLM before applying LLM or `WHERE` filters.
* LLM calls are expensive. Begin with a small dataset to evaluate response quality and verify the results meet the requirements before scaling up.
* Enterprise plans support three model providers; Aura, Amazon Bedrock, and Azure AI Services. Data is processed according to each provider’s policies. If a row violates provider rules, the system fails the batch that includes the row and returns errors for these rows.
* Strict usage quotas apply per model and per organization. These quotas are not configurable by end users. For higher usage limits, contact [SingleStore Support](https://support.singlestore.com/). Self-service quota configuration will be available in the future.
***
Modified at: July 9, 2026
Source: [/cloud/ai/ai-ml-functions/ai-functions/](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ai-functions/)
(An index of the documentation is available at /llms.txt)
---
# ML Functions
## Overview
Machine learning (ML) functions enable trained models to be run directly within SQL queries. They support real-time classification of new data and detection of anomalies without requiring custom code. These functions allow predictions to be embedded directly into workflows that operationalize insights at the data layer.
## Introduction to Machine Learning
Machine learning is a field of study in artificial intelligence that develops and applies methods for learning patterns from historical data and using those patterns to make predictions or decisions on new data. Unlike rule-based systems, ML models adapt automatically based on the data. Common use cases include fraud detection, predictive maintenance, and customer behavior analysis. Once trained, models can be deployed and invoked using ML functions to generate predictions at scale.
## Classification
Classification is a supervised learning technique that assigns each input to one of a predefined set of classes or labels. Models are trained on labeled datasets, where each input is paired with its correct output, and then used to classify new data. For example, a model may predict whether an incoming email is "spam" or "not spam" based on its content and metadata.
Following are the types of classification:
* **Binary Classification**: Predicts one of two possible outcomes (for example, fraud vs. non-fraud).
* **Multiclass Classification**: Predicts one label from multiple possible categories (for example, product type A, B, or C).
* **Multilabel Classification**: Assigns multiple labels to a single data point (for example, tagging an image with "beach" and "sunset").
Examples:
* A credit-card transaction classified as “fraudulent” or “legitimate.”
* Customer support tickets categorized as “billing,” “technical issue,” or “account upgrade.”
The `ML_CLASSIFY` is a supervised machine learning function for classification tasks. It supports both binary (two classes) and multi-class (more than two classes) classification. It leverages algorithms such as logistic regression, random forest, and gradient boosting. Use SQL queries to call `ML_CLASSIFY` function and return predicted class labels.
## Anomaly Detection
Anomaly detection identifies data points that deviate significantly from expected patterns. Anomalies signal critical issues such as fraud, equipment failure, or network intrusions. An anomaly is any value or pattern that does not match normal behavior. Anomalies indicate the following:
* Performance issues (for example, server overload)
* System faults (for example, failed jobs or memory leaks)
* Opportunities (for example, traffic spikes caused by a marketing campaign)
For example, if a cluster's CPU usage normally stays between 20–60% and suddenly rises to 95%, the spike is an anomaly.
## Time-Series Anomaly Detection
Time-series anomaly detection analyzes data collected over time. For example, CPU or memory utilization per minute or hour. It considers not only individual values, but also the sequence and patterns in the data. It learns seasonal patterns (daily or weekly), long‑term trends, and normal variability ranges. The system flags values that deviate from these learned patterns.
Following are the types of time-series anomaly detection:
* **Supervised**: Supervised models use labeled anomalies to learn failure patterns.
* **Unsupervised**: Unsupervised models learn normal behavior from historical data and flag deviations without labels.
The `ML_ANOMALY_DETECT` function is an unsupervised time-series anomaly detection function currently. It supports statistical methods (e.g., z-score, interquartile range) and machine learning methods (e.g., Isolation Forest, One-Class SVM). This function returns a prediction for each row, identifying it as normal or anomalous, which can trigger alerts or be recorded for further analysis.
## Install ML Functions
To install ML Functions, navigate to **AI > AI & ML Functions**, select the deployment on which to install ML Functions. In the **ML Functions** tab, select **Install**, review the **ML Functions Summary** and then select **Deploy**.
Once the ML Functions are installed, query them in the SQL Editor or SingleStore Notebooks. SingleStore provides the following ML Functions:
| **Category** | **Function** |
| --------------------------------------------------------- | --------------------------------------------------- |
| Statistical and Predictive Functions | `ML_CLASSIFY(model_name, TO_JSON(selected_data.*))` |
| `ML_ANOMALY_DETECT(model_name, TO_JSON(selected_data.*))` | |
## Statistical and Predictive Functions
## ML\_CLASSIFY
Performs binary and multi-class classification on a dataset using standard machine learning algorithms. Supports common algorithms including:
* Logistic Regression
* Random Forest
* Gradient Boosting
## Syntax
```sql
ML_CLASSIFY(model_name, TO_JSON(selected_data.*))
```
## Arguments
* `model_name`: Name of the trained ML model to use.
* `selected_data`: A row or set of rows selected for prediction.
## Return Type
`string`
## Usage
| Basic usage | `SELECT cluster.ML_CLASSIFY(model_name, TO_JSON(selected_data.*)) AS predictions FROM (SELECT * FROM table) AS selected_data;` |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic usage with`LIMIT` | `SELECT cluster.ML_CLASSIFY(model_name, TO_JSON(selected_data.*)) AS predictions FROM (SELECT * FROM table WHERE column1 > 100000LIMIT 100) AS selected_data;` |
| Insert predictions into a table | `INSERT INTO predictions_table (id, prediction); SELECT selected_data.id, cluster.ML_CLASSIFY(model_name, TO_JSON(selected_data.*)) AS prediction FROM (SELECT * FROM table LIMIT 100) AS selected_data;` |
## ML\_ANOMALY\_DETECT
Detects outliers and anomalies in datasets using statistical or machine learning-based methods. Suitable for security, monitoring, and anomaly detection applications. Supports the following methods:
* **Statistical**: z-score, interquartile range (IQR)
* **ML-based**: Isolation Forest, One-Class SVM
## Syntax
```sql
ML_ANOMALY_DETECT(model_name, TO_JSON(selected_data.*))
```
## Arguments
* `model_name`: Name of the trained ML model to use.
* `selected_data`: A row or set of rows selected for prediction.
## Return Type
`string`
## Usage
| Basic usage | `SELECT cluster.ML_ANOMALY_DETECT(model_name, TO_JSON(selected_data.*)) AS predictions FROM (SELECT * FROM table) AS selected_data;` |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic usage with`LIMIT` | `SELECT cluster.ML_ANOMALY_DETECT(model_name, TO_JSON(selected_data.*)) AS predictions FROM (SELECT * FROM tableWHERE column1 > 100000LIMIT 100) AS selected_data;` |
| Insert predictions into a table | `INSERT INTO predictions_table (id, prediction); SELECT selected_data.id, cluster.ML_ANOMALY_DETECT(model_name, TO_JSON(selected_data.*)) AS prediction FROM (SELECT * FROM table LIMIT 100) AS selected_data;` |
## Train a New ML Model
To train a new ML model, follow these steps:
1. Navigate to **AI > Models**.
2. Select **ML Models** tab and then select **Train New ML Model**.
3. In the **Select Function** dialog, select one of the following ML functions:
* `ML_CLASSIFY`
* `ML_ANOMALY_DETECT`
Select **Next** to configure the model.
**Configure Model**
| **Model Name** | Enter the name of the ML model. |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Training Description** | Enter the training description. |
| **Cluster** | Select theSingleStoredeployment (cluster) the notebook connects to.Specifying aclusterallows natively connecting theSingleStoredatabases referenced in the notebook. |
| **Compute Size** | Select one of the following compute sizes: |
| **Run as** | Run the notebook for training a model with or without personal credentials. Select one of the following: - Run as <username>: Runs the notebook using the permissions and access of the current user account.
- Run as a Service Account: Runs the notebook independently of personal credentials, using a service account.
📝 Note:
Service accounts can only be created by Admin.
|
Select **Next**.
**Select Training Data**
| **Database** | Select the database that contains the training data. |
| -------------------------- | -------------------------------------------------------------------------------- |
| **Table** | Select the table from the selected database to train the machine learning model. |
| **Target Column** | Select the column that represents the prediction target for the model. |
| **Feature Selection Mode** | Specify how feature columns are selected. |
| **Feature Column** | Select one or more columns to be used as input features for training the model. |
Preview the data and select **Next**.
Review the **Summary** and generated Fusion SQL syntax in the **Generated SQL Script**. The generated script performs the following:
* Creates and trains a ML model
* Uses data from the selected table in the selected database
* Predicts values of target column status
* Runs on the selected compute instance
* Uses all available features by default
Following is the syntax of Fusion SQL script:
```sql
%s2ml train
--model
--db
--input_table
--target_column
--description
--runtime
--selected_features { \"mode\": , \"features\": }
```
Select **Start Training** to train the ML model.
## Example Notebooks
The following notebooks demonstrates how to use ML Functions:
## ML Functions: Classification
## ML Functions: Anomaly Detection
## Manage an Existing ML Model
Existing ML models can be managed by performing the following actions:
* View details
* Run prediction
* Share
* Delete
## View Details of an Existing ML Model
To view details of an existing ML model, select the ellipsis under **Actions** column of the trained ML model, and select **View Details**. Alternatively, select the ML model in the **Name** column. Select the **Details** tab to view training status, training configuration, training logs, and details about how to use the ML model.
## Run Prediction on an Existing ML Model
Run batch prediction on the existing ML model.
## Run a Batch Prediction
To run a batch prediction on the existing ML model, select the ellipsis under **Actions** column of the trained ML model, and select **Run Prediction**.
**Select Prediction Data**
| **Database** | Select the database. |
| -------------------- | ------------------------------------------------------------------------------ |
| **Target Table** | Select the target table on which the prediction will be run. |
| **Target Column** | Select the target column on which the prediction will focus on. |
| **Timestamp Column** | Select the column having timestamp data. Available for`ML_ANOMALY_DETECT`only. |
Preview the data and select **Next**.
**Configure Destination**
| **Prediction Interval Width** | Select the interval width of prediction. Available for`ML_ANOMALY_DETECT`only. |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Destination Table Name** | Select the destination table in which the prediction results will be stored. |
| **Destination Column** | Select the destination column in which the prediction data will be saved. |
| **Run as** | Run the notebook for training a model with or without personal credentials. Select one of the following: - Run as <username>: Runs the notebook using the permissions and access of the current user account.
- Run as a Service Account: Runs the notebook independently of personal credentials, using a service account.
📝 Note:
Service accounts are only created by Admin.
|
Review the **Summary** and generated Fusion SQL syntax in the **Generated SQL Script**. Select **Start Prediction** to run batch prediction on the trained ML model.
## View Predictions of an Existing ML Model
To view the predictions of the trained ML model, select the ML model in the **Name** column. Select the **Predictions** tab to view prediction metadata and status.
## Share an Existing ML Model
To share an existing ML model, select the ellipsis under the **Actions** column of the trained ML model, and select **Share**.
## Delete an Existing ML Model
To delete an existing ML model, select the ellipsis under **Actions** column of the trained ML model, and select **Delete**.
## Status of ML Models
| **Status** | **Description** |
| -------------- | --------------------------------------------------------------------------------------------- |
| Pre-processing | The system is preparing data for ML model training (e.g., data cleaning, feature extraction). |
| Training | The ML model is currently being trained but results are not yet available. |
| Done | The ML model has been successfully trained and is ready for use. |
| Error | The ML model training or processing failed due to an error. |
## In this section
* [ML Functions Release Notes](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ml-functions/ml-functions-release-notes.md)
***
Modified at: July 9, 2026
Source: [/cloud/ai/ai-ml-functions/ml-functions/](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ml-functions/)
(An index of the documentation is available at /llms.txt)
---
# Shared Embedding Model Service
The Shared Embedding Model Service is a multi-tenant embedding service that provides a shared embedding model for AI Functions. Unlike the dedicated embedding service provisioned per user, this shared service allows multiple users and organizations to use the same embedding infrastructure without provisioning individual resources.
## Overview
When AI Functions are installed, a shared embedding model is automatically provisioned. This model runs on SingleStore Aura container service and is available to all organizations with AI Functions enabled.
The shared embedding model is powered by Qwen3-Embedding-0.6B, a lightweight yet high-quality embedding model optimized for text vectorization, semantic search, and RAG applications. The shared service is currently available in US East (N. Virginia).
| Property | Value |
| ------------ | -------------------------- |
| Model name | `shared-qwen3-embed-0-6b` |
| Model family | Qwen3 Embedding |
| Dimensions | 1024 |
| Region | US East (N. Virginia) |
| Hosting | Aura-hosted (multi-tenant) |
## How It Works
The shared embedding model service differs from dedicated embedding models in the following ways:
| | Shared Embedding Model | Dedicated Embedding Model |
| -------------- | ----------------------------------------- | ----------------------------------- |
| Infrastructure | Multi-tenant, shared across organizations | Single-tenant, provisioned per user |
| Provisioning | Automatic during AI Functions install | Manual setup required |
| Scaling | SingleStore-managed | User-configurable |
| Model | Qwen3-Embedding-0.6B | User's choice |
The shared embedding service runs on GPU-accelerated infrastructure and automatically scales based on demand. SingleStore manages the lifecycle, scaling, and availability of the service.
## Prerequisites
* A SingleStore Helios cluster group with AI Functions installed.
* The Shared Embedding Service feature must be enabled for your organization.
## Select the Embedding Model
You can view and change your default embedding model in the Cloud Portal:
1. Navigate to **AI > AI & ML Functions**.
2. Select your cluster group.
3. On the **AI Functions** tab, in **Settings**, select **Edit**.
4. On the **Edit AI Functions** page, in **Models**, select the **Embedding Model** section.
5. The available embedding models include both the shared model (`shared-qwen3-embed-0-6b`) and the dedicated models provisioned for your organization.
To update the default embedding model used by `EMBED_TEXT`, select the desired model and save the change.
## Usage
Use the shared embedding model with the `EMBED_TEXT` function by specifying the model name `shared-qwen3-embed-0-6b`. The following examples use the `customer_reviews` table.
## Basic Usage
```
SELECT cluster.EMBED_TEXT(
'The headphones have poor sound quality, disconnect frequently, and the battery lasts only a few hours. I would not recommend this product.',
'shared-qwen3-embed-0-6b'
) AS embedding;
```
## Using the Default Model
If the shared embedding model is set as your default embedding model, you can remove the model parameter:
```
SELECT cluster.EMBED_TEXT(
'The headphones have poor sound quality, disconnect frequently, and the battery lasts only a few hours. I would not recommend this product.'
) AS embedding;
```
## Generating Embeddings for a Table Column
```
SET batch_external_functions = AUTO;
UPDATE customer_reviews
SET review_embedding = cluster.EMBED_TEXT(review_text, 'shared-qwen3-embed-0-6b')
WHERE review_embedding IS NULL;
```
## Performance Considerations
* **Batching**: Use `SET batch_external_functions = AUTO`, before bulk embedding operations to enable automatic batching, which significantly improves throughput.
* **Token limits**: The Qwen3-Embedding-0.6B model processes text in token chunks. For large text inputs, the service automatically handles tokenization and batching.
* **Region**: For lowest latency, use cluster groups in the same region.
> **📝 Note**: The shared embedding model is available only in the US East (N. Virginia) region. As a shared multi-tenant service, throughput may vary based on overall system demand. The model selection is fixed to Qwen3-Embedding-0.6B; for custom model requirements, use a dedicated embedding model.
## Related Topics
* [AI Functions](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ai-functions.md)
* [EMBED\_TEXT](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ai-functions/#section-id235175351219875.md)
* [Working with Vector Data](https://docs.singlestore.com/cloud/developer-resources/functional-extensions/working-with-vector-data.md)
***
Modified at: August 4, 2026
Source: [/cloud/ai/ai-ml-functions/shared-embedding-model-service/](https://docs.singlestore.com/cloud/ai/ai-ml-functions/shared-embedding-model-service/)
(An index of the documentation is available at /llms.txt)
---
# Aura Analyst
> **📝 Note**: This is a Preview feature.
## Overview
Aura Analyst is an AI-powered data analyst that makes it easy to converse with the data in plain English. It is a fully managed agentic AI service built natively for SingleStore that translates natural language questions into precise SQL queries and instantly delivers insights from the databases. By removing the requirement of manually writing SQL or building complex dashboards, Aura Analyst accelerates analytics and empowers users to uncover insights faster. Leveraging SingleStore’s Agentic AI platform, it ensures that queries are accurate, context-aware, and governed, helping teams make smarter, data-driven decisions with ease.
## How Aura Analyst Works
Aura Analyst is a fully managed agentic, multi-component AI system designed to transform natural language into reliable, actionable insights. Instead of relying on a single, monolithic model, it orchestrates a series of specialized stages, including intent interpretation, query planning, SQL generation, validation, execution, and result summarization. This modular architecture enhances accuracy, ensures control, and adapts flexibly across diverse datasets and query types.
By clarifying ambiguous inputs, exposing query plans, and automatically retrying on failures, Aura Analyst provides a more dependable experience while building user trust. Beyond running SQL, the system makes results easy to interpret through natural-language summaries and visualizations, enabling business and technical users alike to act on data with confidence.
## What is a Domain
A **Domain** is the context service for Aura Analyst. It acts as a knowledge base, supplying the semantic and structural framework required to interpret questions accurately, generate the right SQL, and deliver governed insights.
Users with the “Agent Domain Owner” permission can configure Domains by selecting relevant clusters, databases, and tables. They can enhance Domains with custom instructions, business-specific formulas, or logic that Aura Analyst applies when answering questions.Once configured, a Domain abstracts the complexity of raw schemas. Users interact with a curated, context-rich view of the data, making analytics more accurate, consistent, and accessible.
Domains are dynamic. As data changes and new business requirement emerges, users can continuously refine them. Each update enhances the context service, ensuring that insights remain reliable, governed, and immediately actionable.
## Create a Domain
Once the Aura Analyst is enabled, select **Create domain**. In the **Create Domain** dialog:
| **Domain Details** | |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | Enter the name of the domain. |
| **Description** | Enter the domain description. |
| **Connect Data** | |
| **Connection** | Select theSingleStoredeployment (cluster) the domain connects to.Specifying aclusterallows connecting theSingleStoredatabases referenced in the domain.SingleStorerecommends creating a newclusterwith a read-only database attachment for Aura Analyst to maintain clarity and separation of workloads. |
| **Select tables** | Select the tables from theSingleStoredatabases. |
Select **Create** to create the domain for Aura Analyst.
> **📝 Note**: Aura Analyst keeps the cluster active as hourly metadata collection prevents the cluster from remaining idle for more than one hour.
## Configure an Existing Domain
To configure an existing domain, enable **Creator Mode**, and enter or select the following:
| **Build** | |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Context** | Contexts are reference materials that the Analyst can draw on to answer questions more accurately. Use them to provide custom instructions, background knowledge, assumptions, or business logic that may not be immediately obvious from the raw data. - Instructions: Add general instructions to set response style, constraints, and domain-specific guidance. To add an instruction, enter your context in Instructions, and then select Save. The following are the context states for the instructions:
- Draft: A working copy of domain instructions that can be edited and tested without affecting the live published version. It is created when a domain owner begins editing instructions in Creator Mode and changes remain isolated until explicitly published. This allows domain owners to test and refine instructions, make multiple edits without disrupting active users, and discard changes if needed.
- Published: The current live version of domain instructions that the Analyst actively uses to answer questions. All users querying the domain see and use the published version, and the Analyst applies these instructions when generating SQL and interpreting questions. This is the production state visible to all domain users.
- Learned Context: The system automatically learns contexts from user questions and interactions. The following are the context states for the learned contexts:
- Pending: Learned contexts that have been automatically generated by the system but have not yet been reviewed by a domain owner. These insights are awaiting approval or rejection.
- Approved: Learned contexts that have been reviewed and approved by a domain owner. Only approved contexts are actively used by the Analyst to answer questions and generate SQL queries.
- Rejected: Learned contexts that have been reviewed and rejected by a domain owner.
You can update and delete existing learned contexts.
|
| **Data** | The Data section allows you to review and enhance schema metadata and includes relationship management capabilities. - Database: Navigate to the Database tab. Auto-generated descriptions for tables and columns help the Analyst understand the data model. Domain owners can edit and refine these descriptions to improve accuracy. Add more tables to the domain by selecting Add. Tables can be added from the deployment connected to the domain. To edit the table description, select the ellipsis (three dots), and then select Edit. To delete the table, select the ellipsis (three dots), and then select Delete. In the Table column, select the table and you can view and edit the description of each column of the table.
- Entity-Relationship: Navigate to the Relationship tab. A relationship crawler automatically discovers foreign key relationships using schema analysis and LLM inference, assigning each relationship a confidence score between 0.0 and 1.0. Discovered relationships include source and target database, table, column, cardinality, and description. You can also manually create relationships by selecting source and target tables and columns, specifying cardinality (> for many-to-one, < for one-to-many, - for one-to-one, <> for many-to-many), and saving entries individually or in bulk. Manually created relationships are labeled accordingly. To add a relationship, select Add. In Add table relationship, enter of select the following:
- Left Table: Select the table from the list.
- Right Table: Select the table from the list.
- Join Condition: Select the columns from each table to create a join condition.
- Type: Select the cardinality type.
- Description (Optional): Enter the description.
Select Save Relationship to save the table relationship. To edit the relationship, select the ellipsis (three dots), and then select Edit. To delete the relationship, select the ellipsis (three dots), and then select Delete.
|
| **Governance** | |
| **Chat Review** | Review recorded analyst conversations and user feedback to monitor quality and identify areas for improvement.View the question, rating, reason, and comment of the response. Select the question to view the Analyst’s response. Monitor response quality, review user feedback, and identify areas for improvement. |
| **API Keys** | Create and manage API keys used for authenticating requests to the[Aura Analyst API](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api.md).Copy the Aura Analyst API`/chat`endpoint URL. |
| **Access Controls** | Access Control provides the ability to assign roles, set permissions, and control who can access the domain.View all the users or teams and their roles in this tab. To share access to the domain with a user or a team, select**Add**. In the**Share \**dialog, select**User**or**Team**, select the access role, and then select**Save**.To remove access for any**User**or**Team**, select**Remove****Access**in the access role of the selected user or team. 📝 Note:
Inherited roles cannot be modified.
|
| **Settings** | Update the domain name and description in the**Name**and**Description**fields, respectively. Enable**Record conversations for review**. When enabled, the system saves all conversations for the selected domain to the**Chat Review**. If this setting is disabled, only questions with user feedback are captured in**Chat Review**. |
## Aura Analyst Access Controls
SingleStore Aura defines three RBAC (role-based access control) roles for Aura Analyst:
* **Organization Level Controls**:
* **Aura Creator**: Provides the ability to install and uninstall Aura Analyst.
* **Agent Domain Owner**: Provides the ability to create and manage domains.
> **📝 Note**: Domain creation is limited to the tables accessible by the "Agent Domain Owner".
* **Domain Level Controls**:
* **Owner**: Provides the ability to manage a given domain.
> **📝 Note**: Domain creation is limited to the tables accessible by the "Owner".
* **User**: Provides the ability to use the domain and ask questions in natural language and receive responses.
When an Agent Domain Owner creates a domain, the system performs the following actions:
* Aura Analyst fetches the data accessible to the Agent Domain Owner.
* Aura Analyst uses AI to infer tables and column definitions.
* SingleStore recommends owners to review the description and modify as required.
* When creating a new domain, a database user `_auraanalyst` is created with select permissions to the tables selected in the domain.
* All queries run by Aura Analyst within a Domain are run as `_auraanalyst` user.
A user can be granted Domain-level access even without having privileges on the underlying databases or tables referenced by the Domain. Aura Analyst runs queries inside the Domain as the `_auraanalyst` database user. This allows any user with access to the Domain to query the underlying databases.
A user may be an Aura Domain **User** or **Domain** Owner regardless of other organization roles. A user can be a member without any additional roles (a "roleless" org member) and still receive Domain-level permissions. However, these permissions do not grant or imply elevated privileges on the underlying databases.
> **📝 Note**: Domain owners must manage Domain roles and access settings to align with their organization’s governance policies.
## Interacting with Aura Analyst
Once a domain is created and configured, you can ask any data related questions to Aura Analyst using natural language. To start a conversation, select the desired domain in the chatbox. Domains can be switched at any time during a conversation.
> **📝 Note**: All queries and interactions require an active Domain context.
Within a conversation, following features can be accessed:
* **Thoughts block**: View how Aura Analyst approached to provide the insights as a response including the SQL queries executed.
* **Left panel controls**:
* View the chat history.
* Start a new session.
* Delete an existing session.
* **Feedback**: Your feedback enables a human-in-the-loop system that continuously improves results.
* Improve accuracy over time: Feedback helps refine how queries are interpreted and answered to deliver more reliable and complete responses for future queries.
* Domain expert review: Domain owners can review query interactions to identify gaps and improve overall system performance.
For a query response, use the “**Is this correct?**” option under the query result to provide feedback.
* Select **Yes** (thumbs-up) if the response is correct.
* Select **Needs Improvement** (thumb-down) if the response is incorrect or incomplete.
When **Needs Improvement** is selected, submit feedback by selecting one of the following options:
* Values look off
* Missing data
* Misunderstood question
* Analyst made something up
* Other
Optionally, enter additional details in the field to describe what went wrong.
> **📝 Note**: Observers can use [Monitoring](https://docs.singlestore.com/cloud/user-and-cluster-administration/cluster-health-and-performance/historical-monitoring/#section-idm33412590041948.md) and [Query History](https://docs.singlestore.com/cloud/query-data/query-tuning/query-history.md) to track queries run by Aura Analyst, including slow-performing queries.
## Share a Chat
You can share an Aura Analyst chat with other users in your organization, enabling them to review the conversation and its associated insights.
To share a chat:
1. Open a chat that includes at least one assistant response.
2. Select **Share** from the right top of the chat.
3. Copy the generated link and share it with the users who need access.
> **📝 Note**: - The shared chat is a snapshot of the conversation up to the most recent assistant response at the time of sharing. It does not update if the chat continues.
> - Shared chats are not public. A user can access a shared link only if the following conditions are met:
>
> * The user is signed in as a member of the same organization that owns the chat.
> * The user has permission to use the Aura Analyst domain associated with the chat.
> - Users who do not meet these conditions see an access denied message.
> - Sharing a chat link is separate from other sharing features in Aura Analyst. It does not affect the following:
>
> * Saving or sharing charts to dashboards
> * Domain access or domain sharing settings in **Domain settings**
## Continue a Shared Chat
When a user opens a shared link, the conversation appears in **read-only** mode.
To continue working from that conversation:
1. Select **Continue conversation** at the bottom of the page.
2. Aura Analyst creates a new chat session that copies the shared conversation.
New messages in this session do not affect the original chat or the shared snapshot.
## Examples
## Example 1: SaaS Product Usage Analytics
This example analyzes product adoption by creating a domain focused on it, using the relevant tables from the `saas_usage` database.

Once the domain is created, questions can be asked about the data.

## Example 2: E-commerce Marketing and Campaign Analytics
This example analyzes marketing product adoption by creating a domain focused on it, using the relevant tables from the `marketing_analytics` database.

Once the domain is created, questions can be asked about the data.

## In this section
* [Aura Analyst API](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api.md)
* [Aura Analyst API Reference](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api-reference.md)
***
Modified at: July 13, 2026
Source: [/cloud/ai/aura-analyst/](https://docs.singlestore.com/cloud/ai/aura-analyst/)
(An index of the documentation is available at /llms.txt)
---
# Aura Analyst API Reference
***
Modified at: July 14, 2026
Source: [/cloud/ai/aura-analyst/aura-analyst-api-reference/](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api-reference/)
(An index of the documentation is available at /llms.txt)
---
# Aura Analyst API
> **📝 Note**: This is a Preview feature.
[Aura Analyst](https://docs.singlestore.com/cloud/ai/aura-analyst.md) is a managed, AI-powered data analyst built natively for SingleStore. It enables you to submit natural language queries, which are automatically translated into optimized SQL statements and executed against the selected data sources. Built on SingleStore's Agentic AI platform, Aura Analyst delivers context-aware, governed, and accurate insights.
SingleStore Aura Analyst API ("the API") enables you to embed [Aura Analyst](https://docs.singlestore.com/cloud/ai/aura-analyst.md) capabilities in your applications, workflows, and user experiences via a REST interface to provide conversational access to data and analytics. Query the API using natural language queries and receive insights on your SingleStore data as tables, charts, or summaries.
## Why Use the Analyst API
The Analyst API provides a streamlined model to integrate Aura Analyst in your applications, which allows you to:
* Send natural language queries and receive generated SQL, results, and visualizations.
* Build interactive analytics experiences using a streaming chat endpoint that delivers real-time events over Server-Sent Events (SSE).
* Maintain multi-turn analytic sessions enabling follow-up questions to reuse prior context and results.
## Analyst API Endpoint Reference
Analyst API currently supports the following endpoints:
| Endpoint | HTTP Method | Request Body | Description |
| ------------------------ | ----------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/query` | `POST` | Required | **Structured Query Endpoint**Runs a natural language analytics query and returns a single, structured JSON response containing generated SQL, optional result data, charts, and explanatory text. Use this endpoint for integrations, pipelines, scheduled jobs, and embedded use-cases that require deterministic, machine-readable output instead of a chat-based stream. |
| `/chat` | `POST` | Required | **Streaming Chat Endpoint**Runs a natural language analytics query and streams back Server-Sent Events (SSE) for use in interactive chat-style UIs. Use this endpoint when real-time typing indicators or incremental responses are required for a chat-based stream. |
| `/conversation-starters` | `GET` | | **Conversation Starter Endpoint**Returns a list of generated starter prompts tailored to the current domain and agent context. Use this endpoint to populate suggested questions in the UI before a user submits the first query or starts a chat session. |
Use the `/query` endpoint for most integrations. It returns a single structured JSON response and is easier to parse in back-end services, pipelines, and embedded product workflows. Use the `/chat` endpoint for a streaming, interactive chat experience over Server-Sent Events (SSE), such as real-time typing indicators or incremental responses in a UI.
Refer to [Aura Analyst API Reference](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api-reference.md) for more information.
## Authentication
Analyst API authenticates to the server using [Bearer authentication](https://swagger.io/docs/specification/authentication/bearer-authentication/) standard, which must be used in conjunction with SSL (HTTPS) for secure communication over the network. To access the API, provide the Analyst API key in the Authorization request header in each HTTP request (API call). The API key is scoped at the domain-level, i.e., each API key is unique to the domain selected while generating the API key.
## Generate an API Key
To generate an API key for Analyst API:
1. On the [Cloud Portal](https://portal.singlestore.com), select **AI > Analyst** on the left navigation pane.
2. On the **Analyst** page, enable **Creator Mode**.
3. From the **Domain** list, select a domain.
4. Under **Governance**, select **API Keys** in the left pane.
5. On the **API Keys** page, select **Create API Key**.
6. In the **Create API key** dialog, enter a name for the API key and select an expiration window.
7. Select **Create API Key**.
8. Copy and securely store the API key. Alternatively, select **Save As Secret** to store the API key as a secret; enter a name for the secret in the **New Secret** dialog, and select **Create Secret**.
> **📝 Note**: The API key is displayed only once.
9. Select **Close**.
Use this key in the API call to authorize access to the API.
## Revoke an API Key
To revoke an existing API key:
1. Select **AI > Analyst**, enable **Creator Mode**, and select a domain.
2. Navigate to the **API Keys** section in the left pane.
3. Under the **Actions** column for the API key, select the delete icon.
4. On the **Revoke API Key** dialog, acknowledge the warning, and select **Revoke**.
The API key is now successfully revoked.
## Access the Analyst API
Copy the endpoint URL from the [Cloud Portal](https://portal.singlestore.com):
1. Select **AI > Analyst**, enable **Creator Mode**, and select a domain.
2. Navigate to the **API Keys** section in the left pane.
3. Select **Copy Endpoint** to copy the URL of the `/chat` endpoint. Replace `chat` with the endpoint to access in the URL.
The base URL of the Analyst API conforms to the following format:
```URL
https://apps.{region}.cloud.singlestore.com/v1/organizations/{orgID}/projects/{projectID}/analyst/
```
> **📝 Note**: The Analyst API endpoints use a domain-scoped API key for authentication. The API key's JWT claims encode the allowed domain, project, organization, and creator for a request. The `{orgID}` and `{projectID}` in the request path must match the key’s claims; otherwise, the request is rejected with `403 INVALID_API_KEY`.
To access the Analyst API, specify the API key in the Authorization header of the API request. For example, while making API calls through an HTTP client (such as cURL), specify the endpoint URL and API key as follows:
```shell
curl -X 'POST' \
'' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer '
```
## Getting Started with Aura Analyst API
To get started with the API:
1. [Create a domain](https://docs.singlestore.com/cloud/ai/aura-analyst/#section-id235182638851576.md) on the [Cloud Portal](https://portal.singlestore.com), or select an existing domain.
2. [Generate an API key](https://docs.singlestore.com/#section-id235672341710795.md) for the Analyst API.
3. [Copy the endpoint URL](https://docs.singlestore.com/#section-id235672343574668.md).
4. Use the API endpoint to access Aura Analyst via the API.
## Start a New Chat Session
Use the `POST /chat` endpoint to start an interactive Aura Analyst conversation over Server-Sent Events (SSE). To create a new chat session, omit `session_id` from the request body. You can also send `null` or an empty string and the gateway will create a new session automatically. The returned session can then be reused in later requests to continue the conversation. For example (update the endpoint, the API key, and message before running the following command):
```shell
curl -X POST "https://apps.${REGION}.cloud.singlestore.com/v1/organizations/${ORG_ID}/projects/${PROJECT_ID}/analyst/chat" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"message": "Show me sales data for Q4."
}'
```
The first stream includes a `response.created` event containing the generated `session_id`. Capture this value and include it in the next request to continue the same chat context.
## Continue an Existing Chat Session
Use the same `POST /chat` endpoint (used to start a new chat) to continue a prior Aura Analyst conversation. Include the previously returned `session_id` in the request body so the Analyst can reuse the earlier context and interpret follow-up questions correctly. For example (update the endpoint, the API key, message, and session ID before running the following command):
```shell
curl -X POST "https://apps.${REGION}.cloud.singlestore.com/v1/organizations/${ORG_ID}/projects/${PROJECT_ID}/analyst/chat" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"message": "Break that down by region",
"session_id": "${SESSION_ID}"
}'
```
The `session_id` must be a valid UUID.
## Get the Generated SQL from a Chat
## Streaming Chat Endpoint
To retrieve generated SQL from the streaming chat endpoint, send the request to `POST /chat` endpoint and set `included_events` to `["sql"]`, which is the event type used for generated SQL queries. The `included_events` field controls which event types are returned for chat responses. If you omit `included_events` or pass an empty array, the API returns all chat events. For example (update the endpoint, the API key, and message before running the following command):
```shell
curl -X POST "https://apps.${REGION}.cloud.singlestore.com/v1/organizations/${ORG_ID}/projects/${PROJECT_ID}/analyst/chat" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"message": "What were the top 10 products by revenue last month?",
"included_events": ["sql"]
}'
```
To query the results in addition to the SQL, use `["sql", "data"]` instead. SingleStore recommends this combination for developer and debugging workflows because it returns both the generated SQL and the executed results. Refer to [Aura Analyst API Reference](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api-reference.md) for more information.
## Structured Query Endpoint
To retrieve the generated SQL for a back-end integration, use the `POST /query` endpoint instead of the streaming chat endpoint. Set `output_modes` to `["sql"]` to return only the generated SQL or `["sql", "data"]` to return both the generated SQL and the executed results. For example (update the endpoint, the API key, and message before running the following command):
```shell
curl -X POST "https://apps.${REGION}.cloud.singlestore.com/v1/organizations/${ORG_ID}/projects/${PROJECT_ID}/analyst/query" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"message": "What were the top 10 products by revenue last month?",
"output_modes": ["sql"]
}'
```
The generated SQL is returned in `results[].sql.command` in the response. Refer to [Aura Analyst API Reference](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api-reference.md) for more information.
## Related Topics
* [Aura Analyst](https://docs.singlestore.com/cloud/ai/aura-analyst.md)
* [Aura Analyst API Reference](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api-reference.md)
***
Modified at: July 16, 2026
Source: [/cloud/ai/aura-analyst/aura-analyst-api/](https://docs.singlestore.com/cloud/ai/aura-analyst/aura-analyst-api/)
(An index of the documentation is available at /llms.txt)
---
# Models
> **📝 Note**: This is a Preview feature.
Models integrate directly with existing SingleStore workflows and provide enterprise-grade performance, security, and observability to support building GenAI-ready applications.
This Helios feature supports:
1. **LLM models**: Deploy and run large language models (LLMs) for text generation and conversational tasks.
2. **Embedding models**: Generate embeddings for semantic search, recommendations, and similarity tasks.
3. **ML models**: Build, train, and run custom ML models for specific applications.
SingleStore Models supports the following deployment options:
* Externally hosted:
* Azure AI Services
* Amazon Bedrock
* Aura hosted: This option hosts the model on SingleStore Aura container service that provides lowest latency (model co-located with compute and data) and ensures that data never leaves the SingleStore VPC. It supports custom and open-source models.
## LLM Models
SingleStore supports the following LLM models:
| Provider | Publisher | Model |
| ---------------------- | ----------------------------------------------------------- | -------------------------------------------------------------- |
| Amazon Bedrock | Anthropic | - Claude Opus 4.6
- Claude Sonnet 4.6
|
| Azure AI Services | OpenAI | |
| Aura Hosted LLM Models | Open source models (Refer to License for individual models) | |
## Embedding Models
SingleStore supports the following embedding models:
| Provider | Publisher | Model |
| ---------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Amazon Bedrock | Amazon | - Titan Embeddings G1 - Text
- Titan Text Embeddings V2
|
| Amazon Bedrock | Anthropic | - Amazon Nova Multimodal Embeddings
|
| Azure AI Services | OpenAI | - text-embedding-3-small
- text-embedding-3-large
|
| Aura Hosted embedding models | Open source models (Refer to License for individual models) | |
## ML Models
Refer to [ML Functions](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ml-functions.md) for more information.
## Create a Model Inference
## LLM Model Inference
Create an LLM model inference by following these steps:
1. Navigate to the [Cloud Portal](http://portal.singlestore.com).
2. In the left navigation, select **AI > Models**.
3. Select the **LLM Models** tab, and then select **New**.
4. In **Select Model**, select the **Provider** and the model of your choice, and then select **Next**.
5. In **Model Settings**, enter and review the following information:
| **Name** | Enter a name for the selected model. |
| ------------------ | --------------------------------------------------------------------- |
| **Description** | Enter the selected model description. |
| **Region** | Select the region for the selected model. |
| **Estimated Cost** | Displays the maximum number of tokens allowed for the selected model. |
6. Accept the terms of service agreement and select **Publish** for the selected LLM model inference deployment.
Once the LLM model inference is deployed, use the LLM model inference via the following options:
* API: Follow the sample code to start integrating with the model in either Python or Node.js.
* AI Functions: Refer to [Text Processing Functions](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ai-functions/#section-id235175307180532.md) for more information.
## Embedding Model Inference
Create an embedding model inference by following these steps:
1. Navigate to the [Cloud Portal](http://portal.singlestore.com).
2. In the left navigation, select **AI > Models**.
3. Select the **Embedding Models** tab, and then select **New**.
4. In **Select Model**, select the **Provider** and the model of your choice, and then select **Next**.
5. In **Model Settings**, enter and review the following information:
| **Name** | Enter a name for the selected model. |
| ------------------ | --------------------------------------------------------------------- |
| **Description** | Enter the selected model description. |
| **Region** | Select the region for the selected model. |
| **Estimated Cost** | Displays the maximum number of tokens allowed for the selected model. |
6. Accept the terms of service agreement and select **Publish** for the selected embedding model inference deployment.
Once the embedding model inference is deployed, use the embedding model inference via the following options:
* API: Follow the sample code to start integrating with the model in either Python or Node.js.
* AI Functions: Refer to [Embedding Function](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ai-functions/#section-id235175344319444.md) for more information.
## Train a New ML Model
Refer to [Train a New ML Model](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ml-functions/#section-id23517557347527.md) for more information.
## Manage LLMs and Embedding Model Inference
Existing LLMs and embedding model inferences can be managed by performing following actions:
* Explore the existing model inferences in Playground
* Update
* Share
* Delete
A notebook can be generated for the embedding model inference only.
## Use an Existing Model Inference
To use the existing model inference, perform the following actions:
* Select the model in the **Name** column and then select **Details** to view the sample code for the integration.
* Create an Aura App API key to use the existing model inference. Refer to [Aura App API Keys](https://docs.singlestore.com/cloud/container-services/container-app-api-keys.md) for related information.
## Generate an Embeddings Notebook
Embedding notebooks can be generated for an embedding model inference. Select **Details > Generate Notebook**. The embedding notebook uses an existing embedding model inference to generate embeddings for a column in a specified table. It stores the resulting vectors in a new column within the same table that enables it to manage and query the embeddings alongside the original data. In the **Embeddings Notebook** dialog, enter or select the following:
| **Cluster** | Select acluster. |
| ---------------------- | ---------------------------------------------------------------------- |
| **Database** | Select a database. |
| **Table** | Select a table. The selected table must have embeddable columns. |
| **Source Column** | Select a source column. |
| **Destination Column** | Enter the name of the destination column. |
| **API Key Secret** | Select the Aura App API key created for the embedding model inference. |
Select **Generate** to generate the embedding notebook. A **Vector Embedding Pipeline Notebook** is created. View the generated embedding notebook in **Editor > Shared**.
## Explore an Existing Model Inference in Playground
To explore an existing model inference in the playground, select the model inference in the **Name** column and then select **Playground**.
## Embedding Model
In **Text Input**, enter the text to generate embeddings and view the results in **Embedding Results**.
## Chat Completion Model
In **Text Input**, enter the text to generate text or chat with the model. Set model parameters as required.
**Parameters**
| **System Prompt** | Enter the system prompt for the chat completion model. |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Temperature** | Set the temperature of the model. Lower values are less random and near zero is deterministic. The default value is 0.7. It ranges between 0 and 1. |
| **Max. Tokens** | Set the maximum number of tokens generated by the model. The default value is 512. It ranges between 1 and 1024. |
| **Frequency Penalty** | Set the frequency penalty of the model. It penalizes new tokens based on existing frequency which reduces repetition. The default value is 0. It ranges between -2 and 2. |
| **Top P** | Set the top P parameter of the model. It controls diversity via nucleus sampling (for example, 0.5 considers half of options). The default value is 1. It ranges between 0 and 1. |
## Update an Existing Model Inference
To update an existing model inference, select the model in the **Name** column and then select **Update** in the upper right. Enter the updates required for the existing model inference, and select **Update**.
## Share an Existing Model Inference
To share an existing model inference, navigate to **Models > LLM Models/Embedding Models**, select the ellipsis in the **Actions** column of the model, and select **Share**. Select the **User** or **Team** with which to share the model inference and select **Save**.
> **📝 Note**: Custom models must be shared before use. Hence, to use a newly created model instance in an AI function, you have to explicitly share the model with the service account created during AI function installation.
## Delete an Existing Model Inference
To delete an existing model inference, select the ellipsis in the **Actions** column of the model, and select **Delete**.
## Manage an Existing ML Model
Refer to [Manage an Existing ML Model](https://docs.singlestore.com/cloud/ai/ai-ml-functions/ml-functions/#section-id235175587330847.md) for more information.
***
Modified at: June 1, 2026
Source: [/cloud/ai/models/](https://docs.singlestore.com/cloud/ai/models/)
(An index of the documentation is available at /llms.txt)
---
# SingleStore AI Rules
SingleStore AI rules are context rules that help AI-assisted development tools or MCP (Model Context Protocol) clients, such as Cursor, in understanding SingleStore’s features. These rules improve the accuracy of code suggestions when working with SingleStore.
AI rules are defined in `.mdc` files. Each `.mdc` file specifies the file types it applies to. When you open a matching file, your AI tool automatically applies the rules to provide more relevant suggestions.
## Add AI Rules
To enable SingleStore AI rules in your project:
1. Add the SingleStore rules files to the `.cursor/rules` directory in your project.
2. The AI tool automatically applies the rules when working with SingleStore related code.
3. Mention these rules in your prompts to receive more specific suggestions.
## AI Context Rules for Drizzle ORM
AI Context rules simplify working with Drizzle ORM (Object-Relational Mapping) in combination with SingleStore when using AI tools.
To use these rules with Drizzle ORM:
* **In Cursor**: Save the [rules](https://docs.cursor.com/context/rules-for-ai#project-rules-recommended) file as `.cursor/rules/singlestore-drizzle.mdc`. The rules are applied automatically when working with files that match supported patterns.
* **In other AI tools**: Include the rules as context when interacting with your AI assistant. Refer to your tool’s documentation for details on how to provide external context (for example, Include file or context commands).
* **Clone or download the rules**: You can clone or download the [SingleStore AI rules](https://github.com/singlestore-labs/mcp-server-singlestore/blob/main/src%2Fapi%2Fresources%2Fdocs%2Fsinglestore-drizzle.mdc). Once the rules are part of your project, AI tools automatically apply them when generating Drizzle ORM code for SingleStore. You can mention these rules in prompts to get more consistent results.
Refer to [Create a Drizzle ORM Project Using the SingleStore MCP Server](https://docs.singlestore.com/cloud/ai/singlestore-mcp-server/create-a-drizzle-orm-project-using-the-singlestore-mcp-server.md) to know more about how to create a Drizzle ORM project using SingleStore MCP Server.
***
Modified at: September 22, 2025
Source: [/cloud/ai/singlestore-ai-rules/](https://docs.singlestore.com/cloud/ai/singlestore-ai-rules/)
(An index of the documentation is available at /llms.txt)
---
# SingleStore MCP Server
## Overview
The Model Context Protocol (MCP) is an open protocol that standardizes how external tools and interfaces communicate context to large language models (LLMs). With MCP, you can describe an environment in which a model operates, including available tools, user intent, system state, and related contextual information.
## Why Use MCP?
MCP enables you to:
* Define context programmatically which enables the model to accurately interpret your goals and available tools.
* Eliminate the need for writing custom prompts for each integration scenario.
* Expose your system’s capabilities and usage conditions for scalable and collaborative AI agent design.
## Capabilities and Benefits
The [SingleStore MCP server](https://github.com/singlestore-labs/mcp-server-singlestore) implements Model Context Protocol (MCP) to enable seamless integration between large language models (LLMs) and SingleStore database services. The server provides a set of tools, resources and prompts templates that allows MCP compatible clients, such as Claude Desktop, VS Code, and Cursor, to interact with SingleStore using natural language prompts. These tools expose essential functionality for database management, notebook workflows, job scheduling, and usage tracking.
The SingleStore MCP server has the following key capabilities:
* **Authentication and Configuration**
* Authenticates with SingleStore’s management API using secure API keys.
* Maintains user-specific session state, including preferences and input history, to support contextual interactions.
* **Cluster and Database Management**
* Retrieves metadata about accessible cluster groups, including cluster group IDs and names.
* Lists clusters within a selected cluster group and provides endpoint and status details.
* Returns details about the user’s current organization, including metadata and settings.
* Lists all supported deployment regions with relevant identifiers and region-specific metadata.
* Runs SQL queries on connected clusters and returns structured results with rows, columns, and error handling.
* Manages Shared clusters within SingleStore:
* Lists available Shared clusters.
* Creates new shared clusters with specific configurations.
* Organizes user access controls and permissions.
* Runs SQL on virtual clusters.
* **Notebook and File Management**
* Manages notebooks:
* Lists available notebook samples.
* Creates new notebooks in the user’s personal cluster.
* Supports custom notebook content and configurations.
* Manages files:
* Lists files in both personal and shared spaces.
* Creates and manages files.
* Organizes file access controls and permissions.
* **Scheduling Jobs**
* Creates scheduled jobs:
* Creates jobs that run notebooks on a defined schedule (one-time or recurring).
* Configures runtime environments and notebook parameters.
* Manages notebook snapshots.
* Monitors jobs:
* Retrieves detailed information about scheduled jobs.
* Lists historical executions.
* Monitors job status and execution results.
## Set Up SingleStore MCP Server
> **📝 Note**: To use the SingleStore MCP Server, you need a SingleStore Helios account and API access credentials.
## Prerequisites
Ensure the following tools are installed:
* Python 3.11+
* [uvx](https://docs.astral.sh/uv/guides/tools/)
* [uv](https://docs.astral.sh/uv/getting-started/installation/)
* Preferred MCP client
## Supported MCP Clients
The SingleStore MCP server supports the following clients:
* Claude Desktop
* Claude Code
* Cursor
* Visual Studio Code
* Windsurf
* Gemini CLI
* LM Studio
* Goose
* Qodo Gen
Following MCP clients are available through Docker Desktop:
* Continue.dev
* Gordon
## MCP Client Setup
You can set up a supported MCP client using any of the following approaches:
1. **Using the initialization command**: The initialization command automatically locates the appropriate configuration file for your client platform and adds or updates it to include the SingleStore MCP server. Additionally, it sets up browser-based OAuth authentication and displays instructions for starting the server.

Use the following command to initiate the server:
```shell
uvx singlestore-mcp-server init
```
Use the following command to specify a client:
```shell
uvx singlestore-mcp-server init --client=
```
Replace `` with a supported MCP client. Following are the example syntax for the supported MCP client.
* Claude Desktop
```shell
uvx singlestore-mcp-server init --client=claude-desktop
```
* Claude Code
```shell
uvx singlestore-mcp-server init --client=claude-code
```
* Cursor
```shell
uvx singlestore-mcp-server init --client=cursor
```
* Visual Studio Code
```shell
uvx singlestore-mcp-server init --client=vscode
```
* Windsurf
```shell
uvx singlestore-mcp-server init --client=windsurf
```
* Gemini CLI
```shell
uvx singlestore-mcp-server init --client=gemini
```
* LM Studio
```shell
uvx singlestore-mcp-server init --client=lm-studio
```
2. **Installing via Smithery**: Use the following command to install `singlestore-mcp-server` via Smithery:
```shell
npx -y @smithery/cli install @singlestore-labs/mcp-server-singlestore --client=
```
Replace `` with a supported MCP client.
3. **Manual Configuration**: You can configure the following supported MCP clients manually. Add the following standard configuration to your MCP client’s configuration file:
```shell
{
"mcpServers": {
"singlestore-mcp-server": {
"command": "uvx",
"args": [
"singlestore-mcp-server",
"start"
]
}
}
}
```
Use the configuration file of the MCP client as mentioned in the following client's documentation:
1. **Claude Desktop**: Refer to the MCP install [guide](https://modelcontextprotocol.io/quickstart/user) for the related information.
2. **Claude Code**: Run the following command to manually setup the MCP client:
```shell
claude mcp add singlestore-mcp-server uvx singlestore-mcp-server start
```
3. **Cursor**: Navigate to **Cursor Settings > MCP > Add new MCP Server**. Enter the name of the MCP server. Select `command` type, and enter the command `uvx singlestore-mcp-server start`. Select **Edit** to verify configuration or add command line arguments.
4. **Visual Studio Code**: Refer to the MCP install [guide](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server) for the related information. You can also install using the VS Code CLI:
```shell
code --add-mcp '{"name":"singlestore-mcp-server","command":"uvx","args":["singlestore-mcp-server","start"]}'
```
After installation, the SingleStore MCP server is available for use with your GitHub Copilot agent in VS Code.
5. **Windsurf**: Refer to the Windsurf [documentation](https://docs.windsurf.com/windsurf/cascade/mcp) for the related information.
6. **Gemini CLI:** Refer to the MCP install [guide](https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md#configure-the-mcp-server-in-settingsjson) for the related information.
7. **LM Studio**: Navigate to **Program** in the right sidebar, then select **Install > Edit `mcp.json`**.
8. **Goose**: Navigate to **Advanced settings > Extensions > Add custom extension**. Enter the name of your custom extension. Select type `STDIO`, and enter the command `uvx singlestore-mcp-server start`. Select **Add Extension** to add your custom extension.
9. Qodo Gen: Open [Qodo Gen](https://docs.qodo.ai/qodo-documentation/qodo-gen) chat panel in VSCode or IntelliJ. Select **Connect more tools > + Add new MCP**, and paste the standard configuration.
> **📝 Note**: This approach does not require any API keys, tokens, or environment variables. When the server starts, authentication is automatically handled via browser-based OAuth.
4. **Using Docker**:
1. Run the following command to build the docker image of the SingleStore MCP server:
```shell
docker build -t singlestore/mcp-server-singlestore .
```
2. Use the following configuration:
```shell
{
"mcpServers": {
"singlestore-mcp-server": {
"command": "docker",
"args": [
"run", "-i", "--rm", "--init", "--pull=always",
"-e", "MCP_API_KEY=your_api_key_here",
"singlestore/mcp-server-singlestore"
]
}
}
}
```
3. Update the configuration of your MCP configuration file, and then restart your MCP client.
> **📝 Note**: When running the server in a Docker container, an API key is required. Browser-based OAuth is not supported for locally hosted containers. For improved security, SingleStore recommends using Docker Desktop to configure the SingleStore MCP server. Refer to The Docker MCP Catalog: the Secure way to Discover and Run MCP Servers for more information.
## Tools in SingleStore MCP Server
The SingleStore MCP server implements the following tools:
| **Tool** | **Description** | **Arguments** | **Returns** |
| ----------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| `get_user_info` | Retrieves details about the user. | None | User details |
| `organization_info` | Retrieves details about the current organization. | None | Organization details |
| `choose_organization` | Retrieves list of organizations. | None | List of organizations |
| `set_organization` | Sets the selected organization. | | Sets the organization |
| `workspace_groups_info` | Retrieves details about accessibleclustergroups. | None | Clustergroup details |
| `workspaces_info` | Retrievesclusters in a specificclustergroup. | | Clusterdetails |
| `resume_workspace` | Resumes a pausedclusterwithin theclustergroup. | | Resumescluster |
| `list_starter_workspaces` | Lists all Sharedclusters accessible to the user. | None | Sharedclusterdetails |
| `create_starter_workspace` | Creates a Sharedclusterand user. | name database_name username password workspace_group (optional)
| Details of the createdclusterand user |
| `terminate_starter_workspace` | Terminates Sharedcluster. This action cannot be undone. | | Terminates Sharedcluster |
| `list_regions` | Lists all regions that supportclusters. | None | List of regions |
| `list_sharedtier_regions` | Lists the available regions before creating a Sharedcluster. | None | Lists region name and cloud provider. |
| `run_sql` | Runs SQL on a connectedcluster. | workspace_group_identifier workspace_identifier username password database sql_query
| SQL results in structured format |
| `create_notebook_file` | Creates a new notebook in the specified space (personal or shared). | notebook_name content (optional)
| Created notebook details |
| `upload_notebook_file` | Uploads created notebook file in theCloud Portal. | local_path upload_name (optional) upload_location (optional)
| Uploads created notebook |
| `create_job_from_notebook` | Creates a scheduled job to run a notebook. | name notebook_path schedule_mode execution_interval_minutes (optional) start_at (optional) description (optional) create_snapshot (optional) runtime_name parameters (optional) target_config (optional)
| Created job details |
| `get_job` | Retrieves details of an existing job | | Existing job details |
| `delete_job` | Permanently deletes a scheduled job. | | Deletes the scheduled job permanently |
## In this section
* [Examples](https://docs.singlestore.com/cloud/ai/singlestore-mcp-server/examples.md)
* [Create a Drizzle ORM Project Using the SingleStore MCP Server](https://docs.singlestore.com/cloud/ai/singlestore-mcp-server/create-a-drizzle-orm-project-using-the-singlestore-mcp-server.md)
***
Modified at: July 10, 2026
Source: [/cloud/ai/singlestore-mcp-server/](https://docs.singlestore.com/cloud/ai/singlestore-mcp-server/)
(An index of the documentation is available at /llms.txt)
---
# Create a Drizzle ORM Project Using the SingleStore MCP Server
You can easily create a Drizzle ORM project using the SingleStore MCP server and the VS Code MCP Client to connect to your SingleStore deployment and run queries.
## Prerequisites
* Python 3.11+
* [uv](https://docs.astral.sh/uv/getting-started/installation/)
* [uvx](https://docs.astral.sh/uv/guides/tools/)
* GitHub Copilot for VS Code
## Connect to SingleStore using Drizzle ORM
The following example creates a Drizzle ORM project using the SingleStore MCP Server and the GitHub Copilot in VS Code MCP client, and performs the following tasks in response to a specified prompt:
1. Initializes a `npm` project and installs the required dependencies.
2. Creates the required configuration files (Typescript config, Drizzle config, etc.).
3. Connects to a SingleStore deployment and runs the specified migration.
1. Creates a table named `stock` in the SingleStore database.
2. Inserts a sample data set into the `stock` table.
3. Queries the table.
4. Provides an overview of the steps performed.
The Copilot automates each of these steps, prompting the user only for a confirmation to proceed.
## Step 1: Install the SingleStore MCP Server
Open an empty folder in VS Code and perform the following tasks:
1. Run the following command in the terminal to initialize the SingleStore MCP Server in VS Code:
```shell
uvx singlestore-mcp-server init
```
2. Authenticate via browser OAuth (log in to the [Cloud Portal](https://portal.singlestore.com)).
3. Restart the MCP client (VS Code) to apply the changes.
## Step 2: Add the SingleStore Drizzle ORM Context
After the changes are applied,
1. Select **Add context** in the Copilot Chat view.
2. From the list of resources, select **MCP Resources**.
* (If required) Authenticate via browser OAuth. And, then select **Add context > MCP Resources**.
* (If required) Start the SingleStore MCP server, select the icon in the chat view, and then select **Start Server** from the list.
3. Select **get\_singlestore\_drizzle\_guide**.
## Step 3: Initialize the Project and Run the Application using Copilot
Upon adding the `get_singlestore_drizzle_guide` MCP context, enter the following prompt (or similar) in the Chat view:
> **📝 Note**: Update the connection configuration (connection string) of your SingleStore Helios deployment before submitting the prompt.
```Prompt
Create a sample Drizzle project using SingleStore.
The endpoint URL of the SingleStore deployment is:
singlestore://:@:/.
Create a table named stock, with the ID, Type, and quantity columns.
Insert sample data into the table and then query the data.
Also calculate the total stock of each Type.
```
After submitting the prompt, follow the instructions in the Chat view. The following example demonstrates the steps performed and the output generated by the Chat view in response to the specified prompt.
> **📝 Note**: The Copilot automates each of these steps, prompting the user only for a confirmation to proceed. (You may be prompted to select **Continue** after completing each step.)
1. Initialize a new `npm` project.
```Response
I'll help you create a Drizzle project with SingleStore integration.
Let's break this down into steps:
First, let's create a new workspace for the project:
- Generating plan to create a new workspace
Let me help you create a Drizzle project with SingleStore integration.
I'll create the necessary files and set up the project structure.
First, let's initialize a new npm project and install the required dependencies:
Run command in terminal
npm init -y
Initializing a new npm project
```
2. Install the required dependencies.
```Response
Now, let's install the required dependencies:
Run command in terrminal:
npm install drizzle-orm mysql2 dotenv && npm install -D drizzle-kit typescript ts-node @types/node
Installing required dependencies
```
3. Generate the following necessary files:
* `tsconfig.json` (TypeScript configuration)
* `schema.ts` (database schema)
* `drizzle.config.ts` (Drizzle configuration)
* `index.ts` (database connection and queries)
* `.env` (environment variables)
* `package.json` (package scripts)
```Response
Let's create the necessary TypeScript configuration:
Created tsconfig.json
Now, let's create our database schema:
Created schema.ts
Let's create the Drizzle configuration file:
Created drizzle.config.ts
Let's create our database connection and queries:
Created index.ts
Let's create the environment file with the SingleStore connection URL:
Created .env
Let's update the package.json scripts:
Created package.json
```
4. Run the migrations and start the application.
```Response
Now, let's run the migrations and start the application.
First, we'll generate and push the migrations:
Run command in terminal
npm run generate && npm run push
Generating and pushing the database migrations
Now let's run the application.
npm run start
```
```output
Connecting to database...
Creating stock table...
Successfully connected to the database
Inserting sample data...
Querying all stocks:
[
{ id: 4503599627370498, type: 'Furniture', quantity: 50 },
{ id: 4503599627370499, type: 'Electronics', quantity: 75 },
{ id: 4503599627370500, type: 'Clothing', quantity: 200 },
{ id: 4503599627370497, type: 'Electronics', quantity: 100 },
{ id: 4503599627370501, type: 'Furniture', quantity: 25 }
]
Calculating total stock by type:
[
{ type: 'Electronics', totalQuantity: '175' },
{ type: 'Clothing', totalQuantity: '200' },
{ type: 'Furniture', totalQuantity: '75' }
]
```
5. Overview of the steps performed.
```Response
Let's break down what we've accomplished:
* Successfully connected to the SingleStore database
* Created the stock table with the required columns:
* id (BIGINT, auto-incrementing primary key)
* type (VARCHAR)
* quantity (INT)
* Successfully inserted sample data with different types of stock:
* Electronics (total: 175 units)
* Furniture (total: 75 units)
* Clothing (total: 200 units)
* Successfully queried the data:
* Retrieved all stock entries
* Calculated total quantity by type using GROUP BY aggregation
The application is now fully functional!
```
As instructed in the prompt, the Copilot successfully completes the specified tasks.
## Related Topics
* [Connect with Drizzle ORM](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js/connect-with-drizzle-orm.md)
***
Modified at: September 22, 2025
Source: [/cloud/ai/singlestore-mcp-server/create-a-drizzle-orm-project-using-the-singlestore-mcp-server/](https://docs.singlestore.com/cloud/ai/singlestore-mcp-server/create-a-drizzle-orm-project-using-the-singlestore-mcp-server/)
(An index of the documentation is available at /llms.txt)
---
# Examples
The following examples demonstrate how to use the SingleStore MCP Server with the Claude Desktop. This requires an initial setup. Perform the following tasks to initiate the MCP client:
1. Run the following command in the terminal:
```shell
uvx singlestore-mcp-server init
```
2. Restart Claude Desktop.
> **📝 Note**: When using third-party tools such as Claude with the SingleStore MCP server, a permission prompt appears requesting access to run actions like `run_sql`. Review each action carefully before granting access. These tools operate independently, and Claude cannot guarantee the security or privacy practices of third-party integrations.You can choose one of the following options:- **Allow once**: Approves the action for a single use.
> - **Allow always**: Grants persistent access for future requests.
> - **Decline**: Denies the request.For improved security, SingleStore recommends selecting **Allow once** during initial setup or testing.
## Create a Notebook in Personal Space
This example creates a notebook in personal space. Open Claude Desktop, and enter the following prompt:
```shell
Create a notebook named myrag in personal space. In this notebook, write a python code to create a RAG application. The RAG application will use arxiv papers as data source, SingleStore as vector database, Gemma model as the LLM, and use LangChain orchestration framework.
```
Once the prompt is submitted, the following tools will run to perform the relative task:
* `choose_organization`: Selects the organization.
* `set_organization`: Sets the organization.
* `create_notebook_file`: Creates a notebook with a comprehensive RAG application that uses ArXiv papers, SingleStore as the vector database, Gemma as the LLM, and LangChain orchestration framework.
* `upload_notebook_file`: Uploads the notebook to your personal space with the name **myrag**.

The notebook is created with the MCP integration. You can view the notebook in your personal space in the [Cloud Portal](http://portal.singlestore.com).

## Query a Database
This example creates a table, ingests data into the table, and queries the inserted data.Before proceeding with this example, create a database named `sales` and an associated table. Open Claude Desktop, and update your cluster, cluster group, and organization details in the following prompt:
```shell
Create a new database named sales in under of , and then create a table called SalesData with the following columns:
- Date: Text
- Store_ID: Big integer (20), nullable
- ProductID: Text
- Product_Name: Text,
- Product_Category: Text
- Quantity_Sold: Big integer (20), nullable
- Price: Float, nullable
- Total_Sales: Float, nullable
```
Once the prompt is submitted, the following tools will run to perform the relative task:
* `choose_organization`: Checks the organization information.
* `set_organization`: Sets the organization to the specified organization.
* `cluster_groups_info`: Checks and finds information on the specified cluster group.
* `clusters_info`: Checks and finds information on the specified cluster.
* `run_sql`: Creates the specified database.
* `run_sql`: Creates the specified tables.

To ingest data using a pipeline, enter the following prompt:
```shell
Create a pipeline SalesData_pipeline using 's3://singlestoreloaddata/SalesData/*.csv'
```
Once the prompt is submitted, the following tool will run to perform the relative task:
* `run_sql`: Creates the pipeline in the `sales` database.

To start the pipeline, enter the following prompt:
```shell
Start the pipeline
```
Once the prompt is submitted, the following tool will run to perform the relative task:
* `run_sql`: Starts the pipeline.

To query the data in the table, enter the following prompt:
```shell
Identify the top three stores with the highest sales in the Electronics category.
```
Once the prompt is submitted, the following tool will run to perform the relative task:
* `run_sql`: Queries the `SalesData` table to find the top three stores with the highest sales in the Electronics category.

## Create a Scheduled Job
This example creates a notebook in shared space and schedules the job. Open Claude Desktop, and update your cluster, cluster group, and organization details in the following prompt:
```
Create a notebook named SalesData in the shared space. In the notebook, use the SalesData table from the sales database in under of , to generate appropriate visualizations based on the data.
```
Once the prompt is submitted, the following tools will run to perform the relative task:
* `choose_organization`: Checks the organization information.
* `set_organization`: Sets the organization to the specified organization.
* `cluster_groups_info`: Checks and finds information on the specified cluster group.
* `clusters_info`: Checks and finds information on the specified cluster.
* `run_sql`: Explores SalesData table structure.
* `run_sql`: Understands the sample data of the table.
* `run_sql`: Understands the aggregate information of the table.
* `run_sql`: Explores the distinct product categories.
* `create_notebook_file`: Creates the **SalesData** notebook file.
* `upload_notebook_file`: Uploads the **SalesData** notebook file in shared space.

The notebook is created in the shared space in the Cloud Portal.

To schedule the notebook, enter the following prompt:
```shell
Create a schedule job using the SalesData notebook, with the name of job as SalesJob, start executions "Now", with "Weekly" "Recurring" schedule mode. Save all the execution results.
```
Once the prompt is submitted, the following tool will run to perform the relative task:
* `create_job_from_notebook`: Creates a scheduled job using SalesData notebook in weekly recurring schedule mode.

***
Modified at: May 13, 2026
Source: [/cloud/ai/singlestore-mcp-server/examples/](https://docs.singlestore.com/cloud/ai/singlestore-mcp-server/examples/)
(An index of the documentation is available at /llms.txt)
---
# Connect to SingleStore
SingleStore is MySQL wire-compatible and offers a wide range of tools and integrations to connect to your database. In most cases, you can connect to your SingleStore Helios deployment from MySQL-compatible tools without any customization using the [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md).
## Develop with SingleStore
SingleStore simplifies the process of connecting to your database and starting application development using various libraries:
| [C/C++](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-c-c.md) | [C#/.NET](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core.md) | [LangChain](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-with-langchain.md) |
| ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Java/JDBC](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc.md) | [Laravel](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-laravel.md) | [Node.js](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js.md) |
| [Perl](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-perl.md) | [PHP](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-php.md) | [Python](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python.md) |
| [Ruby](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-ruby.md) | [Rust](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-rust.md) | [Go](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-go.md) |
Refer to [Connect with Application Development Tools](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools.md) for more information.
## SQL Client Drivers
SingleStore offers native drivers which may provide enhancements and performance improvements over standard MySQL drivers.
## Native Client Drivers
SingleStore provides the following native client drivers:
* [The SingleStore JDBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md)
* [The SingleStore ODBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc/the-singlestore-odbc-driver.md)
## MySQL Client Drivers
Refer to [Connect with MySQL](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql.md) for supported MySQL Clients and MySQL-compatible tools.
## Data Access APIs
You can connect to your SingleStore Helios deployments via a data access API using the following:
* [Connect with Data API](https://docs.singlestore.com/cloud/reference/data-api.md)
* [Connect with Hasura](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-hasura.md)
## Integrated Clients
* [Connect with Integrated Notebooks](https://docs.singlestore.com/cloud/container-services/notebooks.md)
* [Connect with SQL Editor](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-the-sql-editor.md)
## Supported SQL Clients
SingleStore supports the following following SQL clients:
* [Connect with DBeaver](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-dbeaver.md)
* [Connect with DbVisualizer](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-dbvisualizer.md)
* [Connect with Sequel Pro](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sequel-pro.md)
* [Connect with SQL Developer](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sql-developer.md)
* [Connect with SQL Workbench](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sql-workbench.md)
## Supported Analytics and BI Tools
| [Alteryx Designer](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-alteryx-designer/) | [IBM Cognos Analytics](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-ibm-cognos-analytics/) | [Denodo](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-denodo/) |
| ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| [Dremio](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-dremio/) | [Oracle GoldenGate](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-oracle-goldengate/) | [GoodData](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-gooddata/) |
| [Looker](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-looker/) | [MicroStrategy](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-microstrategy/) | [Power BI](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-power-bi/) |
| [Sisense](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-sisense/) | [Superset](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-superset/) | [Tableau Desktop](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-tableau/connect-with-tableau/) |
| [ThoughtSpot](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-thoughtspot/) | [Tibco Spotfire](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-tibco-spotfire/) | [Zoho Analytics](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-zoho-analytics/) |
Refer to [Connect with Analytics and BI Tools](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools.md) for more supported tools.
## Supported Data Integration and ETL Tools
| [AWS Glue](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-aws-glue.md) | [Apache Beam](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-apache-beam.md) | [Apache Flink](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-apache-flink.md) |
| --------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| [Apache NiFi](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/connect-with-apache-nifi.md) | [Azure Data Factory (ADF)](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-azure-data-factory-adf.md) | [Azure Event Hubs](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-azure-event-hubs.md) |
| [Data Virtuality Pipes](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-data-virtuality-pipes.md) | [dbt](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/transform-data-with-dbt.md) | [Estuary Flow](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-estuary-flow.md) |
| [Fivetran](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-with-fivetran.md) | [Flyway](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/migrate-schema-with-flyway.md) | [HVR](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-hvr.md) |
| [Informatica PowerCenter](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-informatica-powercenter.md) | [Liquibase](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-with-liquibase.md) | [Qlik Replicate](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-qlik-replicate.md) |
| [Kafka Sink](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/singlestore-kafka-sink-connector.md) | [Spark](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-spark.md) | [StreamSets](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios/load-data-from-streamsets.md) |
| [Tableau Prep](https://docs.singlestore.com/cloud/query-data/connect-with-analytics-and-bi-tools/connect-with-tableau/connect-with-tableau-prep.md) | | |
Refer to [Integrate with SingleStore Helios](https://docs.singlestore.com/cloud/load-data/integrate-with-singlestore-helios.md) for more supported tools.
## Supported IDEs
SingleStore supports the following IDEs:
* [Connect with JetBrains DataGrip](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-jetbrains-datagrip.md)
* [Connect with Visual Studio Code](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-visual-studio-code.md)
## Other Connection Methods
You can also connect to your SingleStore Helios deployments via the following:
* [SingleStore Kai](https://docs.singlestore.com/cloud/reference/singlestore-kai.md)
## Private Service and Networks
To configure private connections using AWS PrivateLink, Azure Private Link, and Google Private Service Connect, refer to [Connect with Private Services and Networks](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections.md).
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
## In this section
* [Client and Driver Downloads](https://docs.singlestore.com/cloud/connect-to-singlestore/client-and-driver-downloads.md)
* [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md)
* [Connect with DBeaver](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-dbeaver.md)
* [Connect with DbVisualizer](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-dbvisualizer.md)
* [Connect with Hasura](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-hasura.md)
* [Connect with JetBrains DataGrip](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-jetbrains-datagrip.md)
* [Connect with MySQL](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql.md)
* [Connect with SQL Developer](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sql-developer.md)
* [Connect with the SingleStore Client](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-the-singlestore-client.md)
* [Connect with the SQL Editor](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-the-sql-editor.md)
* [Connect with Sequel Pro](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sequel-pro.md)
* [Connect with SQL Workbench](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sql-workbench.md)
* [Connect with Visual Studio Code](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-visual-studio-code.md)
* [Connect with Data API](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-data-api.md)
* [Connect with Private Services and Networks](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections.md)
* [Connect to Your Cluster - Related Topics](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-to-your-cluster-related-topics.md)
***
Modified at: June 15, 2026
Source: [/cloud/connect-to-singlestore/](https://docs.singlestore.com/cloud/connect-to-singlestore/)
(An index of the documentation is available at /llms.txt)
---
# Client and Driver Downloads
SingleStore recommends using the following drivers, connectors, and clients.
## Language Database Clients/Drivers
| Driver Connector | Reference |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Go | [GoSingleStoreDriver](https://github.com/singlestore-labs/go-singlestore-driver) |
| Java/JDBC | [SingleStoreJDBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md) |
| ODBC | [SingleStoreODBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc/the-singlestore-odbc-driver.md) |
| .NET and .NET Core | [SingleStoreConnector for .NET and .NET Core](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core.md) |
| Node.js | [SingleStoreNode.js Driver](https://github.com/singlestore-labs/singlestore-nodejs) |
| Python | [SingleStorePython Client](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-using-the-singlestore-python-client.md) |
| R2DBC | [SingleStoreR2DBC Connector](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-r-2-dbc.md) |
Refer to [Connect with Application Development Tools](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools.md) for more supported drivers/languages, including third-party drivers and connectors.
## ORMs and Application Frameworks
| Framework | Reference |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Entity Framework Core | [SingleStoreEntity Framework Core Provider](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core/connect-using-entity-framework-core.md) |
| Django | [Django Connector forSingleStore](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-with-django.md) |
| Hasura | [HasuraSingleStoreData Connector](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-hasura.md) |
| Hibernate | [HibernateSingleStoreDialect](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/hibernate-singlestore-dialect.md) |
Refer to [Connect with Application Development Tools](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools.md) for more supported ORMs and application frameworks.
## In this section
* [Client Version Support Policy](https://docs.singlestore.com/cloud/connect-to-singlestore/client-and-driver-downloads/client-version-support-policy.md)
***
Modified at: April 20, 2026
Source: [/cloud/connect-to-singlestore/client-and-driver-downloads/](https://docs.singlestore.com/cloud/connect-to-singlestore/client-and-driver-downloads/)
(An index of the documentation is available at /llms.txt)
---
# Client Version Support Policy
SingleStore is MySQL compatible and provides native software (drivers, connectors, etc.) which may provide specific enhancements to SingleStore's performance or features. The native software must be installed on the system to leverage these optimizations.
SingleStore regularly releases new versions to address bugs and introduce new features. SingleStore recommends using the latest version of SingleStore drivers and connectors.
SingleStore maintains a driver and connector version support policy with the following guidelines:
* SingleStore generally supports each driver and connector release for at least two years, except when more recent releases provide critical fixes for security or performance issues. SingleStore may not support connectivity with versions older than this.
* SingleStore recommends using versions released within the scope of SingleStore's support policy. SingleStore does not distribute versions that are no longer supported.
* Latest driver and connector releases provide performance enhancements, new features, and bug fixes. They are not retroactively made available in the older versions.
* For critical fixes, SingleStore may require updating the driver or connector to the latest version or a version higher than the oldest supported version.
This policy does not apply to drivers and connectors provided by third-party companies outside of SingleStore's control. Contact the respective third-party provider for their latest support policies.
***
Modified at: July 29, 2024
Source: [/cloud/connect-to-singlestore/client-and-driver-downloads/client-version-support-policy/](https://docs.singlestore.com/cloud/connect-to-singlestore/client-and-driver-downloads/client-version-support-policy/)
(An index of the documentation is available at /llms.txt)
---
# Connect to Your Cluster - Related Topics
* [Create a Database](https://docs.singlestore.com/cloud/create-a-database.md)
* [Load Data](https://docs.singlestore.com/cloud/load-data.md)
* [Query Data](https://docs.singlestore.com/cloud/query-data.md)
***
Modified at: February 6, 2025
Source: [/cloud/connect-to-singlestore/connect-to-your-cluster-related-topics/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-to-your-cluster-related-topics/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Data API
SingleStore provides the Data API to execute SQL statements against your database over an HTTP connection. The Data API can be used to integrate SingleStore with serverless architecture, develop custom applications, and build seamless integrations with applications.
SingleStore's Data API is authenticated to the server using the HTTP Basic and Bearer Authentication standards. To authenticate using JWTs, use the Bearer authentication standard. The Data API uses standard HTTP methods and response codes and supports URI versioning. It also uses JSON-encoded responses with support for conventional data type conversions. The Data API is accessible via a built-in HTTP server.
The Data API supports all SQL statements that can be run in a direct database connection with SingleStore Helios.
To learn more about SingleStore's Data API, refer to the following topics.
* [Data API](https://docs.singlestore.com/cloud/reference/data-api.md)
* [Data API Authentication](https://docs.singlestore.com/cloud/reference/data-api/data-api-authentication.md)
* [Access the Data API](https://docs.singlestore.com/cloud/reference/data-api/access-the-data-api.md)
* [Enable the Data API](https://docs.singlestore.com/cloud/reference/data-api/enable-the-data-api.md)
* [Data API Data Type Conversion](https://docs.singlestore.com/cloud/reference/data-api/data-api-data-type-conversion.md)
* [Data API Error Handling](https://docs.singlestore.com/cloud/reference/data-api/data-api-error-handling.md)
* [Data API Endpoint Reference](https://docs.singlestore.com/cloud/reference/data-api/data-api-endpoint-reference.md)
***
Modified at: October 18, 2024
Source: [/cloud/connect-to-singlestore/connect-with-data-api/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-data-api/)
(An index of the documentation is available at /llms.txt)
---
# Connect with DBeaver
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
You can manage your SingleStore Helios databases with [DBeaver](https://dbeaver.io/) using the SingleStore JDBC driver.
## Prerequisites
* [The SingleStore JDBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md): Download the latest version of the driver from [GitHub](https://github.com/memsql/S2-JDBC-Connector/releases/latest).
## Connect with SingleStore Helios from DBeaver
To connect to your cluster from DBeaver,
1. In DBeaver, select **Database > Driver Manager**.
2. On the **Driver Manager** dialog, select **MariaDB > Copy**. The **Create New Driver** dialog opens.
3. In the **Create new driver** dialog, on the **Settings** tab, enter the following details:
* **Driver Name**: Enter **SingleStore**.
* **Driver Type**: From the list, select **MySQL**.
* **Class Name**: Specify the Class Name for the SingleStore JDBC driver: `com.singlestore.jdbc.Driver`.
* **URL Template**: Enter the following template:
`jdbc:singlestore://{host}[:{port}]/[{database}]`.
* **Default Port**: The default is `3306`.

4. On the **Libraries** tab,
1. Remove the existing MariaDB dependencies.
2. Select **Add file**. Select the SingleStore JDBC driver `.jar` file downloaded earlier, and select **Open**.
Alternatively, you can select **Add Artifact**, and then add the following dependency for the SingleStore JDBC driver under **Dependency Declaration**.
```xml
com.singlestore
singlestore-jdbc-client
1.1.9
```
Update the version in the dependency declaration with the latest version.
5. Select **OK**. The SingleStore driver is now configured in DBeaver.
6. In DBeaver, select **New Database Connection > SingleStore**.
7. On the **Connect to a database** dialog, enter the connection configuration of your SingleStore Helios cluster.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
8. Select **Test Connection** to test your connection.
The connection is now configured, and you can connect to your SingleStore databases from DBeaver.
***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-dbeaver/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-dbeaver/)
(An index of the documentation is available at /llms.txt)
---
# Connect with DbVisualizer
You can manage your SingleStore database using [DbVisualizer](https://www.dbvis.com/database/singlestore/).
## Prerequisites
* [The SingleStore JDBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md) (You may also install the SingleStore JDBC driver from DbVisualizer, select **Tools > Driver Manager**. Find the **SingleStore** driver from the list, and install it.)
## Connect with DbVisualizer
You need to setup a **Database Connection** in DbVisualizer to access your SingleStore database.
1. In DbVisualiser, select **Database > Create Database Connection**.
2. From the **Driver Name** list, select **SingleStore**.
3. In the **SingleStore** tab, enter the following details in the corresponding fields:
* `Database Server`: the endpoint of the SingleStore cluster
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* `Database Port`: the port used by the SingleStore Helios cluster (default: `3306`)
* `Database`: the name of the SingleStore database
* `Database Userid`: ID or name of the SingleStore user
* `Database Password`: password for the SingleStore user

4. Select the **Connect** button. You may also select **Ping Server** to verify the connectivity between DbVisualizer and SingleStore.
You can now explore your SingleStore databases using DbVisualizer.
***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-dbvisualizer/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-dbvisualizer/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Hasura
The Hasura SingleStore Data Connector ("the connector") connects your SingleStore database to Hasura Data Delivery Network (DDN) and enables you to query and update your SingleStore data via a GraphQL API. Once the connector is initialized, it automatically deploys a GraphQL API on top of your SingleStore data.
The Hasura SingleStore Data Connector is built using the [Native Data Connector SDK for TypeScript](https://github.com/hasura/ndc-sdk-typescript), and it implements Hasura's [Native Data Connectors](https://github.com/hasura/ndc-spec) specification.
## Prerequisites
* A [Hasura Cloud](https://console.hasura.io/) account.
* Install the [DDN CLI](https://hasura.io/docs/3.0/cli/installation) and [Docker](https://docs.docker.com/engine/install/).
* Create a [supergraph](https://hasura.io/docs/3.0/getting-started/init-supergraph).
* Create a [subgraph](https://hasura.io/docs/3.0/getting-started/init-subgraph).
* An active SingleStore Helios deployment.
## Connect to SingleStore
To connect to your SingleStore deployment using the connector:
1. Set the context for an existing subgraph.
2. Initialize the connector.
```shell
ddn connector init -i
```
3. Specify the connection configuration for your SingleStore deployment using the following environment variables:
| Variable Name | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SINGLESTORE_HOST` | Hostname or IP address of yourSingleStore Heliosdeployment.Refer to[SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md)to determine the endpoint (`host:port`) of your deployment. |
| `SINGLESTORE_PORT` | Port of yourSingleStore Heliosdeployment.Default is`3306`. |
| `SINGLESTORE_USER` | Name of theSingleStoredatabase user with which to access the database. |
| `SINGLESTORE_PASSWORD` | Password for theSingleStoredatabase user |
| `SINGLESTORE_DATABASE` | Name of theSingleStoredatabase to connect with. |
Refer to the [Hasura SingleStore Data Connector](https://github.com/singlestore-labs/singlestore-hasura-connector?tab=readme-ov-file#using-the-singlestore-connector) GitHub repository for information on additional configuration options and connection pool options.
4. Once the connector is initialized, [introspect the source database](https://hasura.io/docs/3.0/cli/commands/ddn_connector_introspect/) to update the configuration.
5. Add your [models](https://hasura.io/docs/3.0/cli/commands/ddn_model_add/), [commands](https://hasura.io/docs/3.0/cli/commands/ddn_command_add/), and [relationships](https://hasura.io/docs/3.0/cli/commands/ddn_relationship_add/).
6. Create a new [build](https://hasura.io/docs/3.0/cli/commands/ddn_supergraph_build_local/), and [run](https://hasura.io/docs/3.0/cli/commands/ddn_run/) the scripts using the connector.
The connector is now configured and ready.
## Supported Features
| Feature | Supported |
| --------------------------------- | --------- |
| Native queries and logical models | |
| Simple object query | ✔ |
| Filter or search | ✔ |
| Simple aggregation | ✔ |
| Sort | ✔ |
| Paginate | ✔ |
| Table relationships | ✔ |
| Views | ✔ |
| Distinct | ✔ |
| Remote relationships | ✔ |
| Mutations | |
## Limitations
SingleStore does not support foreign keys. Therefore, relationships between tables must be manually defined by appending the relationship information to the `.hml` files. Refer to [Relationships](https://hasura.io/docs/3.0/supergraph-modeling/relationships/) for more information.
## References
* [SingleStore Data Connector](https://hasura.io/connectors/singlestore)
* [Hasura DDN Documentation](https://hasura.io/docs/)
***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-hasura/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-hasura/)
(An index of the documentation is available at /llms.txt)
---
# Connect with JetBrains DataGrip
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
Use [the SingleStore JDBC driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md) to connect to your SingleStore databases from the JetBrains DataGrip IDE. DataGrip natively supports the SingleStore JDBC driver; select SingleStore from the list of supported drivers and then configure SingleStore as a data source.
## Prerequisites
* [Install](https://www.jetbrains.com/help/datagrip/installation-guide.html) JetBrains DataGrip.
* [Download](https://github.com/memsql/S2-JDBC-Connector/releases/latest) the latest version of the SingleStore JDBC Driver (`singlestore-jdbc-client-.jar`).
* An active SingleStore Helios deployment.
## Configure the Connection to SingleStore
To connect to SingleStore from JetBrains DataGrip:
1. Open JetBrains DataGrip, and then select **+** (icon) **> Driver**. Alternatively, select **File > Data Sources > Drivers** (tab).
2. On the **Data Sources and Drivers** dialog, select **SingleStore**.
3. Under **Driver Files**, select **+** (icon) **> Custom JARs**.
4. Select and upload the downloaded SingleStore JDBC driver `.jar` file.
5. Select **Create Data Source**.
6. On the SingleStore data source page, enter the connection configuration of your SingleStore deployment:
* **Host**: Hostname or IP address of the SingleStore deployment.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* **Port**: Default is `3306`.
* **User**: Username of the SingleStore database user.
* **Password**: Password for the SingleStore database user.
* **Database**: Enter the name of the SingleStore database to connect with.
7. Select **Test Connection** to test connectivity to the SingleStore database.
8. Upon successfully connecting to SingleStore, select **OK** to save the configuration.
The SingleStore connection is configured and ready.
***
Modified at: November 7, 2025
Source: [/cloud/connect-to-singlestore/connect-with-jetbrains-datagrip/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-jetbrains-datagrip/)
(An index of the documentation is available at /llms.txt)
---
# Connect with MySQL
SingleStore is wire-compatible with MySQL so you can connect using most other MySQL compatible tools/languages.
You’ll need to specify the `host`, `port`, `user`, `password`, and possibly the `database`.
## In this section
* [Connect with MySQL Client](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client.md)
* [Connect with Any MySQL Compatible Tool to SingleStore Helios](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-any-mysql-compatible-tool-to-singlestore-helios.md)
* [Connect with MySQL Workbench](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-workbench.md)
***
Modified at: July 27, 2021
Source: [/cloud/connect-to-singlestore/connect-with-mysql/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Any MySQL Compatible Tool to SingleStore Helios
In general, if the client you are using to connect supports the MySQL protocol, you can use it to connect to SingleStore Helios. For example, if you connect Wordpress to MySQL, you can probably use most of the same configuration to connect to SingleStore Helios.
Ensure that the connection details are correct. Refer to [Common Issues](https://docs.singlestore.com/#section-idm4564738306016032548222614039.md) to troubleshoot some common connectivity issues.
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
## Connection Details
You’ll need to specify the `host`, `port`, `user`, `password`, and possibly the `database`.
* `host`: IP address or hostname of your cluster.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* `port`: Port of the SingleStore deployment. Default is `3306`.
* `user`: Username of the SingleStore database user. For example, admin.
## Common Issues
Some of the issues you may encounter, and how to solve them:
* Wrong Authentication Adapter: MySQL v8 authentication has some issues in SingleStore Helios and SingleStore recommends that you use a newer version. Sometimes you can work around this by specifying `--default-auth=mysql_native_password` in the connection details.
* Binary Protocol: Use the text protocol when connecting to SingleStore Helios. You may need to disable server-side prepared statements (`useServerPrepStmts=false`).
* Connection Failed: Check the firewall configuration and perform other general connectivity troubleshooting.
***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-mysql/connect-with-any-mysql-compatible-tool-to-singlestore-helios/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-any-mysql-compatible-tool-to-singlestore-helios/)
(An index of the documentation is available at /llms.txt)
---
# Connect with MySQL Client
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
SingleStore is wire-compliant with MySQL meaning connecting to SingleStore is as easy as connecting to a MySQL database. You may need the `-u ,` `-h `, and `-P ` flags to ensure you are connecting to SingleStore properly. For example:
```shell
mysql -u admin -h svc-xxxx-ddl.aws-oregon-1.svc.singlestore.com -P 3306 --default-auth=mysql_native_password -p
```
where,
* `-u`: Specifies the name of the SingleStore database user.
* `-h`: Specifies the IP address or hostname of the SingleStore deployment.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* `-P`: Specifies the port to connect to. Default: `3306`.
* `--default-auth=mysql_native_password`: (Optional) For proper authentication.
You may also use the `--prompt` flag to change the prompt in the interactive session, simply to help distinguish SingleStore from MySQL:
```shell
mysql -u admin -h svc-[...].svc.singlestore.com -P 3306 --default-auth=mysql_native_password -p --prompt="singlestore> "
```
The output when you connect should look similar to this:
```sql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.5.8 MemSQL source distribution (compatible; MySQL Enterprise & MySQL Commercial)
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
singlestore>
```
These commands show more information about the connection and the server:
Note that `SHOW STATUS LIKE '%License%';` provides additional license information.
```sql
status
```
```output
--------------
mysql Ver 8.0.23 for osx10.15 on x86_64 (Homebrew)
Connection id: 15507
Current database:
Current user: admin@
SSL: Cipher in use is AES256-SHA
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.5.58 MemSQL source distribution (compatible; MySQL Enterprise & MySQL Commercial)
Protocol version: 10
Connection: svc-9be5e8a1-8a5f-4aa7-b75d-a395570828f2-ddl.aws-oregon-1.svc.singlestore.com via TCP/IP
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
Binary data as: Hexadecimal
--------------
```
```sql
SHOW DATABASES;
```
```output
+--------------------+
| Database |
+--------------------+
| cluster |
| information_schema |
| memsql |
| test |
+--------------------+
4 rows in set (0.03 sec)
```
> **❗ Important**: The `@@version` and `@@version_comment` global variables are for compatibility with MySQL clients, which expect certain minimum version numbers and strings to be present. To check the real version of SingleStore Helios you are running, use the `@@memsql_version` variables instead. To check the license you are running, see the `license_key` and `license_type` status codes.
## In this section
* [MySQL Command-Line Considerations](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/mysql-command-line-considerations.md)
* [Connect to SingleStore Helios using TLS/SSL](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/connect-to-singlestore-helios-using-tls-ssl.md)
* [MariaDB Command-line Client from MariaDB Server Version 10.3.12 (GPLv2)](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/mariadb-command-line-client-from-mariadb-server-version-10-3-12-gplv-2.md)
***
Modified at: July 23, 2026
Source: [/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/)
(An index of the documentation is available at /llms.txt)
---
# Connect with MySQL Workbench
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
To connect to SingleStore Helios from MySQL Workbench:
1. Open MySQL Workbench and create a new MySQL connection.
2. In the **Setup New Connection** dialog, enter the following details:
* **Connection Name**: A name for your connection, for example **SingleStoreDB**.
* **Hostname**: The IP address or hostname of your SingleStore Helios cluster.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* **Username**: The SingleStore database username. Enter `admin`.
* **Password**: The password for the SingleStore database user.
> **📝 Note**: For proper authentication, you may need to specify `defaultAuth=mysql_native_password` in the **Others** field under the **Advanced** tab.
* **Port**: Default is `3306`.
3. Select **Test Connection** to test the connection. Select **OK** to save the connection.

***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-workbench/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-workbench/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Sequel Pro
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
To connect to SingleStore Helios from Sequel Pro:
1. Open Sequel Pro and configure a new connection using **Quick Connect**.
2. On the **Quick Connect** window, enter the following details:
* **Name**: A name for your connection, for example **SingleStoreDB**.
* **Host **: The IP address or hostname of your SingleStore Helios cluster.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* **Username**: The SingleStore database username. Enter `admin`.
* **Password**: The password for the SingleStore database user.
* **Database**: The name of the SingleStore database.
* **Port**: Default is `3306`.
3. Select **Test Connection** to test the connection. Select **Connect** to connect to your SingleStore Helios database.

***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-sequel-pro/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sequel-pro/)
(An index of the documentation is available at /llms.txt)
---
# Connect with SQL Developer
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
To connect to SingleStore Helios from SQL Developer:
1. Download a MySQL connector for Java, for example, [MySQL Connector Java 8.0.24](https://packages.atlassian.com/maven-external/mysql/mysql-connector-java/8.0.24/mysql-connector-java-8.0.24.jar).
2. Open SQL Developer, and add a new third-party connector. Select **Preferences > Database > Third Party Drivers**.
3. Select **Add Entry**, and then add the **.jar** file downloaded earlier.
4. Create a new connection, select **Connections > New Connection**.
5. In the **New / Select Database Connection** dialog, select or enter the following information:
* **Name**: A name for your connection, for example **SingleStoreDB**.
* **Database Type**: From the list, select **MySQL**.
* **Hostname**: The IP address or hostname of your SingleStore Helios cluster.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* **Username**: The SingleStore database username. Enter `admin`.
* **Password**: The password for the SingleStore database user.
* **Port**: Default is `3306`.
6. Select **Connect**.

***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-sql-developer/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sql-developer/)
(An index of the documentation is available at /llms.txt)
---
# Connect with SQL Workbench
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
To connect to SingleStore Helios from SQL Workbench:
1. Open SQL Workbench, and then open the **Connectors** window.
**Note**: Some users have reported issues connecting with SQL Workbench v8 and have recommended using v6 instead.
2. In the **Select Connection Profile** window, select or enter the following information:
* A name for your connection, for example **test-connection**.
* **Driver**: From the list, select **MySQL (com.mysql.jdbc.Driver)**. This Driver requires the [MySQL Java connector](http://dev.mysql.com/downloads/connector/j/).
* **URL**: Enter the connection string in the `jdbc:mysql://:` format.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* **Username**: The SingleStore database username. Enter `admin`.
* **Password**: The password for the SingleStore database user.
3. Complete the other fields as required.

4. Select **OK**. The SQL Workbench window opens. You can issue queries in the top pane and view results in the bottom pane.


***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-sql-workbench/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-sql-workbench/)
(An index of the documentation is available at /llms.txt)
---
# Connect with the SingleStore Client
> **📝 Note**: When using the SingleStore client, or a third-party SQL client, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
The SingleStore client, similar to the MySQL client, is a lightweight Linux application that allows you to connect to SingleStore Helios and run SQL queries directly from a terminal session.
Use `singlestore --help` to for help and to view additional connection options.
## Install SingleStore Client
* *Red Hat Distribution*
## Online InstallationFor online installations where the target host can access the SingleStore YUM repository, perform the following steps.1) Add the SingleStore repository to your repository list.
```shell
sudo yum-config-manager --add-repo https://release.memsql.com/production/rpm/x86_64/repodata/memsql.repo
```
2) Verify that the SingleStore repo information is listed under `repolist`.
```shell
sudo yum repolist
```
3) Verify that the `which` package installed. This is used during the install process to identify the correct package type for your installation.
```shell
rpm -q which
```
If `which` is not installed, it must be installed before proceeding.
```shell
sudo yum install -y which
```
4) Install the SingleStore client.
```shell
sudo yum install -y singlestore-client
```## Offline InstallationDownload the SingleStore client package onto a host that can access your SingleStore Helios cluster.Install the SingleStore client.```shell
sudo rpm -ivh /tmp/singlestore-client--.x86_64.rpm
```
* *Debian Distribution*
## Online InstallationFor online installations where the target host can access the SingleStore APT repository, perform the following steps.1) SingleStore packages are signed to ensure integrity, so the GPG key needs to be added to this host. When done, verify that the SingleStore signing key has been added using `apt-key list`.
```shell
wget -O - 'https://release.memsql.com/release-aug2018.gpg' 2>/dev/null | sudo apt-key add - && apt-key list
```
**Without using `apt-key`**:
```shell
wget -q -O - 'https://release.memsql.com/release-aug2018.gpg' | sudo tee /etc/apt/trusted.gpg.d/memsql.asc 1>/dev/null
```
2) Verify that `apt-transport-https` is installed.
```shell
apt-cache policy apt-transport-https
```
If `apt-transport-https` is not installed, it must be installed before proceeding.
```shell
user-shell sudo apt -y install apt-transport-https
```
3) Add the SingleStore repository to retrieve its packages.
```shell
echo "deb [arch=amd64] https://release.memsql.com/production/debian memsql main" | sudo tee /etc/apt/sources.list.d/memsql.list
```
4) Install the SingleStore client.
```shell
sudo apt update && sudo apt -y install singlestore-client
```## Offline InstallationDownload the SingleStore client package onto a host that can access your SingleStore Helios cluster.Install the SingleStore client.```shell
sudo dpkg -i /tmp/singlestore-client___amd64.deb
```
* *Tarball*
## Download the SingleStore ClientDownload the SingleStore client tarball file onto a host that can access your SingleStore Helios cluster.## Transfer the SingleStore ClientTransfer the SingleStore client tarball file into a dedicated `singlestore` directory on the target host (typically the main deployment host when deploying SingleStore) that has been configured so that non-`sudo` users can access it, such as `/opt/singlestore`.## Unpack the SingleStore ClientUnpack the SingleStore client into a directory of your choice, such as or `/opt/singlestore`.```shell
tar xzvf singlestore-client--.x86_64.tar.gz
```Using symbolic links (or "symlinks") can make using and upgrading the SingleStore client easier. Performing the following steps will allow the `singlestore` command to be run from anywhere on the filesystem, even after an upgrade by updating the symlink.1) Navigate to the directory that contains the unpacked SingleStore client tarball file and create a `singlestore-client` symlink that points to the SingleStore client directory.
```shell
ln -s singlestore-client-- singlestore-client
```
2) Verify that the symlink has been created.
```shell
ls -l
```
```output
singlestore-client -> singlestore-client-1.0.6-c3803db03b
```
3) Update the `PATH` environment variable with the path to the new `singlestore-client` directory. This path can also be added to your shell startup file so you won't have to run this command each time you log in.
```shell
export PATH=/opt/singlestore/singlestore-client:$PATH
```
4) You may now run the `singlestore` command from anywhere on the filesystem.
```shell
singlestore
```
## Connect to Your SingleStore Helios Cluster
The `singlestore_bundle.pem` file is required to configure an SSL connection. Once downloaded, this file can be used to connect to all of your SingleStore Helios clusters via SSL.
1. Download the `singlestore_bundle.pem` file.
1. Log into the [Cloud Portal](https://portal.singlestore.com).
2. Navigate to **Clusters**.
3. Select **Connect > CLI Client** in the **Actions** column for your cluster.
4. Under **TLS/SSL Certificate**, select **Download**. This will download the `singlestore_bundle.pem` file to your computer.
2. To confirm that the connection is using SSL, run the following command to check the connection status.
```
singlestore -h -P -u -p --ssl-ca=singlestore_bundle.pem \
-e status
```
where:
* `client-endpoint` is the SingleStore Helios endpoint for your cluster
* `port` is the port number to connect on (typically `3306`)
* `database-user` is either the [database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to connect as, or the default `admin` user (which was created with the cluster)
* `database-user-password` is the database user password.
You may receive the following message when including the database user password on the command line:
```
singlestore-client: [Warning] Using a password on the command line interface can be insecure.
```
To prevent this message, leave the database user password blank and you will be prompted for the password.
From the output, review the `SSL` line for the cipher in use.
```
--------------
/usr/lib/singlestore-client/singlestore-client Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using EditLine wrapper
Connection id: 17323
Current database:
Current user: admin@
SSL: Cipher in use is AES128-GCM-SHA256
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.7.32 MemSQL source distribution (compatible; MySQL Enterprise & MySQL Commercial)
Protocol version: 10
Connection: via TCP/IP
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
--------------
```
3. Run the following command to connect to your SingleStore Helios cluster.
Note that this is the same command and parameters from Step 2, only without the `-e status` flag.
```shell
singlestore -h -P -u -p --ssl-ca=singlestore_bundle.pem
```
When connected, the following (or similar) output will be displayed.
```
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10141
Server version: 5.7.32 SingleStoreDB source distribution (compatible; MySQL Enterprise & MySQL Commercial)
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
singlestore>
```
## Upgrade SingleStore Client
* *Red Hat Distribution*
To upgrade the SingleStore client, use the same steps for upgrading any RPM package.**Online**```shell
sudo yum update -y singlestore-client
```**Offline**1) Download the SingleStore client package.
2) Upgrade the SingleStore client.
```shell
sudo rpm -Uvh /tmp/singlestore-client--.x86_64.rpm
```
* *Debian Distribution*
To upgrade the SingleStore client, use the sane steps for upgrading any Debian package.**Online**1) SingleStore packages are signed to ensure integrity, so the GPG key needs to be added to this host. When done, verify that the SingleStore signing key has been added using `apt-key list`.
```shell
wget -O - 'https://release.memsql.com/release-aug2018.gpg' 2>/dev/null | sudo apt-key add - && apt-key list
```
**Without using `apt-key`**:
```shell
wget -q -O - 'https://release.memsql.com/release-aug2018.gpg' | sudo tee /etc/apt/trusted.gpg.d/memsql.asc 1>/dev/null
```
2) Upgrade the SingleStore client.
```shell
sudo apt update && sudo apt install -y singlestore-client
```**Offline**1) Download the SingleStore client package.
2) Upgrade the SingleStore client.
```shell
sudo dpkg -i /tmp/singlestore-client___amd64.deb
```
* *Tarball*
To upgrade the SingleStore client, you must manually replace the existing SingleStore client with a new one.1) Obtain the latest version of the SingleStore client.
```shell
curl https://release.memsql.com/production/index/memsqlclient/latest.json
```
The JSON returned contains a relative path to the `singlestore-client-tar` file in the following format.
```shell
"Path": "production/tar/x86_64/singlestore-client--.x86_64.tar.gz"
```
2) Use `wget` to download the file by copying, pasting, and appending the path to . For example:
```shell
wget https://release.memsql.com/production/tar/x86_64/singlestore-client--.x86_64.tar.gz
```
As an alternative, you may download the latest version of the SingleStore client tarball file using the following link.
3) Place this SingleStore client tarball file on your device where the existing SingleStore client has been installed.
4) Unpack the SingleStore client tarball file. This directory will now contain two versions of the SingleStore client: the existing version, and the new version.
```shell
tar xzvf singlestore-client--.x86_64.tar.gz
```Using symbolic links (or "symlinks") can make using and upgrading the SingleStore client easier. Performing the following steps will allow the `singlestore` command to be run from anywhere on the filesystem, even after an upgrade.1) Check if a `singlestore-client` symlink already exists within the current directory.
```shell
ls -l
```
If so, remove the existing `singlestore-client` symlink.
```shell
rm singlestore-client
```
2) Create a `singlestore-client` symlink by pointing it to the new version of the SingleStore client directory.
```shell
ln -s singlestore-client-- singlestore-client
```
3) Verify that the symlink has been created.
```shell
ls -l
```
```output
singlestore-client -> singlestore-client-1.0.6-c3803db03b
```
4) Update the `PATH` environment variable with the path to the new `singlestore-client` directory. This path can also be added to your shell startup file so you won't have to run this command each time you log in.
```shell
export PATH=/opt/singlestore/singlestore-client:$PATH
```
5) You may now run the `singlestore` command from anywhere on the filesystem.
```shell
singlestore
```The upgrade is now complete.Should you encounter any issues with the new SingleStore client, you can simply point the `singlestore-client` symlink back to the previous version.After validating that the new version of the SingleStore client is working as expected, you may remove the previous version.```shell
rm -rf singlestore-client--
```
## Uninstall SingleStore Client
* *Red Hat Distribution*
You may either uninstall the SingleStore client individually or remove it while uninstalling SingleStore Helios. If you want to completely uninstall SingleStore Helios and its related Tools packages, first [uninstall SingleStore Helios](https://docs.singlestore.com/cloud/user-and-cluster-administration/#uninstall-singlestore-helios.md) from your nodes by using the `sdb-deploy uninstall` command. This will remove the `singlestoredb-server` package for that version of SingleStore Helios. To uninstall all versions of SingleStore Helios, include the `--all-versions` flag.> **❗ Important**: The `remove` command and `-e` flag will only remove the binaries in the package and not remove any configuration files.Run the following command to uninstall the SingleStore client.**Online**```shell
sudo yum remove singlestore-client
```**Offline**```shell
sudo rpm -e singlestore-client
```
* *Debian Distribution*
You may either uninstall the SingleStore client individually or remove it while uninstalling SingleStore Helios. If you want to completely uninstall SingleStore Helios and its related Tools packages, first [uninstall SingleStore Helios](https://docs.singlestore.com/cloud/user-and-cluster-administration/#uninstall-singlestore-helios-2.md) from your nodes by using the `sdb-deploy uninstall` command. This will remove the `singlestoredb-server` package for that version of SingleStore Helios. To uninstall all versions of SingleStore Helios, include the `--all-versions` flag).Run the following command to uninstall the SingleStore client.> **❗ Important**: The `purge` command and `-P` flag will remove the binaries in the package as well as any configuration files.To keep the configuration files, use the `remove` command or `-r` flag instead.**Online**```shell
sudo apt purge singlestore-client
```**Offline**```shell
sudo dpkg -P /tmp/singlestore-client___amd64.deb
```
* *Tarball*
Run the following commands to uninstall the SingleStore client.1) Change to the directory where the SingleStore client has been installed.
```shell
cd /opt/singlestore
```
2) Remove the SingleStore client directory (or directories, if more than one version has been installed).
```shell
rm -rf singlestore-client--
```
***
Modified at: May 12, 2026
Source: [/cloud/connect-to-singlestore/connect-with-the-singlestore-client/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-the-singlestore-client/)
(An index of the documentation is available at /llms.txt)
---
# Connect with the SQL Editor
The SQL Editor in the [Cloud Portal](https://portal.singlestore.com) allows you to easily run queries against your cluster.
## Multi-tab SQL Editor
The multi-tab SQL Editor allows you to open and work with multiple SQL files in parallel within a single browser session. You can load, edit, and run queries against different clusters and databases, and save individual SQL files for future use.
## Create and Open a New SQL File
**Note**: Ensure that the correct cluster and database are selected at the top of the file, and all queries are run against the intended database.
1. On the [Cloud Portal](https://portal.singlestore.com/), select **Editor** > **Open SQL Editor**.
2. Navigate to the **+ New **button on the right, and select **New SQL file**.
A new tab opens with an untitled SQL Editor (for example, Untitled-1.sql). Each additional untitled tab is automatically numbered incrementally (such as Untitled-2.sql, Untitled-3.sql, etc.).
## Save a SQL File
To save an untitled SQL file, select the **Save As** button on the top right. In the dialog, enter the filename and confirm its storage location.
**Note**: SQL files can only be saved in the **Personal** folder.
For further modifications, select **Save**, or you can rely on autosave. The editor autosaves content every 5 seconds, as indicated by the **Save** button changing to **Saved**.
If you try to close a file with unsaved changes, you will be prompted to save, discard, or cancel. Unsaved or untitled files are lost permanently when closed.
## Set a Row Limit for Results
To limit the number of rows in the query result:
1. Select the three dots icon in the top right corner of the editor.From the list, select **Settings**.
2. The Settings panel shows a **Limit results to** option.
3. Select a row limit: 300,1000, or 3000. The default is 300 rows.
Alternatively, you can set the row limit by running the following command in the SQL Editor:
```sql
SET SESSION SQL_SELECT_LIMIT = 5000;
```
This example sets the value to 5000.
## Troubleshooting
* If you experience connection errors when running queries, verify that your IP address is allowed in the cluster group's firewall settings.
* For additional assistance, contact [SingleStore Support](https://support.singlestore.com/).
***
Modified at: May 22, 2026
Source: [/cloud/connect-to-singlestore/connect-with-the-sql-editor/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-the-sql-editor/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Visual Studio Code
You can connect to your SingleStore Helios cluster from Visual Studio Code using the SQLTools SingleStore Driver (aka "SingleStore Driver for SQLTools") extension. This driver allows you to perform the following tasks:
* Connect to your SingleStore Helios cluster.
* Manage connections in the Database Explorer.
* Run SQL queries. You can also export query results in JSON and CSV formats.
* View tables, views, columns, functions, procedures, etc.
* Generate `INSERT` queries.
* Autocomplete SQL keywords, table and view names, column names, SingleStore built-in functions, etc.
Refer to [SingleStore Driver for SQLTools](https://marketplace.visualstudio.com/items?itemName=singlestore.sqltools-singlestore-driver) for more information.
## Install the SQLTools SingleStore Driver Extension
To install the SQLTools SingleStore Driver in Visual Studio Code, run the following command in the Visual Studio Code Quick Open (Cmd+p/Ctrl+p):
```vs code
ext install singlestore.sqltools-singlestore-driver
```
You can also install this extension in Visual Studio Code IDE from the **Extensions** tab.
## Connect with SingleStore Helios from Visual Studio Code
To connect to your cluster from Visual Studio Code, perform the following tasks:
1. In Visual Studio Code IDE, on the navigation pane, select **SQLTools**.
2. Under **Connections**, select **Add New Connection**.
3. On the **SQLTools Settings** tab, select the **SingleStore** database driver.
4. Under **Connection Settings**, enter the following details:
* **Connection name** (Required): Name for this connection.
* **Server Address** (Required): IP address or hostname of your SingleStore Helios cluster.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* **Port** (Required): Default is `3306`.
* **Username** (Required): Username for your SingleStore Helios cluster.
To test connectivity, select **TEST CONNECTION**.
5. Select **SAVE CONNECTION**.
6. Under **Review connection details**, select **CONNECT NOW**.
You can now explore your SingleStore databases in Visual Studio Code.
***
Modified at: September 26, 2025
Source: [/cloud/connect-to-singlestore/connect-with-visual-studio-code/](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-visual-studio-code/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Private Services and Networks
You can connect from a SingleStore Helios cluster to private services and networks. Private services/networks simplify networking and connectivity by allowing users to connect directly from a virtual/private network to SingleStore through VPC/private endpoints.
Use the [SingleStore Private Connections](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/singlestore-private-connections.md) feature to configure a private connection to AWS PrivateLink. Setting up a connection to Azure Private Link and Google Private Service Connect involves actions from both your and SingleStore's end. You may need to share the details related to your cluster and Azure/Google account with SingleStore support. To make the setup process seamless, acquire the required information before reaching out to SingleStore support. The list of information required is specified in the configuration process for the respective private service/network.
To successfully set up a private connection, you need to configure both the outbound and inbound connections. Additionally, SingleStore can only process the connection request when your cluster is in the `Active` state. If you need separate reader and writer endpoints for each cluster, specify this in the support ticket while configuring Azure/Google private service/networks. SingleStore recommends using a single endpoint as SingleStore internally manages (reader/writer) query forwarding to this endpoint.
SingleStore recommends having hands-on experience on using private services and networks. For more information, refer to the relevant documentation:
* [AWS PrivateLink](https://docs.aws.amazon.com/vpc/latest/privatelink/what-is-privatelink.html)
* [Azure Private Link](https://learn.microsoft.com/en-us/azure/private-link/private-link-overview)
* [Google Private Service Connect](https://cloud.google.com/vpc/docs/private-service-connect)
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
## SingleStore Private Connections
SingleStore Private Connections (SPC) allows you set up and configure connections to private services and networks through the [Cloud Portal](https://portal.singlestore.com/). This feature is only supported for SingleStore Helios clusters deployed using AWS, and it only supports connections to AWS PrivateLink. For more information, refer to [SingleStore Private Connections](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/singlestore-private-connections.md).
## Configure Private Connections
Configure both the outbound and inbound connections to connect to any of the following private services/networks:
## AWS PrivateLink
* [Connect to SingleStore Helios using AWS PrivateLink](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-using-aws-privatelink.md)
## Azure Private Link
You can connect multiple private links to a single cluster. Refer to [ExpressRoute](https://learn.microsoft.com/en-us/azure/architecture/reference-architectures/hybrid-networking/expressroute) for more information.
* [Configure Outbound Connection](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-out-from-singlestore-helios-clusters-to-private-networks-services-via-azure-private-link.md)
* [Configure Inbound Connection](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-azure-private-link.md)
## Google Private Service Connect
If you have more than one subnet/zone you want to connect via Private Service Connect to your cluster, you should select each of them while configuring the load balancer backend. For more information, refer to [Configure the load balancer](https://cloud.google.com/vpc/docs/configure-private-service-connect-controls#configure-the-load-balancer).
* [Configure Outbound Connection](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-out-from-singlestore-helios-clusters-to-private-networks-services-via-google-private-service-connect.md)
* [Configure Inbound Connection](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-google-private-service-connect.md)
## FAQs
* **Once a private connection is set up, for example AWS PrivateLink, does the data to be ingested have to go through AWS PrivateLink?**
No, this is simply a separate endpoint.
* **While using Kubernetes with Google Private Service Connect, suppose that each node pool creates 3 instance groups, 1 per zone. Should you select every group available in the backend step of the create a load balancer step?**
Yes, if you have more than a single subnet/zone and you want to connect via Google Private Service Connect to your cluster, you should select every available group.
* **Can I connect directly to a cluster via a private link (service/network)?**
No, you need a private service endpoint to connect to a cluster via a private link. You cannot directly access the endpoint of a cluster from private services and networks.
## In this section
* [SingleStore Private Connections](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/singlestore-private-connections.md)
* [Connect to SingleStore Helios using AWS PrivateLink](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-using-aws-privatelink.md)
* [Connect to SingleStore Helios Clusters from Private Networks/Services via Azure Private Link](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-azure-private-link.md)
* [Connect out from SingleStore Helios Clusters to Private Networks/Services via Azure Private Link](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-out-from-singlestore-helios-clusters-to-private-networks-services-via-azure-private-link.md)
* [Connect to MongoDB® using Azure Private Link](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-mongodb-using-azure-private-link.md)
* [Connect to SingleStore Helios Clusters from Private Networks/Services via Google Private Service Connect](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-google-private-service-connect.md)
* [Connect out from SingleStore Helios Clusters to Private Networks/Services via Google Private Service Connect](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-out-from-singlestore-helios-clusters-to-private-networks-services-via-google-private-service-connect.md)
***
Modified at: June 23, 2026
Source: [/cloud/connect-to-singlestore/private-connections/](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/)
(An index of the documentation is available at /llms.txt)
---
# Connect out from SingleStore Helios Clusters to Private Networks/Services via Azure Private Link
For outbound connections, create a private link service and send the **alias** to SingleStore.
To create outbound connections from SingleStore Helios to private services (like Kafka) via Azure Private Link, for tasks like ingesting data through pipelines, perform the following tasks:
1. Request the subscription ID from SingleStore.
2. Create a private link service.
3. Send the alias to SingleStore.
## Request the Subscription ID from SingleStore
Contact [SingleStore Support](https://support.singlestore.com) and request the subscription ID from SingleStore. You'll need to whitelist this subscription ID while creating your private link service (as explained below).
## Create a Private Link Service
1. On the [Azure portal](https://portal.azure.com/), select **Create a resource > Private Link > Create > Create private link service**.
2. On the **Basics** tab, enter or select the following information:
* **Subscription**: Your Azure subscription.
* **Resource group**: The resource group corresponding to your Azure subscription. It should have the same name as your Azure subscription name.
* **Name**: Name of your private endpoint service.
* **Region**: Select a region in which you want to create the private link service.
> **📝 Note**: Your cluster and private link service must be in the same region.
3. On the **Outbound settings** tab, select or enter the following information:
* **Load balancer**
* **Load balancer frontend IP address**
* **Source NAT subnet**
* Use defaults for other configuration settings
4. On the **Access security** tab, whitelist the subscription ID received from SingleStore.
5. On the **Review + create** tab, verify the configuration setting, and select **Create**.
Your private link service is created, and you are redirected to a new page.
6. Select **Go to resource group**, and then select your private link service.
7. Copy the **alias**.
## Send the Alias to SingleStore
Contact [SingleStore Support](https://support.singlestore.com) and send the alias of your private endpoint service. Provide the following information in the support ticket:
* Cluster ID. SingleStore can only process the connection request when your cluster is in the `Active` state.
* Region details
* The **alias** of your private endpoint service
* In the support ticket, specify that the request is for outbound connection
## References
* [Create a private link service](https://learn.microsoft.com/en-us/azure/private-link/create-private-link-service-portal)
***
Modified at: April 1, 2025
Source: [/cloud/connect-to-singlestore/private-connections/connect-out-from-singlestore-helios-clusters-to-private-networks-services-via-azure-private-link/](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-out-from-singlestore-helios-clusters-to-private-networks-services-via-azure-private-link/)
(An index of the documentation is available at /llms.txt)
---
# Connect out from SingleStore Helios Clusters to Private Networks/Services via Google Private Service Connect
For outbound connections, you'll send the service attachment to SingleStore. You'll also receive a project name from SingleStore so that you can whitelist the project while creating the service.
To create outbound connections from SingleStore Helios to private networks/services (not accessible from the Internet, like Kafka) for tasks like ingesting data via pipelines perform the following tasks:
1. Obtain a project name from SingleStore.
2. Create a Network Load Balancer (NLB).
3. Publish the Service.
4. Send the Service Attachment to SingleStore.
## Obtain a Project Name from SingleStore
Contact SingleStore Customer Support (see [Support FAQ](https://docs.singlestore.com/cloud/support/support-faq.md)) and obtain a project name for the service you are going to create. Provide the following information in the support ticket:
* Cluster ID. SingleStore can only process the connection request when your cluster is in the `Active` state.
* Region details
* Request a project name from SingleStore
* In the support ticket, specify that the request is for outbound connection
You'll need to whitelist this project name while creating the service later.
## Create a Network Load Balancer
1. In the GCP console, select **Networking > Networking Services > Load Balancing > Create load balancer**.
2. Under **TCP Load Balancing**, select **Start configuration**.
3. Under **Internet facing or internal only**, select **Only between my VMs** and **Single region only**.
4. Under **Backend type**, select **Backend Service**. Select **Continue**.
5. On the **New TCP load balancer** screen, enter a **Name** for the Network Load Balancer.
6. Select **Backend configuration**, enter the **Region** and **Network** information, and then add your service's **Instance group**.
> **📝 Note**: If you do not have an Instance group yet, but you do have a running service, select **GCP Console > Compute Engine > Instance groups > Create Instance Groups** to create an instance group. If you already have an instance, but do not have a group, you may want to create an *unmanaged* group to which you can add existing instances. See [Creating groups](https://cloud.google.com/compute/docs/instance-groups/creating-groups-of-unmanaged-instances#create_unmanaged_group) to create an unmanaged instance group.
7. Fill out the Backend and Frontend configurations and then click **Create**.
For more NLB configuration related information, see [Configuring Load Balancer](https://cloud.google.com/load-balancing/docs/internal/setting-up-internal#configure_the_load_balancer).
Once you have an NLB, you can test it. An easy test would be to use `curl` with the Network Load Balancer's IP and Port from within the VPC to verify that the connection is established.
```shell
$ curl :
```
## Publish the Service
When you publish a service, you create a service attachment. Send the Service attachment information to SingleStore. You will also need to whitelist the project that SingleStore sent you earlier.
1. In the GCP Console, select **Networking > Network Services > Private Service Connect > Published Services > Publish Service**.
2. Under **Load balancer** type, select **Internal TCP/UDP Load Balancer**.
3. Add the project name you received from SingleStore to the whitelist for your Service.
4. Enter the necessary details and create a subnet if needed. See [Publish a Service](https://cloud.google.com/vpc/docs/configure-private-service-connect-producer#publish-service) for more information. Do NOT enable **Use Proxy Protocol**.
5. Select **Add service**.
For more information, see [Publish Services using Private Service Connect](https://cloud.google.com/vpc/docs/configure-private-service-connect-producer).
## Send the Service Attachment to SingleStore
Contact [SingleStore Support](https://support.singlestore.com) and provide the Service Attachment. Follow these steps:
1. On the Google Cloud console, go to the **Private Service Connect** page.
2. On the **Published Service** tab, select the service you just created. Open the **Private Service Connect service details** screen.
3. Send the **Service attachment** information to [SingleStore Support](https://support.singlestore.com). Service attachment names usually have the following format: `projects//regions//serviceAttachments/`.
***
Modified at: April 1, 2025
Source: [/cloud/connect-to-singlestore/private-connections/connect-out-from-singlestore-helios-clusters-to-private-networks-services-via-google-private-service-connect/](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-out-from-singlestore-helios-clusters-to-private-networks-services-via-google-private-service-connect/)
(An index of the documentation is available at /llms.txt)
---
# Connect to MongoDB® using Azure Private Link
SingleStore supports connecting to a MongoDB® instance via Azure Private Link.
## Prerequisites
* Create a SingleStore Kai-enabled cluster. Refer to [Getting Started with SingleStore Kai](https://docs.singlestore.com/cloud/reference/singlestore-kai/getting-started-with-singlestore-kai.md) for related information.
* The cluster must be deployed in an Azure region.
## Configure the Connection
To connect to the MongoDB® instance using Azure Private Link:
1. Copy the **VPC Endpoint Service Name** from the SingleStore Helios Cloud Portal.
1. On the [Cloud Portal](https://portal.singlestore.com/), select **Clusters** in the left navigation pane.
2. Select the three dots under the **Actions** column for your cluster, and select **Access & Security** from the list.
3. On the **Access** tab, under **Private Links**, select **Create Connection**.
4. On the **Create Connection** dialog, copy and store the **Private Link Service Alias**. The Endpoint and Connection Type fields are automatically set to MongoDB® and Inbound, respectively.
5. (Optional) Keep the Create Connection dialog open to enter the resource ID of your Azure private endpoint created in the next step.
2. Create a private endpoint on the Azure portal. While configuring the connection, perform the following tasks:
1. Under **Resource**, select **Connect to an Azure resource by resource ID or alias**. Enter the Private Link Service alias copied in the previous step in the **Resource ID or alias** field.
2. Allow incoming connections to `TCP` port `27017` of your private endpoint.
3. Approve the private endpoint connection request.
4. Copy the Private Endpoint Resource ID of your Azure private endpoint. The resource ID has the following format:
`/subscriptions//resourceGroups//providers/Microsoft.Network/privateEndpoints/`
3. Create an inbound private connection on the Cloud Portal. On the **Create Connection** dialog from the first step, enter the **Private Endpoint Resource ID**. The Endpoint and Connection Type fields are automatically set to MongoDB® and Inbound, respectively.
4. Select **Create Connection**.
The connection is ready to use once it is in `ACTIVE` state. Connect to the MongoDB® endpoint using the following connection string (update the credentials and private endpoint address):
```
mongodb://:@:27017/?authMechanism=PLAIN&tls=true&loadBalanced=true&tlsAllowInvalidHostnames=true&tlsAllowInvalidCertificates=true
```
Refer to [Connect to SingleStore Helios Clusters from Private Networks/Services via Azure Private Link](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-azure-private-link.md) for related information.
***
Modified at: July 6, 2026
Source: [/cloud/connect-to-singlestore/private-connections/connect-to-mongodb-using-azure-private-link/](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-mongodb-using-azure-private-link/)
(An index of the documentation is available at /llms.txt)
---
# Connect to SingleStore Helios Clusters from Private Networks/Services via Azure Private Link
For inbound connections, you need to provide your cluster ID and Azure subscription details so that SingleStore can accept the connection request.
To set up inbound connections to SingleStore Helios using private networks/services via Azure Private Link, perform the following tasks:
1. Request an alias from SingleStore.
2. Create a private endpoint.
## Request an Alias from SingleStore
Contact [SingleStore Support](https://support.singlestore.com), and provide the following information:
* Cluster ID and name. SingleStore can only process the connection request when your cluster is in the `Active` state.
* Your Azure subscription ID and name
* Region details
* In the support ticket, specify that the request is for an inbound connection
SingleStore will provide an alias. Use this alias to create a private endpoint (as explained below).
## Create a Private Endpoint
> **📝 Note**: Your cluster and private endpoint must be in the same region.
1. On the [Azure portal](https://portal.azure.com/), select **Create a resource > Networking > Private Link > Create**.
2. Under **Private Link Center**, select **Private endpoints > Add**.
3. Under **Create a private endpoint**, on the **Basics** tab, enter or select the following information:
* **Subscription**: Your Azure subscription.
* **Resource group**: The resource group corresponding to your Azure subscription. It should have the same name as your Azure subscription name. Select **Create new** to create a new resource group.
* **Name**: Name of your private endpoint service.
* **Region**: Select a region in which you want to create the private link service.
4. On the **Resource** tab, under **Connection method**, select **Connect to an Azure resource by resource ID or alias**.
5. Under **Resource ID or alias**, enter the alias received from SingleStore support.
6. On the **Configuration** (or **Virtual Network)** tab, select the **Virtual Network** and **Subnet** where the private endpoint is created.
7. On the **Review + create** tab, review the private endpoint configuration, and select **Create**.
The private endpoint is ready to use.
> **📝 Note**: SingleStore Helios does not support Certificate Authority (CA) verification for inbound connections. For information on connecting to SingleStore Helios using SSL, refer to [Connect to SingleStore Helios using TLS/SSL](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/connect-to-singlestore-helios-using-tls-ssl.md).
## References
* [What is a private endpoint?](https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-overview)
* [Create a private endpoint](https://learn.microsoft.com/en-us/azure/private-link/create-private-link-service-portal#create-private-endpoint-1)
***
Modified at: April 1, 2025
Source: [/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-azure-private-link/](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-azure-private-link/)
(An index of the documentation is available at /llms.txt)
---
# Connect to SingleStore Helios Clusters from Private Networks/Services via Google Private Service Connect
For inbound connections, you will receive a Service Attachment from SingleStore. You'll also need to provide your Google PSC project name to SingleStore, so that SingleStore can whitelist the project name from where you are trying to connect to the cluster.
To set up inbound connections to SingleStore Helios using private networks/services via Google Private Service Connect, perform the following tasks:
1. Contact SingleStore Support (refer to [Support FAQ](https://docs.singlestore.com/cloud/support/support-faq.md)), and provide the following information:
* Cluster ID. SingleStore can only process the connection request when your cluster is in the `Active` state.
* Your Google Private Service Connect project name
* Region details
* In the support ticket, specify that the request is for inbound connection
SingleStore will send you the Service Attachment.
2. On the **Google Cloud** console, under **Private Service Connect**, select a project in the region you want to connect to the Service Attachment sent by SingleStore.
3. [Create a Private Service Connect endpoint](https://cloud.google.com/vpc/docs/configure-private-service-connect-services#create-endpoint) and use the Service Attachment from step 1. SingleStore will then accept the request into the service to complete the connection.
> **📝 Note**: Your cluster and Private Service Connect endpoint must be in the same region.
> **📝 Note**: SingleStore Helios does not support Certificate Authority (CA) verification for inbound connections. For information on connecting to SingleStore Helios using SSL, refer to [Connect to SingleStore Helios using TLS/SSL](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/connect-to-singlestore-helios-using-tls-ssl.md).
***
Modified at: April 1, 2025
Source: [/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-google-private-service-connect/](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-clusters-from-private-networks-services-via-google-private-service-connect/)
(An index of the documentation is available at /llms.txt)
---
# Connect to SingleStore Helios using AWS PrivateLink
Configure both outbound and inbound connections to connect your cluster to AWS PrivateLink. For information on managing private connections, refer to [SingleStore Private Connections](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/singlestore-private-connections.md).
To connect via AWS PrivateLink using Flow, specify the VPC endpoint of your private link in the destination database configuration. Refer to [Configure Flow](https://docs.singlestore.com/#section-id235511456889768.md).
Contact [SingleStore Support](https://support.singlestore.com) for assistance with setting up or configuring private connections.
> **📝 Note**: [This tutorial](https://aws.amazon.com/blogs/big-data/how-goldman-sachs-builds-cross-account-connectivity-to-their-amazon-msk-clusters-with-aws-privatelink/) builds cross-account connectivity to Amazon MSK clusters with AWS PrivateLink by fronting all brokers in the cluster with a single NLB that has cross-zone load balancing enabled. Refer to **Pattern 2: Front all MSK brokers with a single shared interface endpoint** in the tutorial for more information.
## Configure Inbound Connections
To successfully set up an inbound connection to SingleStore Helios using AWS PrivateLink, perform the following tasks:
1. [Create an Inbound Connection on the Cloud Portal](https://docs.singlestore.com/#section-idm4577804916545633710638230996.md)
2. [Create a Private Endpoint on the Amazon VPC Console](https://docs.singlestore.com/#section-idm4587784974278433710639955862.md)
## Create an Inbound Connection on the Cloud Portal
On the [Cloud Portal](https://portal.singlestore.com),
1. Select **Clusters**.
2. Select the three dots under **Actions** for your cluster and select **Access & Security** from the list.
3. Under **Private Links**, select **Create Connection**.
4. On the **Create Connection** dialog, enter or select the following information:
1. **Endpoint**: Select **SingleStore Endpoint**.
2. **Connection Type**: Select the **Inbound** connection type from the list.
3. **AWS Account ID** (Inbound connections only): Enter the AWS Account ID associated with your VPC/private endpoint.
5. Select **Create Connection**.
Once the connection is ready to use, which may take a few minutes, its status changes to `ACTIVE`. If an error occurs while creating the private connection, the connection is deleted automatically. Hover over the `DELETED` status indicator to view the error message.
Copy the **VPC Endpoint Service Name** of your connection, and enter it in the **Service name** field while creating a private endpoint on the Amazon VPC Console. Refer to [Manage Private Connections](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/singlestore-private-connections/#section-idm4493093347076833710473823166.md) for information on how to view the private connection details.
## Create a Private Endpoint on the Amazon VPC Console
> **📝 Note**: Your cluster and endpoint must be in the same region.
Create a private endpoint using the **Service name** copied earlier:
1. On the [Amazon VPC console](https://console.aws.amazon.com/vpc/), select **Endpoints > Create endpoint**.
2. Under **Service Category**, select **Other endpoint services**.
3. Enter the **Service name** copied from the [Cloud Portal](https://portal.singlestore.com) in the **Service name** box.
4. Select **Verify service** to verify the Service name.
5. Under VPC, select the VPC from which you'll connect with the AWS service.
6. Under **Subnets**, select one subnet per Availability Zone from which you'll connect to the AWS service.
7. Select **Create endpoint**.
You can use the endpoint after it enters the `Available` state. Refer to [Endpoint states](https://docs.aws.amazon.com/vpc/latest/privatelink/concepts.html#concepts-service-consumers) for more information. Create a security group to control access to the endpoint, and then attach the security group to the endpoint. Refer to [Control traffic to resources using security groups](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html) for more information.
> **📝 Note**: SingleStore Helios does not support Certificate Authority (CA) verification for inbound connections. For information on connecting to SingleStore Helios using SSL, refer to [Connect to SingleStore Helios using TLS/SSL](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/connect-to-singlestore-helios-using-tls-ssl.md).
## Configure Outbound Connections
To successfully set up an outbound connection to SingleStore Helios using AWS PrivateLink, perform the following tasks:
1. [Copy the AWS account ID from the Cloud Portal](https://docs.singlestore.com/#section-idm4587785065080033710540738094.md)
2. [Create an Endpoint Service on the AWS Console](https://docs.singlestore.com/#section-idm4573444058233633710541583593.md)
3. [Create an Outbound Connection on the Cloud Portal](https://docs.singlestore.com/#section-idm4602413659161633710543006469.md)
4. [Accept the Connection Request in your AWS Console](https://docs.singlestore.com/#section-id23551147332954.md)
If you are using Kafka brokers with AWS MSK, you must specify the IP address of the broker endpoints while creating the target groups of the load balancer. Run the `nslookup` command with the DNS names of the MSK brokers to get their IP addresses. Note that the IP address of the endpoint does not change since it is attached to the VPC ENI (elastic network interfaces). Hence, resolve the broker endpoint IP address before initiating the connection. When using Kafka brokers, use the broker name with the port instead of the endpoint name in the `CREATE PIPELINE` command.
## Copy the AWS Account ID from the Cloud Portal
On the [Cloud Portal](https://portal.singlestore.com),
1. Select **Clusters**.
2. Select the three dots under **Actions** for your cluster and select **Access & Security** from the list.
3. Under **Private Links**, select **Create Connection**.
4. On the **Create Connection** dialog, from the **Connection Type** list, select **Outbound**. Copy the AWS account ID displayed.
You'll need to whitelist this ID while creating your endpoint service.
## Create an Endpoint Service on the AWS Console
On the AWS Console,
1. Create a target group for each of the AWS services that you want to access using AWS PrivateLink, select **EC2 > Target groups > Create Target group**. Refer to [Target Groups](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html) for more information.
2. Create a network load balancer, select **EC2 > Load Balancers > Create Load Balancer**.
3. Under **Network Load Balancer**, select **Create**. Your cluster and the load balancer must be in the same region. Ensure that **Cross-zone load balancing** is enabled. Refer to [Create a Network Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-application-load-balancer.html) for related information.
4. In the AWS Console, select **VPC > Endpoint Services > Create Endpoint Service**.
> **📝 Note**: Your cluster and endpoint service must be in the same region.
* Associate the endpoint service with the Network Load Balancer created in the previous step.
* Enable **Require acceptance for endpoint** for additional security.
5. For this service, under **Allow principals**, add the AWS account ID copied from the Cloud Portal in the `"arn:aws:iam:::root"` format. This enables SingleStore to find and access the private endpoint service.
6. Verify that the security group rules in your VPC allow inbound traffic from the endpoint service, including traffic from internal private IP ranges (for example, RFC1918 ranges such as 10.0.0.0/8), depending on your network configuration. Refer to [Control traffic to resources using security groups](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html) for more information.
7. Copy the **Service Name** of this AWS endpoint service.
## Create an Outbound Connection on the Cloud Portal
On the [Cloud Portal](https://portal.singlestore.com),
1. Select **Clusters**.
2. Select the three dots under **Actions** for your cluster and select **Access & Security** from the list.
3. Under **Private Links**, select **Create Connection**.
4. On the **Create Connection** dialog, enter or select the following information:
1. **Endpoint**: Select **SingleStore Endpoint**.
2. **Connection Type**: Select the **Outbound** connection type from the list.
3. **Service name** (Outbound connections only): Enter the **Service Name** associated with your AWS endpoint service.
5. Select **Create Connection**.
6. (Optional) [Accept the connection request in your AWS Console](https://docs.singlestore.com/#section-id23551147332954.md).
The connection is ready to use once the endpoint status changes to `ACTIVE`. If an error occurs while creating the private connection, the connection is deleted automatically. Hover over the `DELETED` status indicator to view the error message.

## Accept the Connection Request in your AWS Console
If **Require acceptance for endpoint** is enabled while creating the endpoint service, you must accept the connection request from SingleStore in your AWS account. On the AWS Console,
1. Select **VPC > Endpoint Services**, and then select your endpoint service.
2. On the **Endpoints Connections** tab, find the request from the SingleStore AWS account with the **Pending Acceptance** status.
3. From the **Actions** menu, select **Accept Endpoint Connection Request**.
The connection status changes to **Available**, indicating that the connection is successfully established and is ready to use.
## Configure Flow
To configure Flow to connect using AWS PrivateLink:
1. Log in to the [Cloud Portal](https://portal.singlestore.com).
2. Copy the **VPC Endpoint** of your outbound private link.
1. Select **Clusters**.
2. Select the three dots under **Actions** for your cluster and select **Access & Security** from the list.
3. Under **Private Links**, select the three dots under **Actions** for your private link, and then select **View Connection**.
4. Copy the **VPC Endpoint** for your private link.
3. Select **Ingestion > Load Data**, and then select a source supported by Flow.
4. Configure the destination database, connection name, Flow instance size, and then select **Create Flow Instance**.
5. Select **Open Flow** under the **Actions** column of the Flow instance created in the previous step.
6. On the **Setup** tab, configure the source database and then select **Next**.
7. Under **Destination Database**, enter the **VPC Endpoint** copied earlier in the **Host Name** field.
8. Enter the username and password of the SingleStore database user with which to connect.
9. Select **Test** to test the connection.
Once the connection is verified, [configure the Flow instance](https://docs.singlestore.com/cloud/load-data/load-data-with-singlestore-flow-on-helios/use-flow-on-helios.md) as required and proceed with data ingestion.
Refer to [Load Data with SingleStore Flow on Helios](https://docs.singlestore.com/cloud/load-data/load-data-with-singlestore-flow-on-helios.md) for more information.
## References
* [AWS PrivateLink Concepts](https://docs.aws.amazon.com/vpc/latest/privatelink/concepts.html#concepts-service-consumers)
* [Create a private endpoint service](https://docs.aws.amazon.com/vpc/latest/privatelink/create-endpoint-service.html)
## In this section
* [Connect SingleStore Helios to AWS MSK using AWS PrivateLink](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-using-aws-privatelink/connect-singlestore-helios-to-aws-msk-using-aws-privatelink.md)
* [Connect to MongoDB® using AWS PrivateLink](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-using-aws-privatelink/connect-to-mongodb-using-aws-privatelink.md)
***
Modified at: May 15, 2026
Source: [/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-using-aws-privatelink/](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-using-aws-privatelink/)
(An index of the documentation is available at /llms.txt)
---
# SingleStore Private Connections
The SingleStore Private Connections (SPC) feature allows you to connect from a SingleStore Helios cluster to private services and networks. Private services/networks simplify networking and connectivity by allowing users to connect directly from a virtual private network to SingleStore Helios.
To successfully set up a private connection, you need to configure both the outbound and inbound connections. Each cluster can only have one active inbound and outbound connection.
The SPC feature is only supported for SingleStore Helios clusters deployed using AWS, and it only supports connections to AWS PrivateLink.
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
## Prerequisites
The SPC feature must be enabled for your organization. If this feature is not enabled by default, contact [SingleStore Support](https://support.singlestore.com).
## Configure Private Connections
To create a private connection to AWS PrivateLink, refer to [Connect to SingleStore Helios using AWS PrivateLink](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/connect-to-singlestore-helios-using-aws-privatelink.md).
## Manage Private Connections
To manage a private connection on the [Cloud Portal](https://portal.singlestore.com/), navigate to **Clusters**, select the three dots under the **Actions** menu for your cluster and select **Access & Security** from the list. Under **Private Links**, select the three dots in the **Actions** column of your private connection.
Once the private connection is in `ACTIVE` state, you can perform the following actions:
* **Edit Connection**: Displays the private connection details, and allows you to edit the AWS Account ID of your (inbound) private connection.
* **Delete Connection**: Deletes a private connection.
## Private Connection Status
Any private connection can have one of the following statuses:
| **Status** | **Description** |
| ---------- | ------------------------------------------- |
| `ACTIVE` | The private connection is ready for use. |
| `DELETED` | The private connection has been deleted. |
| `PENDING` | The private connection is being configured. |
***
Modified at: May 12, 2026
Source: [/cloud/connect-to-singlestore/private-connections/singlestore-private-connections/](https://docs.singlestore.com/cloud/connect-to-singlestore/private-connections/singlestore-private-connections/)
(An index of the documentation is available at /llms.txt)
---
# SingleStore Helios Endpoints
An endpoint is a URL used to connect with SingleStore Helios clusters. The SingleStore Helios endpoints are available on the [Cloud Portal](https://portal.singlestore.com). Once logged in,
1. Navigate to **Clusters**.
2. Select the **Connect** under the **Actions** column of your cluster, and then select **CLI Client** from the list.
3. On the **CLI Client** tab, select **SingleStore Endpoints** from the list. The endpoint of your SingleStore deployment is displayed in the **Endpoint** section.
Access SingleStore Helios deployment using the available endpoint with any of the supported [SQL clients](https://docs.singlestore.com/cloud/connect-to-singlestore.md) and/or [development tools](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools.md).
> **📝 Note**: When using a third-party SQL client or development tool, you must first [add a database user](https://docs.singlestore.com/cloud/user-and-cluster-administration/manage-database-users.md) to log into a SingleStore Helios database.
## Connect to SingleStore Helios via TLS/SSL
To establish an encrypted connection from a stand-alone SQL client, you need a TLS/SSL public certificate. This certificate ensures that clients without a valid certificate are not allowed to connect to your cluster. This CA certificate can also be used to verify the identity of each cluster host. Download the TLS/SSL certificate from the Cloud Portal. Install the certificate via the instructions provided at [How Do I Install a Certificate?](https://www.ssl.com/faqs/faq-how-do-i-install-a-certificate/).
For example, using the SingleStore command line (CLI) client, you can connect to the SingleStore Helios endpoints using the `singlestore_bundle.pem` [certificate file](https://portal.singlestore.com/static/ca/singlestore_bundle.pem). The `.pem` file enables support for encrypted connections. Include the `--ssl-mode=VERIFY_CA` option to verify the certificate.
**Note**: Include the `--ssl-mode=REQUIRED` option to establish a secure connection in older versions of the MySQL client, even when the `--ssl-ca` option is specified.
```shell
singlestore -u admin -p -h -P 3306 --default-auth=mysql_native_password --ssl-ca=./singlestore_bundle.pem --ssl-mode=VERIFY_CA
```
> **❗ Important**: If your SQL client connects using the `singlestore_bundle.pem` file with the `--ssl-mode=VERIFY_CA` flag and is unable to establish a connection to SingleStore Helios, download and use the latest `singlestore_bundle.pem` file.
See [Connect to SingleStore Helios using TLS/SSL](https://docs.singlestore.com/cloud/connect-to-singlestore/connect-with-mysql/connect-with-mysql-client/connect-to-singlestore-helios-using-tls-ssl.md) topic for more information.
## Secure the SingleStore Helios Connection
## Server Configuration to Require Secure Client Connections
To make the server restrict access to clients over SSL only, add the `REQUIRE SSL` clause to the user’s `GRANT` statement, for example:
```sql
CREATE USER 'user'@'%' IDENTIFIED BY 'password';
ALTER USER 'user'@'%' REQUIRE SSL;
```
For example, if `REQUIRE SSL` is specified for the user `user`:
```shell
## This connection attempt is rejected with an "Access denied" error:
singlestore -u user -h 1.2.3.4
```
```shell
## This one works:
singlestore -u user -h 1.2.3.4 --ssl-ca=ca-cert.pem
```
Unless the client is configured properly, the client may or may not use SSL to connect to SingleStore Helios even if SSL is enabled on the SingleStore Helios cluster. Adding `REQUIRE SSL` helps protect against misconfigured clients by preventing them from connecting over an insecure plaintext connection. However, proper client configuration is still necessary for security against active network attacks, regardless of server configuration.
Note that the server currently uses a hardcoded version of the TLS protocol.
***
Modified at: May 14, 2026
Source: [/cloud/connect-to-singlestore/singlestore-helios-endpoints/](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints/)
(An index of the documentation is available at /llms.txt)
---
# Container Services
> **📝 Note**: Containers and the medium/GPU pool are currently in private preview. Please contact [Support](https://support.singlestore.com) for more information
SingleStore’s Aura Container Service (SingleStore Aura service, also referred to as "Managed Container Service") is a serverless platform designed to provide instant access to pre-warmed containers for running custom applications with minimal latency. While initially developed to support Jupyter Notebooks, the platform is designed to execute any containerized application across supported hardware configurations.
## Key Features
* **Instant Container Availability**: The platform maintains a pool of pre-warmed containers, enabling sub-second container acquisition times for your applications. This eliminates the traditional wait times associated with container startup and initialization.
* **Enhanced Security**: The platform implements the [gVisor](https://gvisor.dev/) container runtime for robust security isolation, allowing you to safely execute untrusted code, LLM-generated content, or third-party applications without compromising the host system.
* **GPU Support**: Pre-configured container images come with NVIDIA drivers pre-installed, making it seamless to run GPU-accelerated workloads without additional setup.
* **Simplified Developer Experience**: The platform abstracts away the complexity of Docker and Kubernetes management and handles all container orchestration automatically, allowing developers to focus on their code rather than infrastructure concerns.
## How It Works
## Container Pool Management
The platform automatically maintains and manages a pool of warm containers, ensuring immediate availability when requested.
## Streamlined Workflow
Traditional container deployment typically involves:
1. Spinning up a new container
2. Configuring the environment
3. Installing required dependencies
4. Starting application services
With the Aura Container Service, this process is simplified to:
1. Request a container
2. Connect to a pre-configured environment
3. Begin working immediately
## Container Sizing and Node Type
| **Node** | **Container** |
| ------------------------------------ | --------------------------------------------- |
| CPU Pool | Small(1750m vCPU, 14 GB RAM, 40 GB) |
| Medium(3750m vCPU, 27 GB RAM, 40 GB) | |
| GPU Pool | GPU - T4(1 GPU, 6500m vCPU, 27 GB RAM, 40 GB) |
## Rate Limits
To prevent abuse, either accidental or intentional, SingleStore enforces limits on the number of containers that can be created in an organization, which can be increased upon request.
By default, an organization can have up to 50 active sessions and can create up to 20 containers per minute.
## Session Limits
The session limits for different container service workloads are:
| **Workload Type** | **Idle Timeout (Minimum)** | **Idle Timeout (Maximum)** | **Long Code Execution Limit** |
| --------------------- | -------------------------- | -------------------------- | ----------------------------- |
| Interactive Notebooks | 15 minutes (Default) | 4 hours | 1 hour |
| Dashboards | 15 minutes (Default) | No Timeout | 1 hour |
| Cloud Functions | 15 minutes (Default) | No Timeout | 1 hour |
| Python UDFs | 15 minutes (Default) | No Timeout | 1 hour |
Idle Timeout can be configured while creating or updating the workload instance. Once the timeout limit is reached, the system automatically terminates the workload session and deletes any unsaved data (state/variables/files).
Interactive notebooks allow a single active session per user with each session having a maximum lifetime of 8 hours.
Organization-level workloads such as Dashboards, Cloud Functions, and Python UDFs allow only one active session at a time, and that session is shared across all users.
## Session Persistence and State Management
Workload sessions can run indefinitely when no idle timeout is configured or when activity remains within the configured limits.
However, workloads must not rely on in-memory state or stateful connections. The system may move a session across multiple containers during its lifetime. As a result, in-memory state can be lost at any time and stateful protocols or long-lived connections are not guaranteed to persist.
## In this section
* [Notebooks](https://docs.singlestore.com/cloud/container-services/notebooks.md)
* [Scheduled Jobs](https://docs.singlestore.com/cloud/container-services/scheduled-jobs.md)
* [Dashboard Apps](https://docs.singlestore.com/cloud/container-services/dashboard-apps.md)
* [Cloud Functions](https://docs.singlestore.com/cloud/container-services/cloud-functions.md)
* [Container App API Keys](https://docs.singlestore.com/cloud/container-services/container-app-api-keys.md)
* [Container Services RBAC](https://docs.singlestore.com/cloud/container-services/container-services-rbac.md)
* [Python UDFs](https://docs.singlestore.com/cloud/container-services/python-udfs.md)
***
Modified at: December 19, 2025
Source: [/cloud/container-services/](https://docs.singlestore.com/cloud/container-services/)
(An index of the documentation is available at /llms.txt)
---
# Cloud Functions
> **📝 Note**: This is a Preview feature.
SingleStore Cloud Functions is a serverless, cloud-based service that allows users to run code without managing compute resources. It enables the execution of code such as SQL queries, Python scripts, and API calls in response to trigger actions. As a fully managed service, it eliminates the need to provision or manage servers. It allows users to run complex queries and perform ETL (Extract, Transform and Load) tasks without the need to manage dedicated compute resources.
Create and manage cloud functions using the Cloud Portal or via the [Management API](https://docs.singlestore.com/cloud/reference/management-api.md).
## Publish Cloud Functions using the Cloud Portal
## Create a Cloud Function
Cloud Functions can be created for shared notebooks only. Create a cloud function using one of the following methods:
1. Navigate to **Cloud Functions** in the left navigation and select **Get Started**.
2. Navigate to **Editor > Shared**.
1. Select a shared notebook.
2. Select **Publish** (on the top right).
## New Cloud Function
After selecting **Publish**, enter or select the following in **Publish Settings**:
| **Publish Settings** | |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Publish as** | Select**Cloud Function**. |
| **Name** | Enter a name for the cloud function. |
| **Description** | Enter the cloud function description. |
| **Notebook** | Select a shared notebook to publish as a cloud function. The shared notebook is pre-selected when the cloud function is published through notebooks. |
| **Cluster** | Select theSingleStoreclusterthe notebook will connect to.Selecting aclusterallows connecting to theSingleStoredatabases referenced in the notebook natively. A cloud function can be published without aclusterattached to it. |
| **Runtime** | Select a runtime from the following: 📝 Note:
This field is in preview.
|
| **Region** | Select a region. |
| **Idle Timeout** | Select an idle timeout. 📝 Note:
This field is in preview.
|
Select **Next** , review the **Summary**, and then select **Publish** to publish the notebook as a cloud function.
## Example Notebook
The following notebook shows how to publish your first cloud function:
## Manage an Existing Cloud Function
To view an existing cloud function, select **Cloud Functions** in the left navigation. Existing cloud functions can be managed by performing the following actions:
* View
* Update
* Share
* Delete
## View an Existing Cloud Function
To view an existing cloud function, select the cloud function name under the **Name** column and view the details for each cloud function.
View the details of a cloud function on the right navigation pane. Following actions can be performed for a cloud function from this page:
* Copy URL
* View API Keys
* View Live Logs
* Share
* Update
* Delete
## View API Keys
Refer to [Container App API Keys](https://docs.singlestore.com/cloud/container-services/container-app-api-keys.md) for related information.
## View Live Logs
To view live logs of the selected cloud function, select **View Live Logs** from the ellipsis on the right side. A new window appears, where the **Timestamp** and the message in the **Body** column can be viewed. View the **Log JSON** by selecting the eye icon.
## Update an Existing Cloud Function
To update an existing cloud function, select the ellipsis in the **Actions** column of the cloud function, and select **Update**.
A cloud function can also be updated from a shared notebook. Select **Update Cloud Function** and select **Update**.
## Share an Existing Cloud Function
To share an existing cloud function, select the ellipsis in the **Actions** column of the cloud function, and select **Share**.
## Delete an Existing Cloud Function
To delete an existing cloud function, select the ellipsis in the **Actions** column of the cloud function, and select **Delete**.
## Publish Cloud Functions using the Management API
Use the `CloudFunctions` path (`/v1/cloudfunctions` endpoint) to create and manage jobs using the Management API. Refer to [Management API](https://docs.singlestore.com/cloud/reference/management-api.md) and [Management API Reference](https://docs.singlestore.com/cloud/reference/management-api/reference.md) for more information.
For example, the following API call lists all the cloud functions in the current organization:
```shell
curl -X 'GET' \
'https://api.singlestore.com/v1/cloudfunctions' \
-H 'accept: application/json'
```
## Status of Cloud Functions
| **Status** | **Description** |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Initializing | The notebook is creating or updating the cloud function. |
| Active | The notebook is successfully published as a cloud function. |
| Failed | The cloud function is not configured correctly. View the notebook snapshot to debug the failure. |
| Error | An error unrelated to the notebook code prevented the cloud function from initializing. Refer to[Troubleshoot Cloud Functions](https://docs.singlestore.com/#section-idm234665756837262.md). |
## Troubleshoot Cloud Functions
SingleStore automatically saves a snapshot of the notebook for each execution that fails. Navigate to **Cloud Functions** in the left navigation, select the cloud function, and download the snapshot associated with the failed cloud function to diagnose the error. The following table lists some common errors and their resolutions:
| **Error** | **Solution** |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------- |
| ClusterDeleted | Update the cloud function and select acluster. |
| ClusterSuspended | Resume thecluster, or create a new cloud function with a differentcluster. |
| Database Detached | Reattach the database with the right permissions or create a new cloud function with a different database. |
| Notebook Deleted/Not Present | Create a new cloud function with a different notebook. |
| Internal Errors/Misc | Reach out to[SingleStoreSupport](http://support.singlestore.com)or use the chat feature in theCloud Portal. |
***
Modified at: July 7, 2026
Source: [/cloud/container-services/cloud-functions/](https://docs.singlestore.com/cloud/container-services/cloud-functions/)
(An index of the documentation is available at /llms.txt)
---
# Container App API Keys
> **📝 Note**: This is a Preview feature.
Container App API keys allow you to programmatically interact with SingleStore Aura environment. These keys are used to authenticate requests to Container App APIs, which enables automation, integration with CI/CD pipelines, and secure service-to-service communication. A Container App API key can be created for and used to access any Container App, such as **Cloud Functions** and **Dashboard Apps**. The API key is unique and only enables access to the Container App for which it is created.
## Create a Container App API Key
To create an API key, perform the following steps:
1. In the Cloud Portal, under the **Container Services** section, navigate to a Container App.
2. Select an App instance. An example with a Cloud Function App is demonstrated.
3. Select **View API Keys** in the upper right corner.
4. Select **Create API Key**.
5. In the **Create API key for \ - \ **dialog,
1. Enter the name in the **API Key Name** field.
2. In **Expiration**, select the expiration date.
3. Select **Create API Key**.
6. Once the API key is generated, select **Copy API Key** to copy it or **Save As Secret** to store it securely in **[Secrets](https://docs.singlestore.com/cloud/developer-resources/secrets.md)**. The API key is displayed only **once**.
7. If **Save As Secret** is selected:
1. In the **New Secret** dialog, enter the name for the secret in the **Name** field.
2. Select **Create Secret**. The API key is stored in a secret.
8. Select **Close**.
## Types of Container App API Keys
There are two types of Container App API keys:
1. **Active API key**: An API key that is currently valid, associated with an existing App instance or user, and has not been revoked. It can successfully authenticate requests to the Container App APIs.
2. **Orphaned API key**: An API key that is not associated with an existing App instance, as the App or user that created it, was deleted. Orphaned keys are inactive and cannot be used to authenticate API requests.
> **📝 Note**: Orphaned API keys pose a potential security risk and should be identified and revoked promptly.
## Manage a Container App API Key
You can manage a Container App API key in two ways:
1. Using the App instance
2. Using the Container Service
## Using the App Instance
1. Navigate to the Container Service.
2. Under the **Name** column, select the App instance for which you want to manage the Container App API key.
3. Select **View API Keys** in the upper right corner. You can view the total number of API keys for the App instance on the **View API Keys** button.
4. To revoke an active or orphaned Container App API key, perform the following tasks:
1. Revoke an Active Container App API key:
1. Navigate to the **Active** tab.
2. Select the delete icon under the **Actions** column next to your API key.
3. In the **Revoke API key** dialog, enable the agreement and select **Revoke**.
2. Revoke an Orphaned Container App API key:
1. Navigate to the **Orphaned** tab.
2. Select the delete icon under the **Actions** column next to your API key.
3. In the **Revoke API key** dialog, enable the agreement and select **Revoke**.
> **📝 Note**: Orphaned keys can only be revoked by the **Aura Owner** or **Owner** of the organization.
## Using the Container Service
1. Navigate to the Container Service.
2. Select **View API Keys** in the upper right corner.
3. To revoke an active or orphaned Aura App API key, perform the following tasks:
1. Revoke an Active Container App API key:
1. Navigate to the **Active** tab.
2. Select the delete icon under the **Actions** column next to your API key.
3. In the **Revoke API key** dialog, enable the agreement and select **Revoke**.
2. Revoke an Orphaned Container App API key:
1. Navigate to the **Orphaned** tab.
2. Select the delete icon under the **Actions** column next to your API key.
3. In the **Revoke API key** dialog, check the agreement and select **Revoke**.
> **📝 Note**: Orphaned keys can only be revoked by **Aura Owner** or **Owner** of the organization.
***
Modified at: July 7, 2026
Source: [/cloud/container-services/container-app-api-keys/](https://docs.singlestore.com/cloud/container-services/container-app-api-keys/)
(An index of the documentation is available at /llms.txt)
---
# Container Services RBAC
> **📝 Note**: This is a Preview feature.
SingleStore Aura supports Role-Based Access Control (RBAC), which allows administrators to assign granular permissions at multiple levels. This ensures that users and teams have only the access they need to develop, deploy, and manage Container services such as Cloud Functions, Dashboard Apps, and Scheduled Jobs.
Refer to [Role-Based Access Control (RBAC) for SingleStore Helios](https://docs.singlestore.com/cloud/security/administration/role-based-access-control-rbac-for-singlestore-helios.md) for more information on RBAC in SingleStore Helios.
## Benefits of RBAC in SingleStore Aura
* **Operational Efficiency**: You can onboard or offboard users efficiently and modify their access based on role changes.
* **Secure Collaboration**: RBAC ensures that users access only the resources they need. For example, data scientists can build applications, while analysts can view them without making changes.
* **Compliance-Ready**: Role-to-resource mappings and access logs simplify audit processes and help meet regulatory requirements.
* **Orphaned Resource Prevention**: When users leave, RBAC helps prevent lost or unmanaged assets by enabling easy transfer of ownership.
## Predefined Roles for Container App Resource
| **Role** | **Description** | **Permission** |
| -------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Owner | Owners are granted full access including the ability to manage access, operate, delete, monitor and use the Container App. | - Control Access
- Create API Keys
- Delete
- Revoke API Keys
- Update
- Use
|
| User | Users are granted access to only use Container App and create Container App API keys. | |
## How to Use RBAC in SingleStore Aura
Aura App users can enforce RBAC in SingleStore Aura using both the Cloud Portal and Management API.
## Using Cloud Portal
To use RBAC in the Cloud Portal, perform the following steps:
1. Under the **Container Services** section, navigate to an Aura App.
2. Select the three dots under the **Actions** column next to your Container App instance, and then select **Share**.
3. From the list, select **User** or **Team** to share the Container App with.
4. In the **Access** list, select the desired role next to the selected user or team.
5. To remove access for a user or team, select **Remove Access** in the **Access** list.
## Using Management API
Use the `Users` (`/v1/users` endpoint) and `Teams` path (`/v1/teams` endpoint) in the [Management API](https://docs.singlestore.com/cloud/reference/management-api.md) to use RBAC in SingleStore Aura. Refer to [Management API Reference](https://docs.singlestore.com/cloud/reference/management-api/#section-idm4608309617228834306792661294.md) for more information.
***
Modified at: July 7, 2026
Source: [/cloud/container-services/container-services-rbac/](https://docs.singlestore.com/cloud/container-services/container-services-rbac/)
(An index of the documentation is available at /llms.txt)
---
# Dashboard Apps
> **📝 Note**: This is a Preview feature.
SingleStore Dashboard Apps enables users to create, publish, and manage real-time interactive dashboards through the Cloud Portal. It integrates with SingleStore Notebooks and uses Plotly's Dash framework. It helps in monitoring key metrics, exploring trends, and making data-driven decisions in real time.
Create and manage dashboard apps using the Cloud Portal.
## Publish Dashboard Apps using the Cloud Portal
## Create a Dashboard App
Dashboard Apps can be created for shared notebooks only. Create a dashboard app using one of the following methods:
1. Navigate to **Dashboards** in the left navigation and select **Get Started**.
2. Navigate to **Editor > Shared**.
1. Select a shared notebook.
2. Select **Publish** (on the top right).
## New Dashboard App
After selecting **Publish**, enter or select the following in **Publish Settings**.
| **Publish Settings** | |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Publish as** | Select**Dashboard**. |
| **Name** | Enter a name of the dashboard app. |
| **Description** | Enter the dashboard app description. |
| **Notebook** | Select a shared notebook to publish as a dashboard app. The shared notebook is pre-selected when the dashboard app is published through notebooks. |
| **Cluster** | Select theSingleStoreclusterthe notebook connects to.Selecting aclusterallows connecting to theSingleStoredatabases referenced in the notebook natively. A dashboard app can be published without a attached to it. |
| **Runtime** | Select a runtime from the following: 📝 Note:
This field is in preview.
|
| **Region** | Select a region. |
| **Idle Timeout** | Select an idle timeout. 📝 Note:
This field is in preview.
|
Select **Next**, review the **Summary**, and select **Publish** to publish the notebook as a dashboard app.
## Example Notebook
The following notebook shows how to publish your first dashboard app.
## Manage an Existing Dashboard App
To view an existing dashboard app, select **Dashboards** in the left navigation. Existing dashboard App can be managed by performing the following actions:
* View
* Update
* Share
* Delete
## View an Existing Dashboard App
To view an existing dashboard app, select the dashboard app name under the **Name** column and view the details for each dashboard app.
View the details of a dashboard app on the right navigation. Following actions can be performed for a dashboard app from this page:
* View Dashboard in New Tab
* View API Keys
* View Live Logs
* Share
* Update
* Delete
## View API Keys
Refer to [Container App API Keys](https://docs.singlestore.com/cloud/container-services/container-app-api-keys.md) for related information.
## View Live Logs
To view live logs of the selected dashboard app, select **View Live Logs** from the ellipsis on the right side. A new window appears, where the **Timestamp** and the message in the **Body** column can be viewed. View the **Log JSON** by selecting the eye icon.
## Update an Existing Dashboard App
To update an existing dashboard app, select the ellipsis in the **Actions** column of the dashboard app, and select **Update**.
A dashboard app can also be updated using the shared notebook. Select **Update Dashboard** and select **Update**.
## Share an Existing Dashboard App
To share an existing dashboard app, select the ellipsis in the **Actions** column of the dashboard app, and select **Share**
## Delete an Existing Dashboard App
To delete an existing dashboard app, select the ellipsis in the **Actions** column of the dashboard app, and select **Delete**.
## Status of Dashboard Apps
| **Status** | **Description** |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Initializing | The notebook is creating or updating the dashboard. |
| Active | The dashboard is configured correctly. The notebook is successfully published as a dashboard. |
| Failed | The dashboard is not configured correctly. View the notebook snapshot to debug the failure. |
| Error | An error unrelated to the notebook code prevented the dashboard from initializing. Refer to[Troubleshoot Dashboard Apps](https://docs.singlestore.com/#section-idm234663965101069.md). |
## Troubleshoot Dashboard Apps
SingleStore automatically saves a snapshot of the notebook for each execution that fails. Navigate to **Apps** in the left navigation, select the dashboard, and download the snapshot associated with the failed dashboard to diagnose the error.
| **Error** | **Solution** |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------- |
| ClusterDeleted | Update the dashboard and select acluster. |
| ClusterSuspended | Resume theclusteror create a new dashboard with a differentcluster. |
| Database Detached | Reattach the database with the right permissions or create a new dashboard with a different database. |
| Notebook Deleted/Not Present | Create a new dashboard with a different notebook. |
| Internal Errors/Misc | Reach out to[SingleStoreSupport](http://support.singlestore.com)or use the chat feature in theCloud Portal. |
***
Modified at: July 7, 2026
Source: [/cloud/container-services/dashboard-apps/](https://docs.singlestore.com/cloud/container-services/dashboard-apps/)
(An index of the documentation is available at /llms.txt)
---
# Notebooks
Notebooks are a common tool for developing code and presenting results. In SingleStore, notebooks enable collaboration between users with a native integration with SingleStore runtime using SQL and Python. We have implemented notebooks to be useful tools for data engineers and scientists, and app developers who want to quickly prototype and demo application code.
Notebooks are implemented with security in mind. Administrators have control over which endpoint they allow notebooks to connect. Notebooks can be private or shared with all other users with access to the same workgroup. Notebooks are run in separate containers. In general, notebooks in SingleStore behave as standard Jupyter notebooks.
Notebooks can also be run on a schedule with SingleStore [Job Service](https://docs.singlestore.com/cloud/container-services/scheduled-jobs.md). This helps you to easily make your notebooks production-ready for various scenarios like Data Prep and ML Flows, Python-based transformations, and building dashboards on real-time data. You can power these scenarios without any data having to leave your SingleStore environment and through the familiar and collaborative notebook environment.
The topics in this section provide a high-level overview of how to work with notebooks, as well as more detail on using notebooks with SQL and SingleStore Helios specific features.
## In this section
* [Using Notebooks](https://docs.singlestore.com/cloud/container-services/notebooks/using-notebooks.md)
* [Notebook Version History](https://docs.singlestore.com/cloud/container-services/notebooks/notebook-version-history.md)
* [Github Integration for Notebooks](https://docs.singlestore.com/cloud/container-services/notebooks/github-integration-for-notebooks.md)
* [Develop with Notebooks](https://docs.singlestore.com/cloud/container-services/notebooks/develop-with-notebooks.md)
* [Load Dataframes From Notebooks](https://docs.singlestore.com/cloud/container-services/notebooks/load-dataframes-from-notebooks.md)
* [Running a Notebook from Another Notebook using Fusion SQL](https://docs.singlestore.com/cloud/container-services/notebooks/running-a-notebook-from-another-notebook-using-fusion-sql.md)
***
Modified at: November 17, 2025
Source: [/cloud/container-services/notebooks/](https://docs.singlestore.com/cloud/container-services/notebooks/)
(An index of the documentation is available at /llms.txt)
---
# Develop with Notebooks
Prototyping applications or analyzing via notebooks in SingleStore Helios follows the same general principles as developing with notebooks in general.
To get started, connect to a data source.
## Connect to Data Sources
SingleStore Helios supports internal and external data sources. Internal data sources are databases that exist within your cluster. An external data source could be an AWS S3 bucket, for example.
## Connect to a SingleStore Data Source
Once you select a cluster, you can access all of the databases attached to that cluster. You cannot connect to databases that are not attached to the cluster you are using.
You can specify a default database for your notebook, eliminating the need to specify the database context every time you make a query on that default database. To set a default database, select a database from the drop-down menu.
No default database specified:

Default database specified:

## Connecting via SQL
To connect to the default database, you do not need to pass any database context to query that database:
```sql
%%sql
SELECT * FROM mytable;
```
To connect to a non-default database, you will need to specify the database in your query:
```sql
%%sql
USE mydatabase;
SELECT * FROM mytable;
```
You can also use "dot" notation:
```sql
%%sql
SELECT * FROM mydatabase.mytable;
```
## Connecting via Python
When connecting via Python to the default database, use the predefined connection string variable, `connection_url`:
```python
from sqlalchemy import *
db_connection = create_engine(connection_url)
```
You can then use that connection string (`db_connection` above) to connect to SingleStore. Here's an example of creating a table using that connection string:
```python
query1 = 'create table people (filename varchar(255), vector blob, shard(filename))'
with db_connection.connect() as conn:
conn.execute(text(query1))
```
When connecting to other databases, use the following method where user (`connection_user`), password (`connection_password`), host (`connection_host`), and port (`connection_port`) are already defined based on the cluster you selected.
```python
from sqlalchemy import *
database_name = 'mydatabase'
db_connection_str = "singlestoredb://"+connection_user+":"+connection_password+"@"+connection_host+":"+connection_port+"/"+database_name
db_connection = create_engine(db_connection_str)
```
You can then use that connection string (`db_connection` above) to connect to SingleStore:
```python
query1 = 'create table people (filename varchar(255), vector blob, shard(filename))'
with db_connection.connect() as conn:
conn.execute(text(query1))
```
## Connect to an External Data Source
SingleStore Helios lets you control which endpoint to access from notebooks to provide secure outbound access to trusted resources.
By default, connections are limited to SingleStore databases; however, you can enable and disable connections to other external endpoints via the allowlist.
Only users with the **Organization Owners** role can add external connections.
When trying to access an external endpoint from a notebook that is not in the allowlist, you should see the following warning:

To fix this issue, select **Add to Firewall** and then select **Save**. The external connection is automatically added into the allowlist. The notebook cell will be executed.

If you do not have access due to your role, your organization owner can manually add or remove the external endpoint using the following steps:

1. In the left navigation, select **Editor**.
2. Select the **Firewall** tab in the main window.
3. Select **Edit** to add new endpoints:

4. In the Edit Allowlist dialog, you can add a Fully Qualified Domain Name (FQDN) or select from a list of suggested FQDNs (for example pypi.org, github.com, or \*.s3.\*.amazonaws.com).
You can provide wildcard access to an endpoint by using the `*` character. The wildcard character represents 0 or more valid DNS characters, except for '.'.
`*.singlestore.com` matches `docs.singlestore.com` but not `singlestore.com` because it only matches up to the '.' character. `ex*le.com` matches example.com but not `examp-site.com`.
For example, to access any AWS S3 endpoints, you can use the following syntax: \*.s3.\*.amazonaws.com.
5. Select **Save**.
To remove a connection select the Trash icon next to the connection in the Edit FQDN Allowlist dialog.
## Manage Cells
Use the same commands and techniques you use with most other Python based cells in notebooks.
## Cell Types
A notebook cell can be one of these types:
* **Markdown**: lightweight markup language used to add formatting to plain text. More information [here](https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Working%20With%20Markdown%20Cells.html).
* **Python**: language supported is Python 3.
* **SQL**: language supported is SQL (for SingleStore).
Specify the cell type by selecting a cell and choosing a type from the drop-down menu:

## Run a cell
Execute/run a cell via keyboard shortcut (**Shift+Return/Enter**) or by selecting the run (play button) icon at the left of the notebook cell, or by selecting **Run Selected Cell** option from the **Run** menu in the toolbar.

## Run Multiple Cells
Execute/run multiple selected cells using the following options from the **Run** menu in the toolbar:
* Run Selected Cell and All Below
* Run All Above and Selected Cell
* Run All Cells
* Restart and Run All Cells
## Manipulating Cells
When you select a cell, some icons for basic cell manipulation appear:
| Action | Icon | Description |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
| Add a cell |  | Add a new cell above or below the selected cell. |
| Move |  | Move the selected cell up or down. |
| Copy |  | Copy the selected cell. |
| Duplicate |  | Duplicate the current cell and place it immediately below the current cell. |
| Delete |  | Delete the selected cell. |
| Ask SQrL |  | An AI-powered co-pilot (SQrL) answers questions. |
For more options, right-click/control-click on a cell to open the cell context menu.
From the context menu, you can perform additional cell functions, such as split and merge.
Keyboard shortcuts exist for most common tasks as well.

## Manage Cell Inputs and Output
Right-click/control-click on a cell to open the cell context menu.

An additional option **Format SQL Cell** is available when the selected cell is using the SQL language (via the `%%sql` magic command or the SQL cell).
You can also show/hide cell output by selecting the vertical bar (purple) next to the output. Before:

After selecting the bar:

## Use Multiple Languages
You can set the default language for notebooks to either SQL or Python3.
You can select the language for a cell via the toggle located above the cell:

## Python Cells
Python 3 is the default language for Python cells. See the [Python documentation](https://docs.python.org/3/index.html) for more information about using Python.
## SQL Cells
There are two options to write SQL in notebooks. The first involves selecting a cell type to be SQL. The following example shows how to specify a default database (mydatabase) and the syntax used to connect to another database (mydatabase2) for use in joins with an SQL cell:
```sql
USE mydatabase; -- the database to use by default
SELECT * from mytable mt1
INNER JOIN mydatabase2.mytable2 mt2 ON mt1.mycolumnid1 = mt2.mycolumnid2;
```
The next option is to use the SQL magic from within a Python cell. This gives you the ability to write SQL and Python code in a single block:
```sql
%%sql - switch the cell to SQL
USE mydatabase; -- the database to use by default
SELECT * FROM mytable mt1
INNER JOIN mydatabase2.mytable2 mt2 ON mt1.mycolumnid1 = mt2.mycolumnid2;
```
The results are displayed as a table.
You can also save and use the output from the calculation in an SQL cell (called `output_reviews` in this example) in another Python cell with the following options:
Using cell output - **Save result to**:

Or, using SQL magic:
```sql
%%sql output_reviews << -- switch the cell to SQL and specify the output as output_reviews
SELECT * FROM reviews
```
This output can then be used in other cells, etc. For example, in this example, `output_reviews` is used with Python as a dataframe:
```python
df = pd.DataFrame(output_reviews)
```
## SQL Line
Use `%sql` to enable a single line of SQL in a Python cell:
```python
result = %sql USE s2_dataset_martech; SELECT * FROM offers GROUP BY customer LIMIT 10
```
Combine SQL and Python in the same cell:
```python
result = %sql USE s2_dataset_martech; SELECT * FROM offers GROUP BY customer
df = pd.DataFrame(result)
```
## Manage Libraries
SingleStore notebooks come with pre-installed libraries, and you can install additional libraries as needed.
## Pre-installed Libraries
Run the following command in a Python cell to see the list of pre-installed libraries:
```python
!pip list
```
## Install and Import Libraries
SingleStore supports libraries available from . This example shows how to install a library from the [Kaggle open dataset](https://pypi.org/project/opendatasets/).
```python
!pip3 install opendatasets
```
To update the version of a pre-installed library:
```python
!pip3 install plotly --upgrade
```
Once a library is installed, you can import library components and add an alias:
```python
import opendatasets as od
```
> **💡 Tip**: For better clarity, have one cell at the beginning of the notebook with all additional libraries to install and have a second cell listing the libraries to import. You can then collapse the two cells to remove clutter.
## Magic Commands
For a specific cell, to see all the supported magic commands:
```python
%lsmagic
```
For information about the full list of available magic commands:
```python
%quickref
```
Some helpful magic commands:
| Magic Command | Description |
| ------------------ | ---------------------------------------------------------------- |
| %history | View the log of the session activity for the notebook. |
| %pinfo \ | Details of the object stored in the specified variable. |
| %time | Show the time of execution of a Python or SQL statement. |
| %who | List all of the currently defined variables within the notebook. |
## Useful Shortcuts
There are two modes in a notebook: command and edit. Command mode is activated by pressing ESC. Edit mode is activated by pressing Enter.
## Command and Edit Mode Shortcuts
| Task | Mac | Windows |
| ---------------------------------- | --------------- | ------------- |
| Run the current cell, select below | Shift + Enter | Shift + Enter |
| Run selected cells | Command + Enter | Ctrl + Enter |
| Run the current cell, insert below | Option + Enter | Alt + Enter |
| Save and checkpoint | Command + S | Ctrl + S |
## Command Mode Shortcuts
| Task | Mac | Windows |
| -------------------------------- | ------------------------ | ------------------------ |
| Enter edit mode | Enter | Enter |
| Select cell above | Up | Home |
| Select cell below | Down | End |
| Extend selected cells above | Shift + Up | Shift + Home |
| Extend selected cells below | Shift + Down | Shift + End |
| Insert cell above | A | A |
| Insert cell below | B | B |
| Cut selected cells | X | X |
| Copy selected cells | C | C |
| Paste cells below | V | V |
| Paste cells above | Shift + V | Shift + V |
| Move cell up | Ctrl + Shift + Up | Ctrl + Shift + Home |
| Move cell down | Ctrl + Shift + Down | Ctrl + Shift + End |
| Split cell | Ctrl + Shift + Minus (-) | Ctrl + Shift + Minus (-) |
| Delete selected cells | D, D (press twice) | D, D (press twice) |
| Undo cell operation | Z | Z |
| Redo cell operation | Shift + Z | Shift + Z |
| Merge selected cells | Shift + M | Shift + M |
| Merge cell above | Ctrl + Delete | Ctrl + Backspace |
| Merge cell below | Ctrl + Shift + M | Ctrl + Shift + M |
| Save and checkpoint | S | S |
| Change the cell type to Code | Y | Y |
| Change the cell type to Markdown | M | M |
| Scroll notebook up | Shift + Space | Shift + Space |
| Scroll notebook down | Space | Space |
| Find | Command + F | Ctrl + F |
| Find next | Command + G | Ctrl + G |
| Find previous | Shift + Command + G | Shift + Ctrl + G |
| Show line numbers | Shift + L | Shift + L |
| Render side-by-side | Shift + R | Shift + R |
## Edit Mode Shortcuts
| Task | Mac | Windows |
| ------------------ | ------------------- | ---------------- |
| Go to command mode | Esc | Esc |
| Select all cells | Command + A | Ctrl + A |
| Undo | Command + Z | Ctrl + Z |
| Redo | Shift + Command + Z | Shift + Ctrl + Z |
| Go to cell start | Command + Up | Ctrl + Home |
| Go to cell end | Command + Down | Ctrl + End |
| Go one word left | Command + Left | Ctrl + Left |
| Go one word right | Command + Right | Ctrl + Right |
***
Modified at: May 11, 2026
Source: [/cloud/container-services/notebooks/develop-with-notebooks/](https://docs.singlestore.com/cloud/container-services/notebooks/develop-with-notebooks/)
(An index of the documentation is available at /llms.txt)
---
# Github Integration for Notebooks
> **📝 Note**: This is a Preview feature.
GitHub integration for notebooks supports the use of Git workflows directly within the notebook environment. This integration allows you to commit notebook changes, track history, and push updates to connected GitHub repositories without switching tools.
Key features include:
* Create pull requests, add comments, view code diffs, and conduct code reviews.
* Reproduce notebook results by running and sharing exact versions of the notebook files.
* Collaborate with team members by sharing notebooks and integrating contributions.
* Connect notebook development to existing CI/CD pipelines.
## Connect a GitHub Account
1. In the [Cloud Portal](http://portal.singlestore.com), navigate to the bottom-left corner and select the organization name to open the menu. Select **User Integrations**.
2. In the **User Integrations** page, enable **GitHub**.
3. The page redirects to **GitHub**. Sign in using the GitHub credentials. If two-factor authentication (2FA) is enabled, complete the verification process to proceed.
4. Select the organization or account required to connect.
> **📝 Note**: SingleStore recommends selecting a personal GitHub account to complete the OAuth flow and enable the integration. A GitHub organization can be connected only by an Organization Admin. If the connecting account does not have admin privileges, a connection request is sent to the organization’s GitHub admin for approval. If a GitHub organization appears as **Configured**, it indicates that the integration has already been set up by another member of the organization. In this case, the organization is automatically added to the connected GitHub accounts once the OAuth flow is completed with a personal account.
5. Select the repositories required to grant access under the selected organization or account:
* To allow access to all repositories, select **All Repositories**.
* To limit access, select **Only select repositories**, and then select the desired repositories.
6. Select **Install & Authorize**.
7. After authorization completes, view the connected GitHub account under **Connected User**.
> **📝 Note**: Each user can connect only one GitHub account at a time. To connect a different account, the existing connection must be disabled first, and then a new connection can be established.
8. Navigate to the bottom-left corner and select the organization name to open the menu. Select **Organization Details > Integrations** in the Cloud Portal to view the GitHub integration and number of users. This page is accessible only to SingleStore organization owners. It can also be accessed from the info alert displayed on the **User Integrations** page visible to SingleStore organization owners only.
## Configure GitHub Integration
1. In the **User Integrations** page, under **GitHub**, select **Configure**.
2. In the **Configure GitHub Integration** dialog, under the **Actions** column of the selected GitHub account, select **Configure**. The dialog also displays any pending connection requests for GitHub organizations that require approval from the respective GitHub organization admins.
3. To install and authorize the GitHub integration for another GitHub account, select **Installation**.
## Load a Notebook from GitHub
1. Navigate to the **Editor**, and then select **New > Import** from GitHub.
2. Select the repository and branch that contains the notebook to import.
3. Select the notebook file.
4. Select the location of the notebook and then select **Import** to complete the process.
## GitHub Version Control
Once the notebook is imported, the synced GitHub connection can be viewed in the right-hand navigation. The following actions can be managed in GitHub version control:
* Fetch
* Commit & Push
## Fetch GitHub Content
To fetch the contents from Github repository, select **Fetch**. Compare the contents and select **Fetch**. Select **Confirm & Overwrite** to overwrite the current notebook version with the notebook content in GitHub repository.
## Commit and Push Notebook Changes
To commit and push the changes in the notebook to the GitHub repository, select **Commit & Push**. Compare the contents and select **Compare & Push**. In the **Push to GitHub** dialog, enter the following details:
| **Commit message** | Enter the commit message. |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **New branch name** | Enter the branch name if the changes are not being pushed to the default branch (main) used when connecting the notebook to the repository. |
Enable **Include Notebook Cell Outputs** if required and select **Commit & Push**.
## Enable the GitHub Connection
GitHub version control can be enabled for individual notebooks that were not initially imported via GitHub integration. Perform the following steps to enable the GitHub connection:
1. Open the desired notebook.
2. Select the GitHub icon on the right upper side. Select **Enable GitHub Version Control**.
3. In the **Upload & Push to GitHub** dialog, enter the following details:
| **Repository** | Select the repository in which the notebook will be uploaded. |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **New branch name** | Enter the branch name if the changes are not being pushed to the default branch (main) used when connecting the notebook to the repository. |
| **Commit message** | Enter the commit message. |
4. Enable **Include Notebook Cell Outputs** if required.
5. Enable **Overwrite existing file if it already exists at selected GitHub path** if required.
6. Select **Upload & Push** to upload the notebook in the selected GitHub repository.
To perform GitHub version control actions after uploading the notebook to the selected GitHub repository, refer to [GitHub Version Control](https://docs.singlestore.com/#section-id235248638096036.md).
## Disconnect the GitHub Connection
To disconnect the GitHub connection, select the ellipsis in the **GitHub Connection** and select **Disconnect**. The existing GitHub connection and the selected notebook is disconnected from the selected GitHub repository. This action does not delete or modify the notebook file in GitHub.
## Disable GitHub Integration
To disable GitHub integration, select **Organization Details > Integrations** in the Cloud Portal and disable GitHub in the **Availability** column. Select **Confirm and Disable** to proceed.
Only an Organization Admin can disable the GitHub integration. Even if users have the integration installed in their GitHub accounts, they cannot import notebooks into SingleStore Helios once the Organization Admin has disabled the integration.
***
Modified at: November 17, 2025
Source: [/cloud/container-services/notebooks/github-integration-for-notebooks/](https://docs.singlestore.com/cloud/container-services/notebooks/github-integration-for-notebooks/)
(An index of the documentation is available at /llms.txt)
---
# Load Dataframes From Notebooks
The simplest and fastest way to load data is using a pandas dataframe. However, the schema inference is not always optimal. Define the table and schema in advance to avoid having to make future schema alterations.
## Create a Dataset with Geospatial and Embeddings
Create a dataset with complex data types, such as, integer, date time, geospatial, and vectors.
Run the following command to install Shapely:
```python
!pip3 install shapely
```
Create the dataset:
```python
from shapely import wkt
import pandas as pd
import numpy as np
data = {
'Integer': [1, 2, 3, 4],
'Datetime': [pd.Timestamp(x) for x in ['2023-06-01', '2023-06-02', '2023-06-03', '2023-06-04']],
'Geospatial Data': [wkt.loads(x) for x in ['POLYGON((1 1,2 1,2 2, 1 2, 1 1))', 'POLYGON((5 1,6 1,6 2,5 2,5 1))', 'POLYGON((5 5,6 5,6 6,5 6,5 5))', 'POLYGON((1 5,2 5,2 6,1 6,1 5))']],
'Vectors': [np.array(x) for x in [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]]
}
df = pd.DataFrame(data)
display(df)
```
## Connecting to the Database
Select the Connection and the Database to use from the dropdown boxes at the top of the notebook.
```python
from sqlalchemy import *
db_connection = create_engine(connection_url)
```
## Check Table Schema
Check the schema for the table; it is not optimal since geospatial and embeddings data were interpreted as text by the engine.
```sql
%%sql
SELECT
TABLE_SCHEMA,
TABLE_NAME,
COLUMN_NAME,
COLUMN_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table_schema_inference' AND TABLE_SCHEMA = 'MyDatabase';
```
| COLUMN\_NAME | COLUMN\_TYPE |
| --------------- | ------------ |
| Integer | bigint(20) |
| Datetime | datetime |
| Geospatial Data | text |
| Vectors | text |
## Create a Table with the Correct Schema
Geospatial indexes are only supported with a rowstore table. Ensure the schema is correct and rowstore in the creation process:
```sql
%%sql
CREATE ROWSTORE TABLE `table_schema_defined` (
`Integer` bigint(20) DEFAULT NULL,
`Datetime` datetime DEFAULT NULL,
`Geospatial Data` GEOGRAPHY NOT NULL,
`Vectors` blob,
index (`Geospatial Data`)
)
```
With the changes made to the SingleStore Python client library, no extra steps are required to convert the data before inserting it into a database. All numpy arrays, shapely and pygeos geometry objects in a dataframe will be converted into the correct format automatically.
## Load the Dataframe Into the Predefined Table Schema
This method is fast but will not provide the best schema inference.
```sql
df.to_sql('table_schema_defined', con = db_connection, if_exists =
'append', index = False, chunksize = 1000)
```
## Verify the Data
Check that the geospatial and vector data have been correctly loaded.
```sql
%%sql
select * from table_schema_defined
```
***
Modified at: November 17, 2025
Source: [/cloud/container-services/notebooks/load-dataframes-from-notebooks/](https://docs.singlestore.com/cloud/container-services/notebooks/load-dataframes-from-notebooks/)
(An index of the documentation is available at /llms.txt)
---
# Notebook Version History
The Version History feature allows users to view and compare visual differences between two notebook versions. It provides a Git-like experience directly within the notebook interface. This feature displays a chronological list of all saved versions with timestamps, which makes it easy to track a notebook's evolution. By visually highlighting changes, Version History reduces the risk of data loss and eliminates the need for manual version management, such as duplicating notebooks at various stages. It streamlines version tracking and simplifies understanding the notebook's development over time.
## View the Notebook Version History
To view the version history in the notebook, select the clock icon to select **Version History**.

## Compare Versions
By default, the **Compare Version** toggle is on. To compare two versions, toggle on **Compare Version** and select the versions you want to compare. When you toggle off **Compare Version**, you can view the selected version on the right side of the panel in its complete n
otebook format, including the outputs.

The side-by-side visual differences are displayed between the two versions. You can also view the versions with timestamps in the Version History (right navigation) pane. In the version selection list, the **Current** option shows the last saved notebook contents, while the **Version History** pane shows the most recently created version from the version history. These versions are not the same, as new versions are created every 2 minutes.

## Version Retention Policy
* A new version is created when changes are made and two minutes have passed since the previous version was created.
* All versions created on the current day are retained.
* For versions created on previous days, only the oldest version for each day is retained, up to a maximum of 30 days.
* Versions older than 30 days are not retained.
* To preserve a specific version, SingleStore recommends adding it to your favorites list on the day you create the version.
> **📝 Note**: New versions are auto-created only when changes occur.
## Manage Versions
You can view details, edit details, add to favorites, remove from favorites, duplicate, restore, and delete a version of the notebook in the **Version History** pane.
## View Version Details
To view the details of a version of the notebook, select the ellipsis (three dots) in the selected version, and select **View Details**. You can view the version name, the name of the user who created it, the timestamp of its creation, and the description.

## Edit Version Details
To edit the details of a notebook version, select a version in the **Version History** pane. Select the ellipsis (three dots) in the selected version, and select **Edit Details**.

In the **Edit Version Details** dialog, enter the **Version Name** and **Description**.

## Add a Version to Favorites
To bookmark a notebook version, select a version in the **Version History** pane and click on the star icon next to the selected version to add it to **Favorites**. After adding a version to favorites, a list of bookmarks (favorite versions) is displayed under **Favorites**, above **Version History**, in the **Version History ** pane. To permanently keep a version, transfer it to the **Favorites** list, which has a limit of 10 versions. However, versions in **Favorites** are always retained. To add an 11th version to **Favorites**, you must delete or remove an existing version.

## Remove a Version from Favorites
Select a version in the **Version History** pane and tap on the star icon to remove it from **Favorites**.
## Duplicate a Version
To duplicate a version of the notebook, select a version in the **Version History** pane. Select the ellipsis (three dots) in the selected version, and select **Duplicate Version**. In the **Duplicate from \** dialog, enter the name in **Notebook Name** and the location, either Shared or Personal, and select **Duplicate Notebook**.

## Restore a Version
To restore a version of the notebook, select a version in the **Version History** pane. Select the ellipsis (three dots) next to the selected version, and select **Restore Version**. Alternatively, you can restore a version by selecting the **Restore Version** button at the bottom.
> **📝 Note**: Restoring a version replaces the current contents of the notebook with the version you selected.

## Delete a Version
To delete a version of the notebook, select a version in the **Version History** pane. Select the ellipsis (three dots) in the selected version, and select **Delete version**.
***
Modified at: November 17, 2025
Source: [/cloud/container-services/notebooks/notebook-version-history/](https://docs.singlestore.com/cloud/container-services/notebooks/notebook-version-history/)
(An index of the documentation is available at /llms.txt)
---
# Running a Notebook from Another Notebook using Fusion SQL
SingleStore Notebooks support running one notebook from another using [Fusion SQL](https://docs.singlestore.com/cloud/reference/fusion-sql.md), either within the same session or in a new session. This is useful when you want to:
* Avoid code duplication such as reusable functions or environment setup by running the shared logic in a separate notebook.
* Run code in parallel by executing notebooks in separate sessions.
## Create a Sample Notebook
You can create a sample notebook in one of two ways:
* On the [Cloud Portal](https://portal.singlestore.com/) select **New** > **New Notebook **> **Shared**.
* Run the following Python code in a notebook:
```python
import nbformat as nbf
nb = nbf.v4.new_notebook()
cell = nbf.v4.new_code_cell("""# This is a code cell
if 'sample_var' not in globals():
sample_var = 'sample value'
print('Sample Notebook has been executed!')""")
cell.metadata = {
"language": "python"
}
nb.cells.append(cell)
# Save the notebook to a file
with open('sample_notebook.ipynb', 'w') as f:
nbf.write(nb, f)
print("Notebook 'sample_notebook.ipynb' created successfully in the local filesystem.")
```
## Example Notebook
The following notebook shows how to run a notebook from another notebook with Fusion SQL:
## Upload the Notebook to Shared Notebooks in the Editor
This step generates a unique notebook name by appending a timestamp to the notebook filename to avoid naming conflicts.
Skip this step if you already created a Shared notebook via the UI in the first step.
```python
import time
sample_notebook_name='Sample Notebook {}.ipynb'.format(int(time.time()
* 1_000_000))
%sql UPLOAD SHARED FILE TO '{{ sample_notebook_name }}'
FROM 'sample_notebook.ipynb';
print("Notebook '{}' has been created in the Editor shared
files.".format(sample_notebook_name))
```
## Run the Notebook in the Current Session
Use `%run_shared` to execute the sample notebook in the current session. Confirm that the `sample_var` variable set in the sample notebook is accessible in the current session.
```python
if 'sample_var' in globals():
del sample_var
%run_shared {{ sample_notebook_name }}
print("The value of 'sample_var' is '{}'.\n".format(sample_var))
```
**Note**: If you created the shared notebook via the UI, replace `sample_notebook_name` in the code above with the actual notebook name in single quotes:
```python
% run_shared {{ 'Sample Notebook.ipynb' }}
```
## Run the Sample Notebook in a New Session
You can also run the sample notebook **in a new session** using jobs. This allows you to execute multiple notebooks in parallel using `RUN JOB USING NOTEBOOK`.
Refer to [RUN JOB USING NOTEBOOK](https://docs.singlestore.com/cloud/reference/fusion-sql/run-job-using-notebook.md) for syntax and more information.
```python
job_ids = []
for x in range(2):
print("Running job for {}...".format(x))
job_res = %sql RUN JOB USING NOTEBOOK '{{ sample_notebook_name }}' WITH PARAMETERS {"sample_var": "{{x}}"}
job_ids.append(job_res[0].JobID)
print(f'Waiting for jobs to complete... {job_ids}')
success = %sql WAIT ON JOBS {{ job_ids }} WITH TIMEOUT 60 MINUTES
print(f'All jobs completed with success: {bool(success[0].Success)}')
```
**Note**: If you created the shared notebook via UI, replace `sample_notebook_name` in the code with your notebook name in single quotes (no brackets):
```sql
%sql RUN JOB USING NOTEBOOK 'Sample Notebook.ipynb' WITH PARAMETERS {"sample_var": "{{x}}"}
```
## View Job Executions
Use `SHOW JOB EXECUTIONS` to inspect job runs.
```python
for job_id in job_ids:
execs = %sql SHOW JOB EXECUTIONS FOR {{ job_id }} from 1 to 1
print(execs)
```
## Delete the Jobs
Use `DROP JOBS` to delete the jobs.
```python
for id in job_ids:
print(f"Dropping job '{id}'...")
%sql DROP JOBS {{id}}
```
**Note**: You can also view, inspect, and delete jobs from the **Jobs** section in the left navigation on the Cloud Portal. Refer to [Scheduling Notebooks with SingleStore Job Service](https://docs.singlestore.com/cloud/container-services/scheduled-jobs.md) for more information.
## Delete the Sample Notebook
Delete the sample notebook using `DROP SHARED FILE`, or via the Cloud Portal by selecting **Delete** from the **Actions** column for your notebook.
```sql
%%sql
DROP SHARED FILE '{{ sample_notebook_name }}'
```
***
Modified at: May 19, 2026
Source: [/cloud/container-services/notebooks/running-a-notebook-from-another-notebook-using-fusion-sql/](https://docs.singlestore.com/cloud/container-services/notebooks/running-a-notebook-from-another-notebook-using-fusion-sql/)
(An index of the documentation is available at /llms.txt)
---
# Using Notebooks
SingleStore Helios supports Jupyter Notebooks for development using SQL and Python.
## Import and Run Notebooks
> **💡 Tip**: **Get Started Quickly**: Notebooks in SingleStore Helios are Jupyter notebooks and if you are familiar with how to use them, you can jump right in and get started. You can access a collection of notebooks in the Gallery, where you can find how-to guides, tutorials, and getting-started information.
## Import Notebooks
To access Notebooks on the [Cloud Portal](https://portal.singlestore.com) , select **Editor**. There are multiple ways to get started using notebooks:
* **New Notebook**: Start with a new notebook (select **New > New Notebook**) or use a beginner notebook template such as "SingleStoreDB Notebook Basics" (recommended).
* **Import Notebook**: Select **New > Import From File** to import a notebook from your local machine using the **Import file** dialog. Notebook files must be in Jupyter format (`.ipynb`) and the file must not exceed 5GB in size.
* **Gallery**: Select the **Gallery** tab to find how-to guides, tutorials, and getting-started notebooks. If you are new to notebooks, SingleStore recommends using the `beginner` flag and taking a look at the "SingleStoreDB Notebook Basics" or "Getting Started with Notebooks" notebooks. Use labels to filter the notebooks in Gallery. To use or explore a notebook, select the notebook, and then select **Try It Now**. Once opened, this notebook is saved and accessible from the **Recent** and **Personal** tabs on the **Editor** page.
## Run Notebooks
You can run a notebook on the Cloud Portal using any of the following methods.
## Using the Notebooks UI
To run a notebook using the Notebooks UI,
1. Open the notebook on the Cloud Portal.
2. Select a SingleStore deployment, database, and available runtime to run the notebook.
3. Use the available options in the **Run** menu to run the selected cells or all the cells in the notebook.
## Using Fusion SQL Commands in a Notebook Cell
Use the `RUN JOB USING NOTEBOOK` Fusion SQL command in a notebook cell to run another notebook. For example:
```sql
RUN JOB USING NOTEBOOK 'example_notebook.ipynb'
WITH RUNTIME 'notebooks-cpu-small';
```
Refer to [RUN JOB USING NOTEBOOK](https://docs.singlestore.com/cloud/reference/fusion-sql/run-job-using-notebook.md) for more information on this Fusion SQL command.
Optionally, explore the [Running Notebooks from Another Notebook with Fusion SQL](https://www.singlestore.com/spaces/running-notebooks-from-another-notebook-with-fusion-sql/) notebook for an end-to-end example of running a notebook from a different notebook.
## Manage Notebooks
You can perform the basic, non-development notebook tasks such as find, share, create, open/edit, delete, and rename.
## Shared and Personal Tabs
Notebooks are stored in either the **Shared** or **Personal** tabs in SingleStore Helios. Notebooks stored in the Shared tab are accessible by any member of the organization.
Notebooks stored in the Personal tab are only visible to the notebook creator and cannot be shared.
## Create or Open/Edit a Notebook
To create a notebook:
1. From **New**, select **New Notebook**.

2. Enter a name for the notebook.
3. Select a location ([Personal or Shared](https://docs.singlestore.com/#section-idm4531404441417633540186021063.md)) for the notebook.
4. Select a template from the template list. To create an empty notebook, select **(Blank Notebook)**.
5. Select **Create**.

To open (or edit) an existing notebook, select the notebook in the list of notebooks.
## Save a Notebook
Notebooks are automatically saved (autosave) every 5 seconds.
## Share a Notebook
All users within the same organization have access to the notebooks that are located in the **Shared** tab.
To share a notebook, navigate to the **Shared** tab, select **Copy Link** from the (three-dot) under the **Actions** column for your notebook. Share the link with other users in the same organization.
To share a notebook , navigate to the **Personal** tab, [duplicate](https://docs.singlestore.com/#section-idm4498060002691233569399455212.md) the notebook and change the location to a **Shared** tab.
## Rename a Notebook
To rename a notebook, select **Rename** from the (three-dot) under the **Actions** column for your notebook
## Duplicate a Notebook
To duplicate a notebook, select **Duplicate** from the (three-dot) under the **Actions** column for your notebook.
Enter a name for the notebook and select a location. If you duplicate a notebook from the Personal tab to a Shared tab, the new notebook will not be private.
## Delete a Notebook
To delete a notebook, select **Delete** from the (three-dot) under the **Actions** column for your notebook
***
Modified at: May 25, 2026
Source: [/cloud/container-services/notebooks/using-notebooks/](https://docs.singlestore.com/cloud/container-services/notebooks/using-notebooks/)
(An index of the documentation is available at /llms.txt)
---
# Python UDFs
> **📝 Note**: This is a Preview feature.
A Python User-Defined Function (UDF) is an external function that allows you to execute Python code outside of the SingleStore engine's process. It enables you to extend SingleStore with custom Python logic in a SingleStore Notebook. Python UDFs are especially useful when you need to integrate with AI applications, machine learning (ML) models and perform vector operations with libraries like NumPy, Pandas, Polars, or call external APIs.
## Prerequisites
To enable Python UDFs in the SingleStore deployment, ensure the following:
* **SingleStore Version**: SingleStore version 8.9 or later.
* **Environment**: The SingleStore deployment must run in an AWS EKS IRSA-supported environment.
After ensuring, contact [SingleStore Support](http://support.singlestore.com) to enable this feature for your organization.
## Publish a Python UDF
## Create a Python UDF
Python UDFs can be created in Shared notebook only. Python UDFs are not supported for Shared Edition clusters. Python UDFs can only be installed per individual database, which requires a Standard or Enterprise cluster.
To create a new Python UDF, perform the following steps:
1. In the left navigation, select **Editor > Shared**.
2. Create or open a shared notebook.
3. Select **Publish** (on the top right).
## New Python UDF
After selecting **Publish**, a new dialog box appears.
**Publish Settings**
| **Publish as** | Select**Python UDF**. |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | Enter a name of the Python UDF. |
| **Description** | Enter the Python UDF description. |
| **Notebook** | Select a shared notebook to publish as a Python UDF. The shared notebook is pre-selected when the Python UDF is published through notebooks. |
| **Deployment** | Select theSingleStoredeployment (cluster) the notebook connects to.Selecting aclusterallows connecting to theSingleStoredatabases referenced in the notebook natively. |
| **Runtime** | Select a runtime from the following: 📝 Note:
This field is in preview.
|
| **Region** | Select a region. |
| **Idle Timeout** | Select an idle timeout. 📝 Note:
This field is in preview.
|
Select **Next**.
Select **Publish** to publish the notebook as Python UDF. Once the Python UDF is published, call the function using SQL Editor.
> **📝 Note**: Python UDF names must be unique. If you attempt to create a Python UDF with a name that already exists, the system returns a "Duplicate UDF Function Name" error. To update an existing Python UDF, delete the existing UDF from Container Services and then create the new Python UDF with the same name.
## Example Notebook
The following notebook shows how to publish your first Python UDF:
## Manage an Existing Python UDF
To view an existing Python UDF, select **Python UDFs** in the left navigation. Existing Python UDFs can be managed by performing the following actions:
* View
* Update
* Delete
## View an Existing Python UDF
To view an existing Python UDF, select the Python UDF from the **Name** column. Following actions can be performed for a dashboard app from this page:
* View Live Logs
* Update
* Delete
## View Live Logs
To view live logs of the selected Python UDF, select **View Live Logs** from the ellipsis on the right side. A new window appears, where the **Timestamp** and the message in the **Body** column can be viewed. View the **Log JSON** by selecting the eye icon.
## Update an Existing Python UDF
To update an existing Python UDF, select the ellipsis in the Actions column of the Python UDF, and select **Update**.
## Delete an Existing Python UDF
To delete an existing Python UDF, select the ellipsis in the **Actions** column of the Python UDF, and select **Delete**.
## Status of Python UDF
| Status | Description |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Initializing | The notebook is creating or updating the Python UDF. |
| Active | The notebook is successfully published as a Python UDF. |
| Failed | The Python UDF is not configured correctly. View the notebook snapshot to debug the failure. |
| Error | An error unrelated to the notebook code prevented the Python UDF from initializing. Refer to[Troubleshoot Python UDFs](https://docs.singlestore.com/#section-id23547459240214.md). |
## Troubleshoot Python UDFs
SingleStore automatically saves a snapshot of the notebook for each failed execution. Navigate to **Container Services** in the left navigation, select the Python UDF, and download the snapshot associated with the failed Python UDF to diagnose the error.
| Error | Solution |
| ---------------------------- | --------------------------------------------------------------------------------------------------------- |
| ClusterDeleted | Update the Python UDF and select a different deployment. |
| ClusterSuspended | Resume theclusteror create a new Python UDF with a different deployment. |
| Database Detached | Reattach the database with the right permissions or create a new Python UDF with a different database. |
| Notebook Deleted/Not Present | Create a new Python UDF with a different notebook. |
| Internal Errors/Misc | Contact[SingleStore Support](http://support.singlestore.com/)or use the chat feature in the Cloud Portal. |
## Defining Python UDFs
Each Python UDF must meet the following requirements:
1. The function's parameters and return types must be annotated.
2. The function must be wrapped with the `@udf` decorator, which is located in `singlestoredb.functions`.
The `@udf` decorator is a critical component, as it automatically analyzes the type annotations to map Python data types to SingleStore data types. The mapping is subsequently used to generate the necessary `CREATE EXTERNAL FUNCTION` statement in the SingleStore database, ensuring a reliable connection between the Python code and the SQL queries. Refer to [Equivalent Data Types](https://docs.singlestore.com/cloud/container-services/python-udfs/working-with-python-udfs/#section-id235163203492027.md) for related information.
There are two main types of Python UDFs, defined by the type annotations:
* Scalar
* Vectorized
## Scalar Python UDFs
Scalar Python UDFs are defined with standard Python type annotations, such as `int`, `float`, or `str`. When called from the database, the Python UDF server receives a batch of rows, but the Python UDF itself is invoked once for each individual row of data. This is useful in complex logic with individual records.
The following example demonstrates a scalar Python UDF:
```python
from singlestoredb.functions import udf
import singlestoredb.apps as apps
@udf
async def multiply(x: float, y: float) -> float:
return x * y
# Start Python UDF server
connection_info = await apps.run_udf_app()
print("UDF server running. Connection info:", connection_info)
```
This creates the following external function:
```sql
CREATE EXTERNAL FUNCTION multiply(x DOUBLE NOT NULL, y DOUBLE NOT NULL)
RETURNS DOUBLE NOT NULL
AS REMOTE SERVICE "http:////invoke" FORMAT ROWDAT_1;
```
Use `async def` for improved cancellation handling.
Invoke the scalar Python UDF using the following command:
```sql
SELECT multiply(5.0, 10.0) AS result;
```
```output
+-----------------------+
| result |
+-----------------------+
| 50.0 |
+-----------------------+
```
## Vectorized Python UDFs
Vectorized Python UDFs are defined with vector type annotations, such as `numpy.ndarray`, `pandas.Series`, `polars.Series`, or `pyarrow.Array`. The Python UDF is called only once for each batch of rows received from the SingleStore database. The entire batch is converted into vectorized inputs, where each column of data corresponds to a single vector object passed as a function parameter. This is useful in high-performance numerical processing.
The following example demonstrates a vectorized Python UDF.
```python
import numpy as np
import numpy.typing as npt
from singlestoredb.functions import udf
@udf
async def vec_multiply(
x: npt.NDArray[np.float64],
y: npt.NDArray[np.float64]
) -> npt.NDArray[np.float64]:
return x * y
# Start Python UDF server
import singlestoredb.apps as apps
connection_info = await apps.run_udf_app()
```
This creates the following external function:
```sql
CREATE EXTERNAL FUNCTION vec_multiply(x DOUBLE NOT NULL, y DOUBLE NOT NULL)
RETURNS DOUBLE NOT NULL
AS REMOTE SERVICE "http:////invoke" FORMAT ROWDAT_1;
```
Invoke the vectorized Python UDF using the following command:
```sql
SELECT vec_multiply(vec_col1, vec_col2)AS result;
```
```output
+-------------------+
| result |
+-------------------+
| [4.0, 10.0, 18.0] |
+-------------------+
```
Where `vec_col1 = [1,2,3]` and `vec_col2 = [4,5,6]`.
## Scalar Python TVFs
Scalar Python TVFs are defined in the same way as scalar Python UDFs, except that a scalar TVF uses a `Table` annotation to indicate that the function returns a table. The function must also return the final result wrapped in a `Table` object.
The following example demonstrates a scalar Python TVF:
```python
import numpy as np
import numpy.typing as npt
from singlestoredb.functions import udf, Table
@udf
async def number_stats(
n: npt.NDArray[np.int_],
) -> Table[npt.NDArray[np.int_], npt.NDArray[np.int_], npt.NDArray[np.float64]]:
numbers = np.arange(1, n[0] + 1, dtype=np.int_)
squares = numbers ** 2
roots = np.sqrt(numbers).round(2)
return Table(numbers, squares, roots)
# Start Python UDF server
import singlestoredb.apps as apps
connection_info = await apps.run_udf_app()
```
This creates the following external function:
```sql
CREATE EXTERNAL FUNCTION
`number_stats`(`n` BIGINT NOT NULL)
RETURNS TABLE(
`numbers` BIGINT NOT NULL,
`squares` BIGINT NOT NULL,
`roots` DOUBLE)
AS REMOTE SERVICE "http:////invoke" FORMAT ROWDAT_1;
```
Invoke the scalar Python TVF using the following command:
```sql
SELECT * FROM number_stats([5]);
```
```output
+---------+---------+-------+
| numbers | squares | roots |
+---------+---------+-------+
| 1 | 1 | 1.00 |
| 2 | 4 | 1.41 |
| 3 | 9 | 1.73 |
| 4 | 16 | 2.00 |
| 5 | 25 | 2.24 |
+---------+---------+-------+
```
SingleStore automatically generates generic column names if no names are associated with the return fields (`numbers`, `squares`, and `roots` in this example). Explicitly name result columns using overrides or schema classes. Refer to [Overriding Parameters and Return Value Types](https://docs.singlestore.com/cloud/container-services/python-udfs/working-with-python-udfs/#section-id235163211595581.md) for related information.
## Vectorized Python TVFs
Vectorized Python TVFs return a table of results. Unlike Python UDFs, which are invoked for each row in a query, a TVF is invoked once with a set of parameters and returns multiple rows and columns. In a vectorized Python TVF, each returned vector represents a column in the output table. The length of each vector determines the number of rows returned.
The following example demonstrates a vectorized Python TVF:
```python
import numpy as np
import numpy.typing as npt
from singlestoredb.functions import udf, Table
@udf
async def vec_table_function(
n: npt.NDArray[np.int_],
) -> Table[npt.NDArray[np.int_], npt.NDArray[np.float64], npt.NDArray[np.str_]]:
x = np.array([10] * n[0], dtype=np.int_)
y = np.array([10.0] * n[0], dtype=np.float64)
z = np.array(['ten'] * n[0], dtype=np.str_)
# Returns a tuple of vectors (each column of the output)
return Table(x, y, z)
# Start Python UDF server
import singlestoredb.apps as apps
connection_info = await apps.run_udf_app()
```
This creates the following external function:
```sql
CREATE EXTERNAL FUNCTION
`vec_table_function`(`n` BIGINT NOT NULL)
RETURNS TABLE(
`x` BIGINT NOT NULL,
`y` DOUBLE NOT NULL,
`z` TEXT NOT NULL
)
AS REMOTE SERVICE "http:////invoke" FORMAT ROWDAT_1;
```
Invoke the vectorized Python TVF using the following command:
```sql
SELECT * FROM vec_table_function([1]);
```
```output
+----+------+-----+
| x | y | z |
+----+------+-----+
| 10 | 10.0 | ten |
+----+------+-----+
```
SingleStore automatically generates generic column names if no names are associated with the return fields (`x`, `y`, `z`). Explicitly name result columns using overrides or schema classes. Refer to [Overriding Parameters and Return Value Types](https://docs.singlestore.com/cloud/container-services/python-udfs/working-with-python-udfs/#section-id235163211595581.md) for related information.
## In this section
* [Working with Python UDFs](https://docs.singlestore.com/cloud/container-services/python-udfs/working-with-python-udfs.md)
***
Modified at: August 4, 2026
Source: [/cloud/container-services/python-udfs/](https://docs.singlestore.com/cloud/container-services/python-udfs/)
(An index of the documentation is available at /llms.txt)
---
# Working with Python UDFs
## Equivalent Data Types
When defining Python UDFs, input parameters and return values must be mapped between Python and SingleStore data types. The framework automatically infers these mappings from type annotations, but they can be overridden if necessary.
Following are the default Python to SingleStore mappings:
| **Python Type** | **SingleStoreType** |
| --------------- | ------------------- |
| `int` | `BIGINT` |
| `float` | `DOUBLE` |
| `str` | `TEXT` |
| `bytes` | `BLOB` |
| `bool` | `BOOL` |
For finer control, use the `singlestoredb.functions.dtypes` module to specify types such as `SMALLINT`, `VARCHAR`, `DECIMAL`, or `JSON`.
## Handling NULL Values
By default, Python UDFs and TVFs do not allow `NULL` values. The method for enabling `NULL` support depends on whether the Python function is scalar or vectorized.
## Scalar Python Functions (UDFs and TVFs)
* Use `Optional[...] `(or `type` | `None` in Python 3.10+) to allow parameters and return values to accept `NULL`.
* This makes the entire parameter or return value nullable.
* If any argument is `NULL`, the function can return `NULL` as needed.
## Vectorized Python Functions (UDFs and TVFs)
* `Optional[...]` cannot be used for element-level NULLs inside vectors.
* Instead, use the `Masked` annotation for parameters and return values that must support `NULL`.
* A `Masked` value consists of:
* A data vector containing the non-NULL values.
* A boolean mask vector, where `True` indicates a `NULL` element.
* This ensures that `NULL` values are preserved and propagated correctly across inputs and outputs.
* In Python TVFs, each output column can independently use `Masked` to indicate nullability.
## Overriding Parameter and Return Value Types
You can specify an output schema using the `returns=` parameter in the `@udf` decorator. This schema can be defined as:
* A list of SQL types with `name=` specified, or
* A `NamedTuple`, `TypedDict`, or `pydantic.BaseModel`.
The schema class is automatically inferred and it does not need to be returned explicitly, it is only used to define the output schema.
## Cancelling Running Python UDFs
When a query that uses a Python UDF is cancelled or when the connection between the database engine and the Python UDF server is broken, the Python UDF execution continues until it can be safely interrupted.
* **Synchronous Python UDFs**
* **Scalar Python UDFs**: Cancellation can only occur between row function calls.
* **Vectorized Python UDFs**: Cancellation occurs only after all rows in the current batch are processed.
* **Asynchronous Python UDFs**
* Cancellation is detected more quickly.
* When a disconnect is detected, an `asyncio.CancelledError` is raised the next time the Python UDF becomes active.
* If synchronous operations are used inside an `async` Python UDF, they must complete before cancellation occurs.
* Nested async calls are cancelled as soon as they activate again.
SingleStore recommends using `async` before the function definition for better cancellation handling.
> **📝 Note**: Use asynchronous Python UDFs and `async` libraries wherever possible to ensure that Python UDFs can be cancelled promptly.
## Timeouts
A timeout can be applied directly in the `@udf`decorator using the `timeout=` parameter.
* The value must be specified in seconds.
* If the timeout period is exceeded, the Python UDF is cancelled automatically.
## User Permissions
To allow users other than the organization owner to execute Python UDFs or TVFs, the organization owner must grant the appropriate permissions. These permissions are applied within the customer’s cluster using the SQL Editor.
## Required Permissions
1. `EXECUTE` (Object-Level Permission)
* Required to execute a function in a specific database.
* Can be granted on all functions in a database or a specific function.
* Following example demonstrates the syntax:
```sql
GRANT EXECUTE ON . TO 'user'@'%';
```
2. `OUTBOUND` (Global Permission)
* Required to allow functions to make external network requests.
* Must be granted globally.
* Following example demonstrates the syntax:
```sql
GRANT OUTBOUND ON *.* TO 'user'@'%';
```
> **📝 Note**: Both permissions must be granted to ensure the user can execute Python UDFs or TVFs successfully. Without these permissions, execution may fail due to insufficient privileges.
## Examples
## Example 1: Calculate Sales Metrics with Vectorized Python TVFs
This example demonstrates a vectorized Python TVF that computes total and average sales per row and returns a table with named columns.
```python
import typing
import numpy as np
import pandas as pd
from singlestoredb.functions import udf, Table
import numpy.typing as npt
# Define output schema using NamedTuple
class SalesOutput(typing.NamedTuple):
total_sales: float
average_sales: float
category: str
@udf(returns=SalesOutput)
async def vector_sales(
units_sold: npt.NDArray[np.float64], # Vector of units sold
unit_price: npt.NDArray[np.float64], # Vector of unit prices
category: npt.NDArray[np.str_] # Vector of categories
) -> Table[pd.DataFrame]:
"""
Calculate total and average sales per row with category.
Parameters
----------
units_sold : np.ndarray[np.float64]
Number of units sold
unit_price : np.ndarray[np.float64]
Price per unit
category : np.ndarray[str]
Category name for each row
Returns
-------
pd.DataFrame
Table with columns:
- total_sales
- average_sales
- category
"""
# Compute vectorized total and average
total_sales = units_sold * unit_price
average_sales = total_sales / np.maximum(units_sold, 1) # Avoid divide by zero
# Return as a DataFrame with named columns
df = pd.DataFrame({
'total_sales': total_sales,
'average_sales': average_sales,
'category': category
})
return Table(df)
# Start Python UDF server
import singlestoredb.apps as apps
connection_info = await apps.run_udf_app()
```
This results in the following external function:
```sql
CREATE EXTERNAL FUNCTION `vector_sales`(
`units_sold` DOUBLE NOT NULL,
`unit_price` DOUBLE NOT NULL,
`category` TEXT NOT NULL
)
RETURNS TABLE(
`total_sales` DOUBLE NOT NULL,
`average_sales` DOUBLE NOT NULL,
`category` TEXT NOT NULL
)
AS REMOTE SERVICE "http:////invoke" FORMAT ROWDAT_1;
```
## Example 2: Vector Embeddings
This example demonstrates a Python UDF that can connect to any deployed embedding service in SingleStore Aura.
```python
import base64
import sys
import numpy as np
import requests
import numpy.typing as npt
from singlestoredb.functions import udf
# Configuration for the embedding service
MODEL_NAME = 'name-of-embedding-service'
MODEL_URL = 'url-of-embedding-server'
TOKEN = 'api-token-of-embedding-service'
HEADERS = {
'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': f'Bearer {TOKEN}',
}
@udf
async def mixedbread_embeddings(
text: npt.NDArray[np.str_], # Input: array of strings
) -> npt.NDArray[np.bytes_]: # Output: array of bytes
"""
Generate vector embeddings for an array of text inputs.
Parameters
----------
text : numpy.ndarray
Array of input strings
Returns
-------
numpy.ndarray
Array of byte embeddings
"""
# Send request to embedding service
res = requests.post(
MODEL_URL,
headers=HEADERS,
json=dict(
model=MODEL_NAME,
input=text.tolist(),
encoding_format='base64',
),
)
# Raise an error if the request failed
if res.status_code >= 400:
print(res.content.decode('utf8'), file=sys.stderr)
raise RuntimeError(res.content.decode('utf8'))
# Decode embeddings and return as a NumPy array of bytes
return np.array(
[base64.b64decode(x['embedding']) for x in res.json()['data']],
dtype=object, # Preserve byte arrays correctly
)
# Start Python UDF server
import singlestoredb.apps as apps
connection_info = await apps.run_udf_app()
```
This results in the following external function:
```sql
CREATE EXTERNAL FUNCTION `mixedbread_embeddings`(`text` TEXT NOT NULL)
RETURNS BLOB NOT NULL
AS REMOTE SERVICE "base-url-of-udf-server-including-port"
FORMAT ROWDAT_1;
```
## Example 3: OpenAI Integration with Structured Output
This example demonstrates a Python table-valued function (TVF) that returns structured output using a `pydantic.BaseModel`. The function takes a word as input and returns 10 synonyms along with a score indicating how close each synonym is to the original word.
```python
import os
from typing import List
from pydantic import BaseModel, Field
from singlestoredb.functions import udf, Table
import instructor
from openai import OpenAI
# Create OpenAI client via instructor wrapper
client = instructor.from_openai(OpenAI(api_key=os.getenv("OPENAI_API_KEY")))
# Define output schema
class Synonym(BaseModel):
word: str = Field(description='Synonym of the given word')
score: float = Field(
description='Closeness score from 0.0 to 1.0'
)
# Define the TVF
@udf
async def get_synonyms(word: str) -> Table[List[Synonym]]:
"""Return a list of synonyms of the given word and a score."""
return Table(client.create(
model='gpt-4o-mini',
messages=[
dict(role='system', content='You are a helpful assistant'),
dict(
role='user',
content=f'''
* Get a list of synonyms of the word "{word}"
* Limit the number of results to 10
'''
)
],
response_model=List[Synonym],
max_retries=0,
))
# Start Python UDF server
import singlestoredb.apps as apps
connection_info = await apps.run_udf_app()
```
This results in the following external function:
```sql
CREATE EXTERNAL FUNCTION
`get_synonyms`(`word` TEXT NOT NULL)
RETURNS TABLE(
`word` TEXT NOT NULL,
`score` DOUBLE NOT NULL
)
AS REMOTE SERVICE "http:////invoke" FORMAT ROWDAT_1;
```
Run the following command to retrieve the synonyms of the word “danger”.
```sql
SELECT * FROM get_synonyms('danger');
```
The command results the following:
```sql
word score
0 hazard 0.90
1 risk 0.85
2 threat 0.88
3 peril 0.90
4 jeopardy 0.87
5 threatening 0.80
6 threatening situation 0.70
7 threatened 0.75
8 insecurities 0.60
9 unsafe 0.65
```
## Example 4: Machine Learning Model Scoring
This example demonstrates how to use a pre-trained Keras model stored in [Stage](https://docs.singlestore.com/cloud/load-data/load-data-from-files/stage.md) to score a collection of input parameters.
```python
import numpy as np
import pandas as pd
import numpy.typing as npt
import singlestoredb.notebook as nb
from tensorflow.keras.models import load_model
from singlestoredb.functions import udf
# Download model from Stage
nb.stage.download_file('my_model.keras', local_path='my_model.keras')
# Load the model
model = load_model('my_model.keras')
@udf
async def keras_score(
param_1: npt.NDArray[np.float32],
param_2: npt.NDArray[np.float32],
param_3: npt.NDArray[np.float32],
) -> npt.NDArray[np.float32]:
"""
Score rows using a Keras model.
Parameters
----------
param_1 : np.ndarray[np.float32]
First input parameter.
param_2 : np.ndarray[np.float32]
Second input parameter.
param_3 : np.ndarray[np.float32]
Third input parameter.
Returns
-------
np.ndarray[np.float32]
Predicted scores from the model.
"""
X_test = pd.DataFrame({
'param_1': param_1,
'param_2': param_2,
'param_3': param_3
})
return model.predict(X_test).reshape((-1,))
# Start Python UDF server
import singlestoredb.apps as apps
connection_info = await apps.run_udf_app()
```
## Example 5: Overriding Types with dtypes
By default, Python types map to general SQL types (for example, `int` maps to `BIGINT`). Refer to [Equivalent Data Types](https://docs.singlestore.com/#section-id235163203492027.md) for related information. Use types from `singlestoredb.functions.dtypes` to override these defaults and define precise SQL signatures.
Pass these types to the `@udf(args=[...], returns=...)` decorator. The following examples show how to override default type mappings:
* Use `SMALLINT` for integer inputs and outputs
This example overrides the default `BIGINT` mapping for Python `int` by explicitly using `SMALLINT`. Use this approach when it is required to match an existing schema that uses smaller integer types.
```python
from singlestoredb.functions import udf
from singlestoredb.functions.dtypes import SMALLINT
@udf(
args=[SMALLINT(nullable=False)],
returns=SMALLINT(nullable=False),
)
def double_small(x: int) -> int:
return x * 2
```
* Control string length and return structured JSON data
This example defines a bounded string input using `VARCHAR(n)` and returns structured data as JSON. Use `VARCHAR(n)` to enforce input size limits and return a JSON-encoded string when using the `JSON` type.
```python
from singlestoredb.functions import udf
from singlestoredb.functions.dtypes import JSON, VARCHAR
@udf(
args=[VARCHAR(128, nullable=False)],
returns=JSON(nullable=False),
)
def wrap_as_json(label: str) -> str:
import json
return json.dumps({"label": label})
```
> **📝 Note**: - Ensure `VARCHAR(n)` length matches the expected input size. Values longer than this limit may be truncated or rejected.
> - When using `JSON` as the return type, return a JSON-encoded string.
> - Set `nullable` to match whether your Python types allow `None`.
***
Modified at: May 22, 2026
Source: [/cloud/container-services/python-udfs/working-with-python-udfs/](https://docs.singlestore.com/cloud/container-services/python-udfs/working-with-python-udfs/)
(An index of the documentation is available at /llms.txt)
---
# Scheduled Jobs
A scheduled execution of a notebook is referred to as a “job.” The SingleStore job service provides a flexible and convenient way to schedule jobs using cron expressions that can be tailored to meet your requirements. Cron-based scheduling uses the [standard cron syntax](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/), providing precise control over when workloads are run. It supports the format - minute hour day month weekday, and allows for complex scheduling patterns (e.g., running jobs at 8:00 AM every Monday). Create, edit, and delete cron schedules, and validate cron expressions in real time.
After scheduling, the job service creates a snapshot. This snapshot represents a read-only notebook captured at the time the job was scheduled. It can be used for subsequent executions at the scheduled time until the user makes modifications. To ensure that the execution reflects the new changes, be sure to update the snapshot explicitly after modifying the notebook.
Create and manage scheduled jobs using the Cloud Portal or via the [Management API](https://docs.singlestore.com/cloud/reference/management-api.md).
## Scheduled Jobs using the Cloud Portal
## Create a Scheduled Job
Jobs can be scheduled for shared notebooks only. Create a scheduled job using the one of the following methods:
1. Navigate to **Jobs** in the left navigation and select **Schedule** (on the top right).
2. Navigate to **Editor > Shared**.
1. Select a shared notebook.
2. Select **Schedule** (on the top right).
## New Scheduled Job
After selecting **Schedule**, enter or select the following in **Job Settings**.
| **Job Settings** | |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | Enter a name for the job. |
| **Description** | Enter the job description. |
| **Notebook** | Select a shared notebook to run the job. The shared notebook is pre-selected when Job is scheduled through notebooks. |
| **Cluster** | Select theSingleStoreclusterthe notebook connects to.Selecting aclusterallows connecting theSingleStoredatabases referenced in the notebook natively. A scheduled job can also be run without aclusterattached to it. |
| **Runtime** | Select a runtime from the following: 📝 Note:
This field is in preview.
|
| **Region** | Select a region. |
Select **Next**. Enter the **Schedule Options**.
| **Scheduled Options** | |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Start Executions After** | Specify the date and time for the first run of the scheduled job. Select one of the following available options: - Now: The job runs as soon as it is created.
- Datetime: Specify a Starting Date and Starting Time.
|
| **Schedule Mode** | Specify the frequency to run a scheduled job. Select one of the following available options: - One Time: The job runs a single time.
- Recurring: Specify when the job needs to be run. Select from the following:
- Hourly
- Weekly
- Monthly
- Weekdays at 9 PM
- Every 6 Hours
- Enter a custom valid CRON expression.
|
| **Parameters** | Specify the job parameters for the scheduled job. - Type: Select the type of parameters from the following:
- String
- Integer
- Float
- Boolean
- Name: Enter the name of the parameter.
- Value: Enter the value of the parameter.
📝 Note:
The system injects parameters as Python variables into the notebook while the scheduled job runs, and access them using the variables where required.
|
| **Additional Settings** | - Save all execution results: Enable this setting to save the execution results. An execution result is a saved version of the notebook along with the cells containing outputs after the completion of a job run. This action enables to validate the execution result and the version of the notebook used for the run. By default, all snapshots for error and failed runs are saved.
- Auto resume the cluster on job execution: Enable this setting to resume the cluster when the job runs. This action resumes any suspended clusters. The previous auto-suspend settings of the clusters remain unchanged.
|
Select **Next**, review the **Summary**, and then select **Create Job** to schedule the job.
## Manage an Existing Job
To view an existing scheduled jobs and job runs, select **Jobs** in the left navigation pane. Existing jobs can be managed by performing the following actions:
* View
* Edit
* Pause
* Resume
* Delete
## View an Existing Job
To view a job, select the job name under the **Name** column and view the job execution details for each job.
View the details of a job on the **Job Details** pane in the right navigation. This page also supports refresh, edit, pause, resume, and delete actions for a job.
## Edit an Existing Job
To edit an existing job, navigate to the selected job page, select the ellipsis, and select **Edit Job**.
## Pause an Existing Job
To pause an existing job, navigate to the **Jobs** page, select the ellipses in the **Actions** column of the job, and select **Pause**. Alternatively, navigate to the selected job page, and select **Pause Job**.
## Resume an Existing Job
To resume an existing job, navigate to the **Jobs** page, select the ellipses in the **Actions** column of the job, and select **Resume**.
## Delete an Existing Job
To delete an existing job, navigate to the **Jobs** page, select the ellipses in the **Actions** column of the job, and select **Delete**.
> **⚠️ Warning**: Deleting a job removes all associated job runs, including snapshots.
## Schedule Jobs using the Management API
Use the `Jobs` path (`/v1/jobs` endpoint) to create and manage jobs using the Management API. Refer to [Management API](https://docs.singlestore.com/cloud/reference/management-api.md) and [Management API Reference](https://docs.singlestore.com/cloud/reference/management-api/reference.md) for more information.
For example, the following API call returns information about the job with the specified `jobID`:
```shell
curl -X 'GET' \ 'https://api.singlestore.com/v1/jobs/7b68b78d-a000-4000-9000-0864fd331524' \ -H 'accept: application/json'
```
## Status of Job Executions
| Status | Description |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Scheduled | The next scheduled run for the job. The latest version of the notebook runs at the Start Time associated with the job. |
| Completed | The notebook in this job run ran to completion. |
| Failed | The execution failed due to user error. View execution result to debug the failure. |
| Error | An error unrelated to the notebook code prevented this job from completing. Refer to[Troubleshoot Job Runs](https://docs.singlestore.com/#section-idm4502415224011234112089885605.md). |
## Troubleshoot Job Runs
SingleStore automatically saves an execution result notebook of an execution that fails. Navigate to **Jobs** in the left navigation, find the job, and download the snapshot associated with the failed job run to diagnose the error.
| Error | Solution |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ClusterDeleted | Edit the Job and select acluster. |
| ClusterSuspended | Resume thecluster, or create a new scheduled job with a differentcluster. |
| Database Detached | Reattach the database with the right permissions or create a new scheduled job with a different database. |
| Internal Errors / Misc | Reach out to[SingleStoreSupport](http://support.singlestore.com)or use the chat feature in theCloud Portal. |
| Notebook Timed Out | View the snapshot to identify the cells where the notebook is timed out.Refer to[Configurability and Key Considerations](https://docs.singlestore.com/#section-idm4561569057196834112075552002.md)for the Execution Time limits set on a job run. |
| Notebook Deleted/Not present | Create a new scheduled job with a different notebook. |
## Configurability and Key Considerations
Scheduled notebook jobs run using a snapshot of the notebook captured at the time the job is created or last refreshed. Updates made to the notebook after the snapshot is captured do not affect scheduled job runs.
To apply updates to a scheduled job, explicitly refresh the notebook snapshot. In the **Jobs** page, select the job and then select **Refresh** in the top right. Alternatively, select the **ellipsis** (three dots), select **Edit Job**, and enable **Update snapshot** to reflect the updates from the associated notebook in the job.
An execution time limit is set for each job:
* **Maximum allowed execution duration**: Specifies the maximum total time a notebook job can run, including all retries. The job is terminated when this limit is reached, even if execution is still in progress. The maximum allowed execution duration limit is 8 hours.
* **Minimum execution interval**: Specifies the minimum required time interval between consecutive notebook job runs. Schedules with intervals shorter than this limit are not allowed. The minimum execution interval limit is 60 minutes.
* **Maximum execution interval**: Specifies the maximum allowed time between consecutive notebook job runs. Schedules with intervals longer than this limit are not allowed. The maximum execution interval limit is 31 days.
## Examples
The following examples demonstrate how **maximum allowed execution duration**, **minimum execution interval**, and **maximum execution interval** are used while creating a scheduled job and how those patterns apply to scheduling notebooks within the SingleStore job service.
## Example 1: Hourly Data Refresh Job
Run a notebook every hour to refresh business analytics tables.
## Configuration
Cron Expression: `0 * * * *`
**Execution Time Limits**
| **Execution Time Parameter** | **Value** |
| ---------------------------------- | ---------- |
| Minimum execution interval | 60 minutes |
| Maximum execution interval | 31 days |
| Maximum allowed execution duration | 8 hours |
## Behavior
This configuration allows the notebook to run once every hour, which satisfies the minimum execution interval of 60 minutes and remains within the maximum execution interval of 31 days. Each job run can execute for up to 8 hours, including retries, after which the system terminates the running job automatically. Cron expressions that schedule executions more frequently than once per hour, such as `*/30 * * * *` are not allowed.
## Example 2: Monthly Compliance Report
Run a notebook once per month to generate a compliance report.
## Configuration
Cron Expression: `0 0 1 * *`
**Execution Time Limits**
| **Execution Time Parameter** | **Value** |
| ---------------------------------- | ---------- |
| Minimum execution interval | 60 minutes |
| Maximum execution interval | 31 days |
| Maximum allowed execution duration | 8 hours |
## Behavior
This configuration allows the notebook to run approximately once every 31 days, which satisfies both the minimum execution interval of 60 minutes and the maximum execution interval of 31 days. Each execution is limited to 8 hours, including retries, and the system terminates the running job if it exceeds this duration. Cron expressions that schedule executions less frequently than once every 31 days, such as `0 0 1 1 *` are not allowed.
***
Modified at: July 7, 2026
Source: [/cloud/container-services/scheduled-jobs/](https://docs.singlestore.com/cloud/container-services/scheduled-jobs/)
(An index of the documentation is available at /llms.txt)
---
# Create a Database
> **📝 Note**: As a database is automatically assigned to you in a SingleStore Helios [Shared Edition](https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-singlestore-helios/singlestore-helios-editions/shared-edition.md) cluster, additional databases cannot be created. To create additional databases, and for even greater functionality, SingleStore recommends creating a [Standard](https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-singlestore-helios/singlestore-helios-editions.md) cluster.
After deploying your cluster, you are ready to create a database.
This guide explains how to create a database using the [CREATE DATABASE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-database.md) command. After you have set up your database, navigate to the [Choosing a Table Storage Type](https://docs.singlestore.com/cloud/create-a-database/choosing-a-table-storage-type.md) topic for more information on what table storage type will best suit your needs.
## In this section
* [Choosing a Table Storage Type](https://docs.singlestore.com/cloud/create-a-database/choosing-a-table-storage-type.md)
* [Columnstore](https://docs.singlestore.com/cloud/create-a-database/columnstore.md)
* [Creating a Columnstore Table](https://docs.singlestore.com/cloud/create-a-database/creating-a-columnstore-table.md)
* [Configuring the Columnstore to Work Effectively](https://docs.singlestore.com/cloud/create-a-database/configuring-the-columnstore-to-work-effectively.md)
* [Rowstore](https://docs.singlestore.com/cloud/create-a-database/rowstore.md)
* [Understanding Keys and Indexes in SingleStore](https://docs.singlestore.com/cloud/create-a-database/understanding-keys-and-indexes-in-singlestore.md)
* [Understanding Shard Key Selection](https://docs.singlestore.com/cloud/create-a-database/understanding-shard-key-selection.md)
* [Understanding Sort Key Selection](https://docs.singlestore.com/cloud/create-a-database/understanding-sort-key-selection.md)
* [Understanding How Datatype Can Affect Performance](https://docs.singlestore.com/cloud/create-a-database/understanding-how-datatype-can-affect-performance.md)
* [Using JSON](https://docs.singlestore.com/cloud/create-a-database/using-json.md)
* [Multi-Value Hash Index (JSON)](https://docs.singlestore.com/cloud/create-a-database/multi-value-hash-index-json.md)
* [Using Persistent Computed Columns](https://docs.singlestore.com/cloud/create-a-database/using-persistent-computed-columns.md)
* [Other Schema Concepts](https://docs.singlestore.com/cloud/create-a-database/other-schema-concepts.md)
* [Detecting and Resolving Data Skew](https://docs.singlestore.com/cloud/create-a-database/detecting-and-resolving-data-skew.md)
* [Optimizing Table Data Structures](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures.md)
* [Specifying Unenforced Unique Constraints](https://docs.singlestore.com/cloud/create-a-database/specifying-unenforced-unique-constraints.md)
***
Modified at: May 11, 2026
Source: [/cloud/create-a-database/](https://docs.singlestore.com/cloud/create-a-database/)
(An index of the documentation is available at /llms.txt)
---
# Choosing a Table Storage Type
The most important consideration when creating a table is its data layout. SingleStore Helios supports two types of tables: on-disk columnstores (which is the default table type for SingleStore Helios) and in-memory rowstore. Columnstore is also known as **Universal Storage**.
The following table enumerates the strengths and intended uses of the columnstore and rowstore.
| Flash, SSD, or Disk-based Columnstore/Universal Storage | In-Memory Rowstore |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| Analytical workloads, but can handle operational/transactional workloads with relatively frequent updates and deletes | Demanding operational/transactional workloads with high update and delete rates |
| Fast inserts over a small or large number of rows | Fast inserts and updates over a small or large number of rows |
| Fast aggregations and table scans via sub-segment access | Random seek performance |
| Compression | `SPARSE`compression option |
## Conceptual Differences Between Columnstore and Rowstore
Column-oriented stores or “columnstores” (columnstore is also referred to as Universal Storage) treat each column as a unit. Columnstore tables sequentially store data segments for each column on the same physical location on disk. This enables two important capabilities. One capability is being able to scan only the columns needed for the query with good cache locality during the scan. The other capability is that columnstores lend themselves well to compression. For example, repeating and similar values can easily be compressed together.
In addition, columnstore tables utilize a feature called sub-segment access with allows quick retrieval of a row once its position is known via hash indexing. Columnstore tables can have multiple multi-column hash indexes. Finally, row-level locking allows many concurrent updates of multiple rows in a columnstore to proceed, without requiring transactions to wait.
Columnstores are usually batch-loaded for optimal performance, although small-batch and streaming insert to columnstores can also perform well. The combination of efficient batch loading and processing of analytic queries make columnstore highly suitable for data warehousing scenarios.
Columnstores can handle operational and transactional workloads with relatively frequent updates and deletes, but rowstore can perform better for a demanding operational and transactional workload with high update and delete rates. [Column group indexes](https://docs.singlestore.com/cloud/create-a-database/columnstore/how-the-columnstore-works.md) can be used on columnstore tables to speed up full-row retrievals and updates, particularly for wide tables.
In general, columnstore tables are effective when your workload matches the following descriptions as much as possible:
* A large number of rows are scanned sequentially (i.e. millions of rows or >5% of the table)
* Aggregation happens over only a few columns (e.g. <10 columns)
A simplified example of how columnstore data is physically stored is shown here:
**Columnstore**
| ProductId |
| --------- |
| 1 |
| 2 |
| 3 |
| 4 |
| Color |
| ---------- |
| Red**x 2** |
| Black |
| White |
*“x 2” indicates that the value is repeated twice.*
| Price |
| --------- |
| 10 |
| 20**x 3** |
*“x 3” indicates that the value is repeated three times.*
Row-oriented stores or “rowstores” are the most common type of data stores used by relational databases. As the name suggests, a rowstore treats each row as a unit and stores all fields for a given row together in the same physical location. This results in very fast performance when running queries seek specific rows. This makes rowstores great for transactional workloads, where the database frequently selects, inserts, updates, and deletes individual rows, often referencing either most or all columns.
With rowstore, data is stored in lock-free indexes for great performance at high concurrency. Rowstore tables can use multiple indexes, allowing them to flexibly support many types of queries.
Finally, when rowstore tables are created with [SPARSE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table/#UUID-003272e3-b877-41c1-7250-e56d395f7c4d.md) compression, the tables are allowed to store more data in the same amount of RAM. Nullable, structured columns can use sparse data compression. The column data types include `BIGINT`, `INT`, `MEDIUMINT`, `SMALLINT`, `TINYINT`, `DATE`, `DATETIME`, `TIME`, `TIMESTAMP`, and `VARCHAR`.
**Logical table and rowstore representation**
| ProductId | Color | Price |
| --------- | ----- | ----- |
| 1 | Red | 10 |
| 2 | Red | 20 |
| 3 | Black | 20 |
| 4 | White | 20 |
**Related Topics**
* Training: [SingleStore Helios Storage](https://training.singlestore.com/learn/course/internal/view/elearning/679/storage)
## Check Your Understanding
**Q**: Do columnstore tables use memory?
**A**: Absolutely – SingleStore Helios uses the operating system disk buffer cache to cache segment files in memory. Good performance in columnstore can only be achieved when there is enough memory to cache the working set. In addition, columnstore tables use a rowstore buffer table as a special segment to batch writes to the disk.
**Q**: Do rowstore tables ever write to disk?
**A**: Yes – data in a rowstore is also written to the transaction log on disk so that it can be recovered when SingleStore Helios is restarted.
**Q**: Are rowstore tables always faster than columnstore tables?
**A**: No, columnstore tables are faster on some workloads – if the workload is batch inserts and sequential reads (e.g. an analytical workload with lots of scans) a columnstore can be significantly faster.
**Q**: What if I need small high-concurrency updates and my data doesn’t fit in memory?
**A**: You can also use columnstore tables while setting hash index(es) on columns you regularly filter on. Rowstore tables could also be effective if you create them with `SPARSE` compression.
**Related Topics**
* Training: [SingleStore Helios Storage](https://training.singlestore.com/learn/course/internal/view/elearning/679/storage)
***
Modified at: February 8, 2024
Source: [/cloud/create-a-database/choosing-a-table-storage-type/](https://docs.singlestore.com/cloud/create-a-database/choosing-a-table-storage-type/)
(An index of the documentation is available at /llms.txt)
---
# Columnstore
The columnstore is the default table type in SingleStore Helios. Columnstore is also known as **Universal Storage**. The following sections explain the basic concepts of columnstore/Universal Storage.
## In this section
* [How the Columnstore Works](https://docs.singlestore.com/cloud/create-a-database/columnstore/how-the-columnstore-works.md)
* [Writing Columnstore Data](https://docs.singlestore.com/cloud/create-a-database/columnstore/writing-columnstore-data.md)
* [Locking in Columnstores](https://docs.singlestore.com/cloud/create-a-database/columnstore/locking-in-columnstores.md)
* [Managing Columnstore Segments](https://docs.singlestore.com/cloud/create-a-database/columnstore/managing-columnstore-segments.md)
* [Encoded Data in Columnstores](https://docs.singlestore.com/cloud/create-a-database/columnstore/encoded-data-in-columnstores.md)
* [Highly Selective Joins](https://docs.singlestore.com/cloud/create-a-database/columnstore/highly-selective-joins.md)
* [Columnstore Seekability using JSON](https://docs.singlestore.com/cloud/create-a-database/columnstore/columnstore-seekability-using-json.md)
* [Columnstore Sizing Estimations](https://docs.singlestore.com/cloud/create-a-database/columnstore/columnstore-sizing-estimations.md)
* [Universal Storage](https://docs.singlestore.com/cloud/create-a-database/columnstore/universal-storage.md)
***
Modified at: April 15, 2025
Source: [/cloud/create-a-database/columnstore/](https://docs.singlestore.com/cloud/create-a-database/columnstore/)
(An index of the documentation is available at /llms.txt)
---
# Columnstore Seekability using JSON
SingleStore exposes a Javascript Object Notation (JSON) (An open standard file format and data interchange format that uses human-readable text to store and transmit data objects consisting of attribute–value pairs and arrays.) column type that implements the [JSON standard](http://http://www.ietf.org/rfc/rfc4627.txt).
The primary encoding for `JSON` columns in columnstore tables is `SeekableJson`. With this encoding, JSON data is automatically columnarized. Analytics on columns with the `SeekableJson` encoding are very efficient.
`JSON` columns may also be encoded with the [seekable string encodings](https://docs.singlestore.com/cloud/reference/sql-reference/data-types/encoding-string-data-in-columnstore-tables.md) `SeekableLZ4` and `SeekableStringRunLength`. These seekable string encodings compress data and save space, but do not support efficient search or extraction on JSON values. SingleStore recommends using `SeekableLZ4` and `SeekableStringRunLength` only for columns on which JSON values will be extracted as a whole.
The non-seekable, columnarized format, `JSONParquet`, is provided for backwards compatibility.
The following table summarizes the properties of the encodings.
| Encoding | Seekable | Columnarized | Supports Efficient Search and Extraction | Default |
| -------------------------------------- | -------- | ------------ | ------------------------------------------- | ------- |
| `SeekableJson` | Yes | Yes | Yes | Yes |
| `SeekableLZ4``SeekableStringRunLength` | Yes | No | No | No |
| `JSONParquet` | No | Yes | Yes, but less efficient than`SeekableJson`. | No |
## Choose an Encoding
SingleStore recommends using `SeekableJson` for any `JSON` columns on which analytics, search, or extraction will be done. That is, if you use functions like `JSON_EXTRACT_`, the `::` operators, or `JSON_MATCH_ANY` on the `JSON` column, use the `SeekableJson` encoding for good performance. `SeekableJson` is the default encoding.
SingleStore recommends using `SeekableLZ4` (or `SeekableStringRunLength`) if you are concerned about memory usage and will not be searching on or extracting from the `JSON` column. Using the `SeekableLZ4` (or `SeekableStringRunLength`) encoding may reduce memory usage but will hurt performance if you are extracting keys and values from the JSON.
## Check which Encoding is Used
The `information_schema.COLUMNAR_SEGMENTS` view stores information about each segment of a columnstore table. Query the `encoding` column of this view to find out which encoding is used.
The following query returns the encoding and sizes of the segments for column ``; in table ``.
```sql
SELECT column_name, segment_id, encoding, uncompressed_size, compressed_size
FROM information_schema.COLUMNAR_SEGMENTS
WHERE table_name = ‘’ and column_name = '';
```
## SeekableJson
In the `SeekableJson` encoding, a schema is inferred from JSON keys and the data is split into columns by keypath (columnarized) and stored in an encoded Parquet-like format. The JSON data is stored as if you had created a schema with separate columns for every field. As a result, queries on `JSON` columns read only the parts of a JSON object that are relevant to a query and therefore have excellent performance.
The `SeekableJson` encoding format is inspired by Apache Parquet but does not produce a Parquet file.
`SeekableJson` is a seekable encoding. That is, during queries, the engine does not search entire segments, instead only a subset of rows in each segment is searched. This practice, called sub-segment seeking or row-level decoding, significantly improves performance.
When using the `SeekableJson` encoding for JSON columns in columnstore tables, the data is stored as follows:
* Top-level JSON properties are stored columnwise and use the same encodings as other data types (i.e., numbers, strings, and dates).
* Nested properties (inside sub-documents) are stored in sequential column format, using SingleStore's standard encoding.
* Arrays are pivoted and stored in column format. For example, a numeric array that is a property of an enclosing JSON document would be stored as a logical column, with multiple values in the column belonging to the same row. The array length information is kept to enable SingleStore to identify what values belong to what row.
The engine variable `use_seekable_json` controls if the default encoding for `JSON` columns is `SeekableJson` or `JSONParquet`. When `use_seekable_json` is set to `ON`, the default encoding for `JSON` columns is `SeekableJson`.
Check if `use_seekable_json` is enabled:
```sql
SELECT @@use_seekable_json;
```
```output
+---------------------+
| @@use_seekable_json |
+---------------------+
| 1 |
+---------------------+
```
## Limit Number of Inferred Keypaths
The engine variable `json_document_max_leaves` limits the number of JSON key paths inferred within a segment and can be used to tune schema inference. Refer to [Columnstore JSON Internals](https://docs.singlestore.com/#section-idm413515222379322.md) for more details.
## SeekableLZ4 and SeekableStringRunLength
`JSON` columns may also be encoded with the seekable string encodings `SeekableLZ4` and `SeekableStringRunLength`.
These encodings store the JSON as a string. Search or extraction on columns stored with these encoding decodes and parses the entire JSON value. Using these encodings may reduce memory usage and improve ingestion time, but they may significantly reduce performance for search and extraction on the JSON column, for example, when extracting keys and values from JSON data.
SingleStore recommends using `SeekableLZ4` and `SeekableStringRunLength` only for columns on which JSON values are extracted as a whole.
[Encoding String Data in Columnstore Tables](https://docs.singlestore.com/cloud/reference/sql-reference/data-types/encoding-string-data-in-columnstore-tables.md) provides a general description of encoding schemes and encoding scheme selection for string (including JSON) columns. String encoding schemes are per-segment and are automatically selected with the goal of maximizing storage savings and lowering query latency.
To specify a string encoding for a `JSON` column, use a collation specification as follows:
```sql
CREATE TABLE json_table (json_lz4_col JSON COLLATE utf8_bin OPTION 'SeekableLZ4');
CREATE TABLE json_table (json_rle_col JSON COLLATE utf8_bin OPTION 'SeekableStringRunLength');
```
## JSON Parquet
Like `SeekableJson`, the `JSONParquet` format is columnarized and inspired by the Apache Parquet format but does not produce a Parquet file.
SingleStore recommends that you use `SeekableJson` instead of `JSONParquet`, as `SeekableJson` is more performant.
`JSONParquet` is a precursor to `SeekableJson` and is not a seekable format, meaning that entire segments must be extracted and decoded for them to be processed.
## Apply SeekableJson Encoding to Existing Data
To change the encoding of a `JSON` column from `ParquetJSON` to `SeekableJson` encoding, use the following options.
## Online Approach
To keep the table online when `use_seekable_json` is not set to `ON`, you can upgrade existing `JSON` columns to use `SeekableJson` by setting `use_seekable_json = ON`, and then running `OPTIMIZE TABLE FULL`. This approach provides a best effort upgrade, when new segments are written, the new segments have the `SeekableJson` encoding. Segments that do not need to be re-written continue to use `JSONParquet` encoding.
## Offline Approach
If there is not a consistent improvement in seek performance with the Online Approach, query the `information_schema.COLUMNAR_SEGMENTS` view using the following query to see if the `JSONParquet` encoding is still used for many segments.
```sql
SELECT column_name, segment_id, encoding, uncompressed_size, compressed_size
FROM information_schema.COLUMNAR_SEGMENTS
WHERE table_name = '' and column_name = '';
```
If many segments are still using `JSONParquet` and it is acceptable to take the table offline; use the following procedure to rewrite all the segments in the new seekable format.
1. Enable or check if the `use_seekable_json` engine variable is enabled for your database: `SET GLOBAL use_seekable_json = ON;`
2. Create a new table to copy the existing data to: `CREATE TABLE LIKE ;`
3. Insert the existing data from the old table to the new table: `INSERT INTO SELECT * FROM ;`
4. Run the optimize table statement with the full argument: `OPTIMIZE TABLE FULL;`
5. Rename the old table with a temporary name: `ALTER TABLE RENAME TO ;`
6. Rename the new table to the original (i.e., old table name): `ALTER TABLE TO `;
7. Drop the temporary table: `DROP TABLE ;`
If the table needs to remain online but you need to ensure every segment is reorganized, update every row in the table gradually. When the merger is run after these updates, the merger reorganizes the segments and applies the seekable encodings.
To avoid modifying data in the table, add a new dummy column to the table and update it. The updates must be true updates; setting a value to itself is considered an update.
## Columnstore JSON Internals
This section provides details on the `SeekableJson` encoding.
A Parquet schema has a JSON-like syntax and a nested structure. The schema consists of a group of fields called a message. Each field has three attributes: repetition, type, and name. The type attribute is either a group or a primitive (e.g., int, float, boolean, or string). The repetition attribute can only be one of the following:
* Required: exactly one occurrence
* Optional: 0 or 1 occurrence
* Repeated: 0 or more occurrences
The infer schema process works as follows:
1. The schema loops through the list of JSON objects.
1. The present keypaths are merged into a schema tree object.
2. If there is a type conflict, the node in the schema tree is marked as un-inferable.
3. If any node in the schema tree contains more children than indicated in the `json_document_max_children` engine variable, the node is marked as un-inferable.
4. If a node has a greater number of children than indicated in the engine variable `json_document_sparse_children_check_threshold` and the average occurrence of all children related to the parent is less than 1/ as indicated in the engine variable `json_document_sparse_children_check_ratio`, the node will be marked as un-inferable.
2. Once the schema tree object is constructed, analyze the schema tree and prune the tree until the number of key paths (distinct root to leaf paths) is less than the setting for the engine variable `json_document_max_leaves`. Also, prune any node where the average occurrence of all the children in relation to the number of rows is less than 1/ as indicated in the engine variable `json_document_absolute_sparse_key_check_ratio`.
The examples will use the engine variables settings and the JSON object table shown below:
* `json_document_max_children = 4`
* `json_document_sparse_children_threshold = 3`
* `json_document_sparse_children_ratio = 2`
| JSON Objects |
| ------------------------------------------------------------ |
| {“a1”: 1, “a2”: {“d1”: 1}, “a3”: {“c1”: 1}, “a4”: {“b1”: 1}} |
| {“a1”: 2, “a2”: 1, “a4”: {“b2”: 1}} |
| {“a1”: 3, “a2”: 1, “a4”: {“b3”: 1}} |
| {“a1”: 4, “a2”: 1, ”a3”: {“c2”: 1}, “a4”: {“b4”: 1}} |
| {“a1”: 5,, “a3”: {“c3”: 1} “a4”: {“b5”: 1}} |
The first pass at merging the keypaths will yield:

The second pass at merging the keypaths contains a type mismatch on a2. The results would be:

The results of the third and fourth passes at merging yield:

In the final merge, the number of children for a4 exceeds the limit (4) set for `json_document_max_children` so it is marked as un-inferable. The number of children for `a3` exceeds the limit (3) set for `json_document_sparse_children_threshold`. The average occurrences of children of a3 (1) relative to the number of occurrences of a3 (3) is calculated as **⅓ < ½**, so a3 would also be un-inferable.
After the merging process, the schema tree with leaves are the inferred columns (also may be referred to as leaves, leaf columns, leaf paths, or key paths).
The keypaths will be a1, a2, a3, a4.
## Encoding Nested Columns
Parquet uses the `Dremel encoding` for nested columns with definition and repetition levels.
* Definition levels specify how many optional fields in the path for the column are defined.
* Repetition levels specify the repeated value of the field in the path.
* SingleStore stores the leaf columns for the JSON schema along with their respective repetition and definition levels.
Each of these internal columns will correspond to the value, definition level and repetition level columns which are encoded in SingleStore encodings (SeekableString, etc).
The example tables will have these values for the internal columns:
| a1 | | |
| ----- | ---------------- | ---------------- |
| Value | Definition Level | Repetition Level |
| 1 | 1 | 0 |
| 1 | 1 | 0 |
| 1 | 1 | 0 |
| 1 | 1 | 0 |
| 1 | 1 | 0 |
| a2 | | |
| ----------- | ---------------- | ---------------- |
| Value | Definition Level | Repetition Level |
| ‘{“d1”: 1}’ | 1 | 0 |
| 1 | 1 | 0 |
| 1 | 1 | 0 |
| 1 | 1 | 0 |
| - | 0 | 0 |
| a3 | | |
| ----------- | ---------------- | ---------------- |
| Value | Definition Level | Repetition Level |
| ‘{“c1”: 1}’ | 1 | 0 |
| - | 0 | 0 |
| - | 0 | 0 |
| ‘{“c2”: 1}’ | 1 | 0 |
| ‘{“c3”: 1}’ | 1 | 0 |
| a4 | | |
| ----------- | ---------------- | ---------------- |
| Value | Definition Level | Repetition Level |
| ‘{“b1”: 1}’ | 1 | 0 |
| ‘{“b2”: 1}’ | 1 | 0 |
| ‘{“b3”: 1}’ | 1 | 0 |
| ‘{“b4”: 1}’ | 1 | 0 |
| ‘{“b5”: 1}’ | 1 | 0 |
## Related Topics
* [OPTIMIZE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/optimize-table/#UUID-95582480-6981-8db3-0ad8-c559a8cfe64e.md)
* [Using JSON](https://docs.singlestore.com/cloud/create-a-database/using-json/#section-idm4634652054806433297983139685.md)
***
Modified at: July 10, 2026
Source: [/cloud/create-a-database/columnstore/columnstore-seekability-using-json/](https://docs.singlestore.com/cloud/create-a-database/columnstore/columnstore-seekability-using-json/)
(An index of the documentation is available at /llms.txt)
---
# Columnstore Sizing Estimations
There are two possible methods for estimating the total memory used by a columnstore table. The first method is brief, while the second is more precise. For more information about how columnstore works, see [Columnstore](https://docs.singlestore.com/cloud/create-a-database/columnstore.md), and the other topics nested under it.
## Simple Method
For the simple method, start with calculating the average row size for your table by adding together the size of each column's data type from [Data Types](https://docs.singlestore.com/cloud/reference/sql-reference/data-types.md). Multiply the average row size by the expected number of rows in your table to get the estimated uncompressed size.
Next, estimate the compression ratio for your dataset. Columnstore compression typically shrinks the data size by 3-7x. Based on these estimations, it is possible to get a very rough estimate of storage requirements for columnstore tables.
## Complex Method
In the same way as the simple method, start with calculating the average row size for your table by adding together the size of each column's data type from [Data Types](https://docs.singlestore.com/cloud/reference/sql-reference/data-types.md). Multiply the average row size by the expected number of rows in your table to get the estimated uncompressed size.
Then, to get an estimate that is more accurate than the base calculation demonstrated above, a more precise compression ratio is needed. Use the steps below to accomplish this by loading a large amount of representative data, then measuring the actual compression ratios achieved (by table, and by column).
1. Load a representative sample of data into a columnstore table. More data leads to more accurate measurements.
1. For information about creating a columnstore table, see [Creating a Columnstore Table](https://docs.singlestore.com/cloud/create-a-database/creating-a-columnstore-table.md).
2. To see options and procedures for loading data, see [Load Data](https://docs.singlestore.com/cloud/load-data.md) and the topics nested below it.
2. Run [OPTIMIZE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/optimize-table.md) on the table in order to ensure the data is optimized and on disk. Use caution when running this command, as it can impact the performance of all other workloads running in the cluster. For more information, see the linked topic.
3. Measure the compression ratios using SQL queries as outlined below.
1. By querying [COLUMNAR\_SEGMENTS](https://docs.singlestore.com/cloud/reference/information-schema-reference/segment-column-and-merge-status/columnar-segments.md).
1. Compression ratio per table (compressed / uncompressed):
```sql
SELECT
database_name,
table_name,
(1-SUM(compressed_size)/SUM(uncompressed_size)) AS ratio
FROM information_schema.columnar_segments
GROUP BY database_name, table_name
ORDER BY ratio DESC;
```
2. Compression ratio per column (compressed / uncompressed):
```sql
SELECT
database_name,
table_name,
column_name,
(1-SUM(compressed_size)/SUM(uncompressed_size)) AS ratio
FROM information_schema.columnar_segments
GROUP BY database_name, table_name, column_name
ORDER BY ratio DESC;
```
## Additional Methods to Obtain Columnstore Table Statistics
The following query can be used to obtain the total disk space used by columnstore secondary indexes:
```sql
SELECT database_name, table_name, SUM(size) AS total_index_size
FROM information_schema.MV_COLUMNSTORE_FILES
WHERE file_type = "INVERTED_INDEX" OR file_type = "CROSS_SEGMENT_HASH_INDEX" GROUP BY 1,2;
```
For more information about the column descriptions, see [MV\_COLUMNSTORE\_FILES](https://docs.singlestore.com/cloud/reference/information-schema-reference/segment-column-and-merge-status/mv-columnstore-files.md).
## Additional Sizing Estimations for Columnstore Table Overhead
Beyond the variable size estimates explained above, columnstore tables also require space for a constant metadata overhead of:
* \~100 bytes of memory per segment per column.
* \~100 KB for each segment that has at least one deleted row.
* 7KB per column per partition for incremental cardinality statistics.
***
Modified at: February 7, 2025
Source: [/cloud/create-a-database/columnstore/columnstore-sizing-estimations/](https://docs.singlestore.com/cloud/create-a-database/columnstore/columnstore-sizing-estimations/)
(An index of the documentation is available at /llms.txt)
---
# Encoded Data in Columnstores
SingleStore Helios performs some query processing operations directly on encoded data in columnstore tables. Columnstore data is stored encoded in a number of different forms, including dictionary encoding, run-length encoding, and value encoding. For these encodings, certain operations, including filtering and aggregation, can be run very efficiently, through the use of special coding techniques, as well as Single-Instruction, Multiple-Data (SIMD) instructions on processors that support the Intel AVX2 instruction set.
SIMD support on your hardware is not required to benefit from operations on encoded data. Performance may speed up for operations on encoded data anywhere from a few times to 30 times without SIMD support. Use of SIMD may give an additional increase in performance. A gain of another 2 to 3 times due to SIMD is not unusual. Your results will depend on your data and queries. Portions of larger queries may be done without operating on encoded data, so the end-to-end speedup you experience may vary.
Operations on encoded data are performed automatically, by default. You don’t need to change any settings to benefit from it. The decision to use operations on encoded data is made by the query execution system at runtime, not by the query optimizer.
## What Is Encoded Data and What Does It Mean to Operate on It?
SingleStore Helios supports several different kinds of data encodings to help compress data. All columnstore data is said to be encoded in one way or another. Common encodings are run-length, dictionary, and LZ4. Only certain encodings can be processed directly, i.e. “operated on” directly. These include dictionary encoding, run-length encoding, and integer value encoding. For example, with dictionary encoding, for a segment of a string column with only 3 distinct values, a 2-bit ID number is stored for each string. The ID numbers are used as references into the dictionary. These IDs are packed tightly together when stored in the columnstore.
For example, consider this dictionary:
| ID | value |
| -- | ----- |
| 0 | red |
| 1 | green |
| 2 | blue |
This can be represented as a bit vector of packed string IDs when it is stored into the column segment:
* Strings: “red”, “blue”, “green”, “green”, “red”
* String IDs: 0, 2, 1, 1, 0
* Bit vector: 00 10 01 01 00 (2 bits per string ID)
As an example of operating directly on encoded data, SingleStore Helios can perform a filter operation, say “t.a = “xyz””, on a string dictionary-encoded column segment by first finding the result of the filter for every entry in the dictionary. Then, while scanning the segment, the query execution system simply takes the encoded ID number for each value in t.a and uses it to look up the result of the string comparison for that ID that was computed in the initial scan of the dictionary. That tends to be much quicker than doing an actual string comparison. Other kinds of operations can also be done directly on encoded data ID values, including the comparison of ID values needed to do group-by operations. The details of these are beyond the scope of this documentation.
The encoding for a blob depends on its type and data. It may hinge both on the ordering and cardinality for numeric delta encoding and dictionary encoding, respectively. It impacts the execution speed, as well as enables SIMD operations on encoded data.
Most query processing in SingleStore Helios outside of columnstore scan is done row-at-a-time. Columnstore processing on encoded data is done in a vectorized fashion, where large batches of data from a column are processed in one or more relatively simple loops. These loops tend to be more friendly to modern CPUs than row-at-a-time processing, resulting in lower instruction count, better cache usage, and improved efficiency of the processor’s instruction pipeline.
## Queries That Can Benefit from Operations on Encoded Data
Queries that can benefit from operations on encoded data are those that run over columnstore tables, and have one or more of these components:
* Filters
* Group-by
* Aggregates
* Expressions in aggregates
* Expressions in group-by
* Star joins on integer columns
Operations on encoded data can be done regardless of the number of distinct values of the encoded columns being processed. Performance tends to be better when the number of distinct values is smaller. This is because when dictionaries are smaller the columnstore data is compressed to a smaller size, and intermediate working lookup tables fit more easily into the cache memory of the processor.
Here’s an example of a query that can benefit from operations on encoded data in several ways.
```sql
SELECT
DAYOFWEEK(shipdate), location,
SUM(price * (1 - discount)), AVG(quantity)
FROM lineitem
WHERE
status = 'S'
GROUP BY 1, 2;
```
Here’s another example of a query that can benefit from join operations on encoded data, if the table `f` is a columnstore.
```sql
SELECT d1.x, d2.y, SUM(f.m)
FROM f, d1, d2
WHERE f.d1_key = d1.key
AND f.d2_key = d2.key
AND d1.v > 100
AND d2.v in (1, 2, 3)
GROUP BY d1.x, d2.y
```
This query is a simple example of a *star join*. If you are using a *star schema* (with a fact table linked to multiple dimension tables), and the joins are on integer columns, you can benefit from operations on encoded data. Use of a `group by` clause and aggregate functions is required to benefit from join operations on encoded data.
## Examples
The following example shows encoded group-by in action:
```sql
CREATE DATABASE db;
USE db;
DROP TABLE IF EXISTS r;
DROP TABLE IF EXISTS is_tables;
/* Extract rows for 50 different tables into a scratch table, is_tables. */
CREATE TABLE is_tables AS
SELECT * FROM information_schema.tables
LIMIT 50;
/* Create a table with a million rows, with every table name
appearing in most or all segments. */
CREATE TABLE r (INDEX USING CLUSTERED COLUMNSTORE(n)) AS
SELECT s.*, (row_number () OVER (ORDER BY s.table_name) % 1000) AS n
FROM (SELECT t1.*
FROM is_tables t1, is_tables t2, is_tables t3, is_tables t4
LIMIT 1000000) AS s;
```
The table r created above is a columnstore with one million rows. You can see the encoding of the TABLE\_NAME column using this query:
```sql
SELECT COUNT(*), encoding, column_name
FROM information_schema.columnar_segments
WHERE table_name = 'r' AND database_name = 'db'
AND column_name = 'TABLE_NAME'
GROUP BY column_name, encoding;
```
The result indicates that StringDictionary encoding is used for the column.
Now, run the following group-by/aggregate query that groups on the table\_name column, in profile mode:
```sql
PROFILE SELECT table_name, COUNT(*) FROM r GROUP BY table_name;
```
Finally, output the JSON profile for the query:
```sql
SHOW PROFILE json;
```
The result includes the following text:
```json
inputs":[
{
"executor":"ColumnStoreScan",
"db":"db",
"table":"r",
...
"segments_scanned":{ "value":16, "avg":2.000000, "stddev":0.000000, "max":2, "maxPartition":0 },
"segments_skipped":{ "value":0 },
"segments_fully_contained":{ "value":0 },
"segments_encoded_group_by":{ "value":16, "avg":2.000000, "stddev":0.000000, "max":2, "maxPartition":0 },
"inputs":[]
}
```
Notice the portion labeled “segments\_encoded\_group\_by”. This part shows that 16 segments were processed in total and all of them were processed with encoded group-by operations. These operations are taking place directly on encoded data.
Now, here is another query (run in profile mode) that is similar to the first, but also has a filter on column table\_name:
```sql
PROFILE SELECT table_name, COUNT(*) FROM r
WHERE table_name LIKE '%COLUMN%'
GROUP BY table_name;
SHOW PROFILE json;
```
The JSON profile for this query contains the text below:
```json
"inputs":[
{
"executor":"ColumnStoreScan",
"db":"db",
"table":"r",
...
"segments_scanned":{ "value":16, "avg":2.000000, "stddev":0.000000, "max":2, "maxPartition":0 },
"segments_skipped":{ "value":0 },
"segments_fully_contained":{ "value":0 },
"segments_ops_compressed_data":{ "value":16, "avg":2.000000, "stddev":0.000000, "max":2, "maxPartition":0 },
"segments_encoded_group_by":{ "value":16, "avg":2.000000, "stddev":0.000000, "max":2, "maxPartition":0 },
"inputs":[]
}
```
Notice that it includes sections for both “segments\_ops\_compressed\_data” and “segments\_encoded\_group\_by”. The “segments\_ops\_compressed\_data” section indicates that 16 segments had filters applied on encoded data.
The final decision about use of operations on encoded data is made at runtime and depends on column encodings for each segment and (for group-by) the number of distinct values in the segment. So the segments\_ops\_compressed\_data and segments\_encoded\_group\_by values may be less than the number of segments scanned minus the number skipped. In this case, the “encoded\_group\_by\_bailout” section will indicate the reasons that encoded group by was disabled as well as the number of segments disabled for each reason.
## Encoded joins
This example shows encoded joins in action.
```sql
/* Create a simulated dimension table with 1000 rows with unique
values for n, and around 100 categories. */
CREATE TABLE d AS
SELECT n, MAX(CONCAT('cat', n % 100)) AS category
FROM r
GROUP BY n;
/* Join dimension table d to "fact" table r on an integer column
and group by category. This is a very simple star join. */
SELECT d.category, COUNT(*)
FROM r, d
WHERE r.n = d.n
AND d.category LIKE 'cat1%'
GROUP BY d.category;
```
The above join query takes only 0.02 seconds on a two-core laptop. Yet it is fully scanning the million-row table r and joining it with 110 rows from d.
You can see that encoded joins are being used in the profile query execution plan for the above statement by using the graphical plan display or `show profile json` output. On the HashJoin operator you will see the property `"encoded_join_enabled":"yes"`. In addition, you can see that operations on encoded data are pushed to the ColumnStoreScan operator since it has the property `segments_encoded_group_by` with `value` set to 8. The HashJoin, ColumnStoreScan, and various GroupBy operators can work together for a star join with a sequence of one or more hash joins over the scan.
## Example Performance Results
Operations on encoded data can yield some astonishingly short query execution times. Below are example queries and runtimes, on tables with 25 to 50 million rows of data, running on a single core.
| query | time |
| -------------------------------------------------------------------------- | ------ |
| `SELECT COUNT(*) FROM y WHERE b IN (thomas1,thomas3,thomas5)` | 0.424s |
| `SELECT COUNT(*) FROM col320 GROUP BY b {320 groups}` | 0.154s |
| `SELECT SUM(j) FROM col10 GROUP BY b {10 groups}` | 0.053s |
| `SELECT COUNT(*) FROM col10 WHERE c < 900000 GROUP BY b {90% selectivity}` | 0.114s |
| `SELECT COUNT(*) FROM col10 WHERE c < 100000 GROUP BY b {10% selectivity}` | 0.097s |
Best case performance in other internal tests have shown a processing rate of over one billion rows per second per core for queries like the following, when column `a` has eight or fewer distinct values, using a recent model high-performance Intel processor.
```sql
SELECT a, COUNT(*) FROM t GROUP BY a;
```
These results can be extrapolated to much larger data sets on a large SingleStore Helios cluster, although memory bandwidth limits may limit total throughput in rows per second per core across the cluster, below the best-case numbers shown here. Your results will of course depend on your data, hardware, and queries.
## Performance Considerations
Because operations on encoded data can process data so fast, their performance can become limited by the bandwidth of main memory (RAM). And the bandwidth of RAM is normally far higher than the bandwidth of your I/O system. For example, RAM bandwidth could be 50 GB/sec and the bandwidth of an SSD could be only 600 MB/sec.
So, SingleStore recommends that you configure your system so that little or no I/O is being done while processing columnstore data, under a steady query workload. You can do this by ensuring that the operating system’s file system buffer cache has enough main memory to hold the working set of your columnstore data, i.e. the segments of columns that are frequently accessed. A good rule of thumb is to have enough RAM in the file system buffer cache to hold at least 20% of your compressed columnstore data. If your workload does a lot of full table scans that touch all the columns of the table, you may want to consider adding more than that.
The Linux operating system will allocate available system memory to the file system buffer cache in an on-demand way, without the need to set any configuration knobs. Simply ensure that there is sufficient memory remaining after all the memory dedicated to SingleStore Helios, the operating system, and any other applications running on the hardware.
## Relevant Hints
SingleStore Helios can perform group-by on encoded data using a HashGroupBy operation, and can also do a group-by on columnstore data using a StreamingGroupBy operation on the sort key of the columnstore. Due to the improvement of HashGroupBy with the introduction of operations on encoded data, it may be the case that HashGroupBy is faster than StreamingGroupBy, yet the query optimizer may choose StreamingGroupBy. If this occurs and it is important for your workload to tune the query to get better performance, you can use the **disable\_ordered\_scan** query hint. For example:
```sql
SELECT SUM(a) FROM t WITH (disable_ordered_scan=true) GROUP BY b;
```
You can use EXPLAIN to see the plan for your query to check the type of group-by operation chosen.
## Data Encodings Supported
Operations on encoded data are supported only for the following:
* String columns (including varchar, char, text, and blob) with string dictionary and string run-length encodings
* Numeric columns (including all integer types (tinyint, bigint, etc.) plus float, decimal, and double) with value and run-length encodings
Group-by/aggregate operations on encoded data are supported only for integers. Filter acceleration on encoded data is supported for both strings and integers.
SingleStore recommends that you allow SingleStore Helios to choose automatically how to encode data for columnstores. However, in the rare event that it chooses an encoding that does not support operations on encoded data, and it is important to you for your application that operations on encoded data be performed, you may wish to force the encoding chosen. You can do this with the `option ''` notation. For example:
```sql
CREATE TABLE t (a int, b varchar(50) option 'StringDictionary',
key(a) USING CLUSTERED COLUMNSTORE);
```
## Operations Supported, and Limitations
To summarize the operations supported on encoded data, as well as limitations to operations on encoded data, they include:
* Scan
* Faster decoding for integer encoding
* Filter
* Filters on the following:
* Strings for string dictionary and string run-length encoding
* Integers for run-length encoding
* Or-of-ands of filter expressions; filter expressions must involve a single string column for faster processing
* Support for Bloom filters on string columns (elimination of rows with no matches for joins on a single string column)
* Aggregates
* Aggregates supported: sum, min, max, count, any
* Aggregate input data types supported: all numeric
* Aggregate expressions supported: multiple table columns allowed in a single expression
* Aggregates encodings supported: integer, integer run-length
* Group-by:
* Operations on encoded data are not done for aggregates without a group-by (a.k.a. scalar aggregates)
* Group-by count star is very fast
* Group-by:
* Multiple group-by columns are allowed
* A mix of columns and expressions is allowed
* Group-by columns must only use these encodings: integer, integer run-length
* There is a limit on number of distinct values per column of a few thousand rows, beyond which, the system reverts to row-at-a-time processing and the local aggregation of data for a row segment will output rows to the parent global aggregate operator
* Similarly, there is a limit on total number of groups, of a few thousand groups, beyond which the optimized group-by processing is not used
* Group-by on the sort key may not be as efficient as group-by on other columns because ordered group-by may be performed while hash groupby might be better
* Group-by on expressions:
* Only one input column is allowed in a single expression
* The expression result must be integer
* Each table column can be used only once in the set of group-by columns and expressions
* Joins:
* Joins must be on some type of integer column, or another column type represented internally as an integer, such as datetime
* The join or joins selected by the query optimizer must be of type HashJoin
* The join must be a many-to-one relationship
* The HashJoin (or a sequence of HashJoins) must appear over a ColumnStoreScan
* A Group By operation and aggregate must be present in the query over the result of the join
## Encoded group by bailout reasons
The final decision on whether to use encoded group by is made at runtime. The possible bailout reasons are:
* Join condition is not a many-to-one relationship
* Unsupported column encoding
* Aggregate not guaranteed to fit in aggregate type (the result may overflow the internal integer or decimal type)
* Reached dynamic dictionary size limit (too many unique group by values)
* Group by column cannot be placeholder blob (column does not yet exist in columnstore)
## Additional Tuning Considerations
If you have upgraded from a MemSQL release below 6.0, you can benefit immediately from operations on encoded data. There is no need to rebuild your columnstore tables. However, columnstore encoding choices have changed slightly in the 6.0 release, with dictionary encoding being more preferred. So queries may run faster on newly loaded data. Encodings are chosen separately for each segment, so even if you don’t use OPTIMIZE on your columnstore tables, as new data is inserted and older data is removed, the encodings chosen will naturally evolve to be those preferred by the latest version of SingleStore Helios.
If you find that operations on encoded data are not occurring as much as you expect them to you can rebuild the columnstore table involved. Before doing this, you can query information\_schema.columnar\_segments as described earlier to see if dictionary, run-length, or integer encodings are not used. If not, then consider rebuilding the columnstore table.
One way to rebuild it is to use
```sql
CREATE TABLE newTable (INDEX USING CLUSTERED COLUMNSTORE()) AS
SELECT *
FROM oldTable;
```
Then drop oldTable and rename newTable to oldTable. Alternatively you can use OPTIMIZE TABLE… FULL. However, be aware that this can take significantly longer than loading the data in the first place, because it causes a single sorted run to be created.
## Scalar count(\*)
Because encoded group-by is so fast, and scalar aggregates are not done on encoded data, you may find the following unexpected behavior. A query like this:
```sql
SELECT a, COUNT(*) FROM t GROUP BY a;
```
may be faster than this:
```sql
SELECT COUNT(*) FROM t;
```
Although it is usually not necessary because count(\*) scalar aggregates are so fast anyway, if you want the fastest possible count(\*), consider this workaround:
```sql
SELECT SUM(t2.c)
FROM (SELECT a, COUNT(*) AS c FROM t GROUP BY a) AS t2;
```
The subquery will be done with encoded group-by, so the containing query may run faster that a scalar count(\*);
## Aggregation of Decimal Types
When creating decimal type columns that are aggregated in queries, for best performance, SingleStore recommends to use precision of 18 digits or less if your application can accommodate this (i.e. the extra precision is not needed to represent meaningful information). Decimal values of 18 digits or less can be processed more efficiently than others because they can be handled internally as 64-bit integers during aggregation. Processing these 64-bit values takes much less time than interpreting decimal values of more than 18 digits, which must be handled in a more general way.
***
Modified at: March 2, 2026
Source: [/cloud/create-a-database/columnstore/encoded-data-in-columnstores/](https://docs.singlestore.com/cloud/create-a-database/columnstore/encoded-data-in-columnstores/)
(An index of the documentation is available at /llms.txt)
---
# Highly Selective Joins
## Working with Highly Selective Joins
Starting in version 7.0, SingleStore introduced support for columnstore hash indexes to broaden the support for OLTP-type queries. However, a common join pattern in OLTP is to have a very selective filter on one table, which produces a few rows from the source table, and then join those rows with another table. Databases for OLTP normally use a nested loop join for this. For each row from the outer table, an index seek is done on the inner table.
SingleStore Helios supports these highly selective joins using an adaptive hash join algorithm. As a result, there’s no need to run a full columnstore scan when there’s a matching hash index. First, it builds a hash table for the table with the highly-selective filter. Then, depending on the number of rows in the hash table, the adaptive algorithm will switch strategies internally.
* If there are only a few rows in the hash table, it switches to use a nested loop join strategy, seeking into the larger table (on the probe side) via the index on the join column of the table on the probe side.
* If the hash build side produces a lot of rows, then it performs a normal hash join.
The following example takes advantage of this strategy for selective joins.
```sql
CREATE TABLE orders(
oid INT,
d DATETIME,
SORT KEY(d),
SHARD(oid),
KEY(oid) USING hash);
CREATE TABLE lineitems(
id INT,
oid INT,
item INT,
SORT KEY(oid),
SHARD(oid)
KEY(oid) USING HASH);
```
Now, add some sample data to `orders`:
```sql
INSERT INTO orders VALUES(1, NOW());
```
Execute the following command repeatedly, until the table has around 33.5 million rows in it.
```sql
INSERT INTO orders
SELECT oid+(SELECT MAX(oid) FROM orders), NOW()
FROM orders;
```
Add 67.1 million rows of data to the `lineitems` table, such that each line item belongs to an order, and each order has exactly two line items.
```sql
INSERT INTO lineitems SELECT oid, oid, 1 FROM orders;
INSERT INTO lineitems SELECT oid + 1000*1000*1000, oid, 2 FROM orders;
```
Find a selective `DATETIME` value for `d` to search on:
```sql
SELECT d, COUNT(*)
FROM orders
GROUP BY d;
```
The result shows that a number of `DATETIME` values only appear in one row in `orders`. For this example, let’s say that one such value is `2020-03-30 16:47:05`.
The following query uses this date to produce a join result with exactly two rows:
```sql
SELECT *
FROM orders o JOIN lineitems l ON o.oid = l.oid
WHERE o.d = "2020-03-30 16:47:05";
```
This query filters rows on `o.d` to find a single row of orders, then joins to `lineitems` via the hash index on `lineitems.oid`, using the new selective join algorithm.
In the JSON profile plan, you can see if a plan may be able to perform a join via a hash index. If this optimization strategy is available in your plan, you will see `join index` in descriptions of columnstore filter operators. For example:
```
"executor":"ColumnStoreFilter",
"keyId":4294968023,
"condition":[
"o.oid = l.oid bloom AND l.oid = o.oid join index"
],
```
You may see a condition that mentions `join index`.
```
o.oid = l.oid bloom AND l.oid = o.oid join index
```
The `join index` filter can also be viewed in the `EXPLAIN` output.
## Performance of Highly Selective Joins
A higher number of join columns having a matching columnstore hash index and fewer number of hash values result in better join performance. For example, if `inventory` and `product` are two columnstore tables with hash indexes on the columns `id` and `code`, then the following query has better join performance than query with single join column:
```sql
SELECT * FROM
inventory JOIN product
ON inventory.id = product.id AND inventory.code = product.code;
```
## Related Content
See [SingleStore Universal Storage – And Then There Was One](https://www.singlestore.com/blog/memsql-singlestore-then-there-was-one/) for additional information about (1) using columnstores with hash indexes, sub-segment access, and fine-grain locking to enable OLTP operations on data bigger than will fit in RAM, and (2) using SPARSE rowstore compression to reduce TCO for rowstore tables with many NULL values.
***
Modified at: March 27, 2025
Source: [/cloud/create-a-database/columnstore/highly-selective-joins/](https://docs.singlestore.com/cloud/create-a-database/columnstore/highly-selective-joins/)
(An index of the documentation is available at /llms.txt)
---
# How the Columnstore Works
In SingleStore Helios there are a few concepts that are important to understand in order to make the best possible use of the columnstore.
* **Clustered columnstore index** - A clustered columnstore index represents the full table structure and is its primary storage.
* **Sort key column(s)** - When creating a columnstore index, one or more columns need to be defined as the key column(s) for the columnstore index. The data in the columnstore is stored in key column order. Selecting a good columnstore key can significantly improve performance as covered later in this section.
* **Row segment** - A row segment is a set of rows within a columnstore index that are stored together, each of which is made up of column segments. SingleStore Helios stores the metadata for each row, which includes the total row count for a given segment, as well as a bitmask tracking which rows have been deleted.
* **Column group** - A [ column group](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table/#UUID-8f75a032-47ca-2ae7-1bb5-e398d5a05141.md) is an optional data structure that creates a materialized copy of a row as a separate index, called a column group index. This data structure can be used to speed up full-row retrievals and table updates.
Column group indexes use less RAM than rowstore tables which can reduce operation costs. Using column group indexes on columnstores can allow you to get both fast lookups and fast analytics on the same table. The column group index improves the performance of lookups, and the standard columnar representation is available to give fast analytics. Using a column group index on a columnstore table is easier to manage than having to move data between rowstore and columnstore tables.
* **Column segment** - Each row segment contains a column segment for every column in a table. The column segment is the unit of storage for a columnstore table and contains all values for a specific column within the row segment. Values in column segments are always stored in the same logical order across column segments within the same row segment. SingleStore stores in memory the metadata for each column segment, which includes the minimum and maximum values contained within the segment. This metadata is used at query execution time to determine whether a segment can possibly match a filter, a process known as `segment elimination`.
* **Sorted row segment group** - A sorted row segment group represents a set of row segments that are sorted together on the columnstore key column(s). This means that within a sorted row segment group there will be no row segments with overlapping value ranges for the column(s) that make up the key for the columnstore index. New segment groups are formed when more segments are created after running `INSERT`, `LOAD`, or `UPDATE` queries on the table. Information on how this affects query performance and how to minimize the number of sorted row segment groups is covered later in this section.
Below is an example of a SingleStore Helios columnstore index on the `Products` table using the `Price` column as its key. See [Choosing a Columnstore Key](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/choosing-a-columnstore-key.md) for an example of how to create the table.
> **❗ Important**: Column segments typically contain on the order of hundreds of thousands of rows. In this example, the segment size is 5 rows for readability.Each row segment contains one column segment per column in the table. For simplicity, this example contains the initial load of the table and has a single sorted row segment group.
**Logical table and rowstore representation**
| ProductId | Color | Price | Qty |
| --------- | ----- | ----- | --- |
| 1 | Red | 10 | 2 |
| 2 | Red | 20 | 2 |
| 3 | Black | 20 | 2 |
| 4 | White | 30 | 2 |
| 5 | Red | 20 | 2 |
| 6 | Black | 10 | 2 |
| 7 | White | 25 | 2 |
| 8 | Red | 30 | 2 |
| 9 | Black | 50 | 2 |
| 10 | White | 15 | 2 |
| 11 | Red | 5 | 2 |
| 12 | Red | 20 | 2 |
| 13 | Black | 35 | 2 |
| 14 | White | 30 | 2 |
| 15 | Red | 4 | 2 |
**Sorted row segment group #1 of 1**
**Row segment #1 of 3**

*“x N” indicates that the value is repeated N times.*
**Row segment #2 of 3**

*“x N” indicates that the value is repeated N times.*
**Row segment #3 of 3**image

*“x N” indicates that the value is repeated N times.*
## Creating Efficient Columnstore Queries
Queries against tables with a columnstore index in SingleStore can take advantage of five characteristics of a columnstore index:
1. All queries will be able to take advantage of the fact that only the column segments containing columns referenced in the query will need to be scanned, as well as the fact that the columnstore’s compression causes less data to need to be scanned. Taking the above table as an example. The query `SELECT SUM(Qty) FROM Products;` will only need to scan the three `Qty` column segments, each of which only contain a single value due to the compression.
2. Some queries can be performed simply by reading the in-memory metadata for column segments referenced in the query. As an example, the query `SELECT COUNT(*) FROM Products;` will only need to read the row count and delete bitmask for all row segments to produce its result, completely eliminating the need to read column segments from disk. Queries that use the `MIN` or `MAX` aggregates can eliminate the need to read column segments from disk if no delete has been performed against the column segment.
3. Some queries can reduce the number of segments that need to be read from disk by eliminating these segments based on the segment metadata (min and max values for the segment). The efficiency of this method depends on what percentage of segments can actually be eliminated.
* For queries that filter on the key columns of the columnstore index, segment elimination is typically very efficient as segments within each row segment will not cover overlapping value ranges. For example, in the above table the query `SELECT AVG(Price), AVG(Qty) FROM Products WHERE Price BETWEEN 1 AND 10;` will eliminate all segments except `row segment: #1 column segment: Price 4-15` and `row segment: #1 column segment: Qty 2-2` which will be scanned.
* For queries that filter on the non-key columns that don’t correlate with the key columns, segment elimination can be much less valuable as segments within each row segment can cover overlapping value ranges. For example, in the above table, the query `SELECT AVG(Price) FROM Products WHERE Color = 'Red';` will be forced to scan all segments for the `Price` and `Color` columns as no segment can be eliminated when the value `Red` is contained in all segments of the `Color` column.
4. Queries that join tables on columns that are the index columns of a columnstore index can be performed very efficiently through the use of a merge join algorithm allowing the join to be performed by simply scanning two segments that need to be joined in lockstep.
5. Certain types of data allow filters and group-by operations to be performed without decompressing data from its serialized-for-disk format. This greatly improves performance by reducing the amount of data that need to be processed, especially when the cardinalities of the involved columns are low. This optimization is only performed in cases when execution run time would be improved. See [Encoded Data in Columnstores](https://docs.singlestore.com/cloud/create-a-database/columnstore/encoded-data-in-columnstores.md) for more information.
6. Queries with selective filters use subsegment access. These queries seek into column segments to read the needed values, rather than scanning whole segments. For a columnstore table `MyTable`, the query `SELECT Field1, Field2 FROM MyTable WHERE Field1 > 50` uses subsegment access. Selective filters with multiple conditions, such as `SELECT Field1, Field2 FROM MyTable WHERE Field1 > 50 AND Field2 > 100`, also use subsegment access.
7. Queries using equality filters can take advantage of hash indexes. See an [example](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table.md). The previous note applies to these queries, since equality filters are often selective filters.
## Create and Drop a Column Group
The following examples show how to create, drop, and use a column group.
Define an `emp` table with a column group named `cg_full`.
```sql
CREATE TABLE emp (
id INT PRIMARY KEY,
name VARCHAR(256),
dept VARCHAR(16),
salary FLOAT,
manager INT,
...
COLUMN GROUP cg_full (*)
);
```
The `*` indicates that the column group covers all the columns in the table. The `...` indicates there are more columns than shown. This table is intended to be a wide table.
> **📝 Note**: Only column groups covering all columns in a table are supported.
Add a column group to an existing table with an `ALTER TABLE` statement.
```sql
ALTER TABLE emp ADD COLUMN GROUP cg_full (*);
```
Drop a column group with an `ALTER TABLE` statement:
```sql
ALTER TABLE emp DROP COLUMN GROUP cg_full;
```
## Use a Column Group Index
The following query uses a column group index.
```sql
SELECT * FROM emp WHERE id = 56231;
```
This query is a single-point lookup using the primary key `id`. To run this query, the engine locates the row using the primary key index. Since the result contains one row, and all columns are projected, the engine retrieves the entire row from the column group index using a single IO.
The following query also uses a column group index.
```sql
SELECT * FROM emp WHERE dept = 'IT';
```
This query uses a filter to list all employees in the `IT` department. During query execution, the engine first uses the columnstore to perform the filter. The filter uses one column (`dept`), hence using the columnstore is the most efficient way to evaluate the filter. If `IT` is a small department, a small number of rows pass the filter. The engine then uses the column group index to read the full rows from the `emp` table. This execution plan is IO efficient.
The following example query demonstrates use of the column group index in an update.
```sql
UPDATE emp SET dept = 'IT' WHERE id = 56231;
```
This query updates the department name to `IT` for an employee with `id = 56231`. Although the query only affects the `dept` column, the engine still needs to read the entire row to implement row level locking (refer to [Locking in Columnstores](https://docs.singlestore.com/cloud/create-a-database/columnstore/locking-in-columnstores.md)). In this example, the column group index is used to efficiently retrieve the row and load it into the in-memory segment of the `emp` table. Similarly, a column group index can improve delete query performance, since delete also requires reading and locking the entire row.
## Common Workflow
A typical workflow using column group indexes is illustrated in the diagram below.
1. The user creates a columnstore table with a column group.
2. When the in-memory segment of the columnstore table is flushed to the disk, the engine creates a column group index blob (marked green in the diagram) in addition to creating the columnstore blobs themselves.
3. During query execution, columnstore hash indexes and columnstore blobs are used for efficient filtering.
4. The column group index blob is used to materialize the rows post-filtering for highly-selective queries that retrieve a small fraction of rows in the table.

The query engine dynamically chooses different storage structures, combining hash indexes, columnstore blobs, and column group indexes to deliver optimal query execution. This efficiency is possible because the column group index and columnstore blobs live in the same columnstore segment — thus they can share the same row locators and indexes.
## Finding the Size of a Column Group Index
The size (in bytes) of a column group index can be found in the [MV\_COLUMNSTORE\_FILES](https://docs.singlestore.com/cloud/reference/information-schema-reference/segment-column-and-merge-status/mv-columnstore-files.md) view as follows:
```sql
CREATE TABLE colgrpsz_1 (a INT, b INT PRIMARY KEY, COLUMN GROUP(*));
```
```sql
INSERT INTO colgrpsz_1 VALUES (1,2),(6,4),(36,8);
```
Run the `OPTIMIZE TABLE FULL` command on any table you want to know the column group index size on. This will create a more accurate reflection of the physical storage of the table's data. Please note, that this operation can be resource-intensive and time-consuming, particularly for large tables. Therefore, it should be scheduled during periods of low system usage to minimize the impact on system performance.
```sql
OPTIMIZE TABLE colgrpsz_1 FULL;
```
Filter the view for the `COLUMN_GROUP` and only information about the column group index will be returned. If there are column group indexes on other tables, they will be displayed in the following query as well.
```sql
SELECT * FROM information_schema.MV_COLUMNSTORE_FILES
WHERE FILE_TYPE = 'COLUMN_GROUP;
```
```output
+---------------+------------+--------------+-----------------------+-----------+------+---------+-----------+------+---------------------+-----+------+------------+
| DATABASE_NAME | TABLE_NAME | FILE_TYPE | FILE | HOST | PORT | NODE_ID | PARTITION | SIZE | CREATION_TIME | LSN | TERM | CHECKSUM |
+---------------+------------+--------------+-----------------------+-----------+------+---------+-----------+------+---------------------+-----+------+------------+
| test1 | colgrpsz_1 | COLUMN_GROUP | blobs/5006/0/0/173_51 | 127.0.0.1 | 3307 | 2 | 2 | 33 | 2024-05-06 11:43:05 | 51 | 173 | 1230141913 |
| test1 | colgrpsz_2 | COLUMN_GROUP | blobs/5006/0/0/173_66 | 127.0.0.1 | 3307 | 2 | 2 | 33 | 2024-05-06 13:39:52 | 66 | 173 | 1230141913 |
| test1 | colgrpsz_1 | COLUMN_GROUP | blobs/5002/0/0/174_52 | 127.0.0.1 | 3307 | 2 | 3 | 47 | 2024-05-06 11:43:05 | 52 | 174 | 2716425258 |
| test1 | colgrpsz_2 | COLUMN_GROUP | blobs/5002/0/0/174_67 | 127.0.0.1 | 3307 | 2 | 3 | 47 | 2024-05-06 13:39:52 | 67 | 174 | 2716425258 |
+---------------+------------+--------------+-----------------------+-----------+------+---------+-----------+------+---------------------+-----+------+------------+
```
The `MV_COLUMNSTORE_FILES` view can be filtered to search for a specific table, the size summed to see the total column group index size per table, etc.
```sql
SELECT * FROM information_schema.MV_COLUMNSTORE_FILES
WHERE FILE_TYPE = 'COLUMN_GROUP' AND TABLE_NAME = 'colgrpsz_1';
```
```output
+---------------+------------+--------------+-----------------------+-----------+------+---------+-----------+------+---------------------+-----+------+------------+
| DATABASE_NAME | TABLE_NAME | FILE_TYPE | FILE | HOST | PORT | NODE_ID | PARTITION | SIZE | CREATION_TIME | LSN | TERM | CHECKSUM |
+---------------+------------+--------------+-----------------------+-----------+------+---------+-----------+------+---------------------+-----+------+------------+
| test1 | colgrpsz_1 | COLUMN_GROUP | blobs/5006/0/0/173_51 | 127.0.0.1 | 3307 | 2 | 2 | 33 | 2024-05-06 11:43:05 | 51 | 173 | 1230141913 |
| test1 | colgrpsz_1 | COLUMN_GROUP | blobs/5002/0/0/174_52 | 127.0.0.1 | 3307 | 2 | 3 | 47 | 2024-05-06 11:43:05 | 52 | 174 | 2716425258 |
+---------------+------------+--------------+-----------------------+-----------+------+---------+-----------+------+---------------------+-----+------+------------+
```
```sql
SELECT DATABASE_NAME, TABLE_NAME, FILE_TYPE, SUM(SIZE) FROM information_schema.MV_COLUMNSTORE_FILES
WHERE FILE_TYPE = 'COLUMN_GROUP' AND TABLE_NAME = 'colgrpsz_1'
GROUP BY DATABASE_NAME, TABLE_NAME, FILE_TYPE;
```
```output
+---------------+------------+--------------+-----------+
| DATABASE_NAME | TABLE_NAME | FILE_TYPE | SUM(SIZE) |
+---------------+------------+--------------+-----------+
| test1 | colgrpsz_1 | COLUMN_GROUP | 80 |
+---------------+------------+--------------+-----------+
```
***
Modified at: August 10, 2026
Source: [/cloud/create-a-database/columnstore/how-the-columnstore-works/](https://docs.singlestore.com/cloud/create-a-database/columnstore/how-the-columnstore-works/)
(An index of the documentation is available at /llms.txt)
---
# Locking in Columnstores
By default, `UPDATE` and `DELETE` queries lock columnstore tables at the row level.
The following example demonstrates how multi-table filters may lock rows that do not match the filters. Consider the following query,
```sql
UPDATE stock JOIN product ON stock.qty = 10 AND stock.id = product.id SET ...
```
This query locks all the rows of the table `stock` where `stock.qty = 10`, including the rows where `stock.id` is not equal to `product.id`. Alternatively, use a single table filter to trim the number of rows locked.
Suppose that a database `errors_db` containing eight partitions has the `app_errors` table that is defined as follows.
```sql
CREATE TABLE app_errors (
error_id INT,
app_name TEXT,
error_code TEXT,
error_date DATE,
SORT KEY (error_date),
SHARD KEY (error_id)
);
```
The following `UPDATE` example demonstrates row-level locking. Assume the `app_errors` table on partition one contains 4500 records having an `app_name` of `App1`.
```sql
UPDATE app_errors SET error_code = 'ERR-2000'
WHERE app_name = 'App1';
```
While this query is running:
* In the `app_errors` table on partition one, other queries can `UPDATE` and `DELETE` the rows not having an `app_name` value of `App1`.
* In the `app_errors` table on partition one, other queries may not `UPDATE` and `DELETE` the rows having an `app_name` value of `App1`.
When a table is locked during a transaction, an error message similar to the following is generated: "Lock wait timeout exceeded; try restarting transaction. Table lock owned by connection id \, query \"
## Overriding Default Locking
By default, `UPDATE` and `DELETE` queries on a columnstore table use row-level locking when they operate on fewer than `default_columnstore_table_lock_threshold` rows in a partition and use partition-level locking when they operate on `default_columnstore_table_lock_threshold` rows or more rows in a partition. In the latter case, all of the table’s rows in the partition are locked.
The default for `default_columnstore_table_lock_threshold` is 0, meaning that a value of 5000 is used.
For an `UPDATE` or a `DELETE` query, you can override the default threshold of `default_columnstore_table_lock_threshold` by specifying the `OPTION (columnstore_table_lock_threshold = )` hint. The `` indicates the row count threshold for which partition level locking takes effect.
The following `UPDATE` example specifies that `columnstore_table_lock_threshold` is 4000.
```sql
UPDATE app_errors SET error_code = 'ERR-2000'
WHERE app_name = 'App1' OPTION (columnstore_table_lock_threshold = 4000);`
```
When you specify a higher `columnstore_table_lock_threshold` value, you can get higher concurrency, but more memory may be used for locking.
In the following scenario, the `columnstore_table_lock_threshold` value is set to a higher value in order to avoid locking:
If a database has 455000 rows and 48 partitions (for this example, we'll assume there is no Shard key and the data is evenly divided among the partitions), each partition would have about 9480 rows, which is higher than the default threshold of 5000. In this case, a set of `UPDATE` or `DELETE` queries that touch every partition would lock the entire table. Setting the threshold value to a value higher than 9480 (say, 12000) would cause the database to use row locking until the number of rows per partition hit 12000.
***
Modified at: December 1, 2023
Source: [/cloud/create-a-database/columnstore/locking-in-columnstores/](https://docs.singlestore.com/cloud/create-a-database/columnstore/locking-in-columnstores/)
(An index of the documentation is available at /llms.txt)
---
# Managing Columnstore Segments
A columnstore table will have the best performance if the rows in the table are in global sorted order across all the row segments. In reality, maintaining such an order is not feasible in the presence of continuous writes.
## Background Merger
SingleStore uses an advanced algorithm that allows it to maintain the order of columnstore tables as close to sorted as possible, while data is being ingested or updated. This process is called a `background merger` and runs constantly in the background.
The `background merger` runs in an optimistic manner. If at any point the background merger tries to move data which is being changed by a concurrent [UPDATE](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/update.md) or [DELETE](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/delete.md) query, it discards all the work it has done so far and starts over. The `background merger` works on a small chunk of data at a time, so if a conflict with an `UPDATE` or `DELETE` occurs, a relatively small amount of work is discarded. However, in the presence of a very heavy update workload, the slowdown can be significant compared to a pessimistic merger, which locks the row segments it is currently processing. A user can manually trigger a pessimistic merger by running the `OPTIMIZE TABLE` command. The following sections explain how to decide whether running an `OPTIMIZE TABLE` command is necessary, and how to run it.
## Sorted Row Segment Group
SingleStore uses the concept of a `sorted row segment group` to describe a set of row segments that are sorted together on the columnstore key columns. Row segments form a sorted row segment group if and only if there is an order on the row segments such that for each row segment the smallest row in it is no smaller than the largest row in any row segment before it. Here and below when we say that one row is smaller than another row, we mean that the values of columns of the `SORT KEY` of that row are smaller than those of the other row.
Within a sorted row segment group there are no row segments with overlapping value ranges for the sort key column(s). Refer to [How the Columnstore Works](https://docs.singlestore.com/cloud/create-a-database/columnstore/how-the-columnstore-works.md) for more information.
A table may have multiple sorted row segment groups. The goal of the background merger is to reorganize the rows among row segments in such a way that the number of sorted row segment groups is as small as possible.
> **📝 Note**: `KEY() USING CLUSTERED COLUMNSTORE` is a legacy syntax that is equivalent to `SORT KEY()`. SingleStore recommends using `SORT KEY()`.
To inspect the current state of the sorted row segment groups of a table, named `sales`, run the `SHOW COLUMNAR MERGE STATUS FOR ` command:
```sql
SHOW COLUMNAR MERGE STATUS FOR sales;
```
```output
+----------------------------------------------------------------------------+
| Merger | State | Plan | Progress | Partition |
+----------------------------------------------------------------------------+
| (Current groups) | NULL | 741,16,1 | NULL | 0 |
| (Current groups) | NULL | 782,20 | NULL | 1 |
| (Current groups) | NULL | 701,40,5 | NULL | 2 |
| (Current groups) | NULL | 326,207,123,37,21,19,17 | NULL | 3 |
+----------------------------------------------------------------------------+
```
Observe the first row of the result. According to that row, the slice of the table that is stored on partition 0 has three sorted row segment groups, one consists of 741 row segments, one consists of 16 row segments, and one consists of a single row segment, for a total of 758 row segments. Consider the impact of that number of sorted row segment groups on a simple query like:
```sql
SELECT * FROM sales WHERE store_id = 15;
```
This query filters on the `SORT KEY` which is `store_id` in this example. The very first sorted row segment group will have at most one row segment that contains rows with `store_id` equal to `15`, unless rows with `store_id = 15` are on the boundary of two row segments, or if there is a large data skew and several row segments consist only of rows with `store_id = 15`. Similarly, at most one row segment in the second sorted row segment group contains relevant rows, and the only segment of the third sorted row segment group might also contain relevant rows. This way, only three row segments out of the total of 758 will be opened and materialized. While the query in this example is very simple, similar reasoning works for significantly more complex queries.
## Optimize Sorted Row Segment Groups
Now take a look at the sorted row segment groups on partition 3, which is significantly less optimized than the other partitions. A `SELECT` query similar to the one above will materialize eight row segments. If the background merger is enabled, and no workload is running concurrently, the background merger would optimize this partition quickly, likely within several seconds. However, in the presence of a heavy workload, the optimistic background merger might fall behind. In this case, it may be reasonable to manually trigger a pessimistic merger by running the following command:
```sql
OPTIMIZE TABLE sales;
```
By running `SHOW COLUMNAR MERGE STATUS` while `OPTIMIZE TABLE` is running, you may see the manual merger in action:
```sql
SHOW COLUMNAR MERGE STATUS FOR sales;
```
```output
+--------------------------------------------------------------------------------+
| Merger | State | Plan | Progress | Partition |
+--------------------------------------------------------------------------------+
| (Current groups) | NULL | 741,16,1 | NULL | 0 |
| (Current groups) | NULL | 782,20 | NULL | 1 |
| (Current groups) | NULL | 701,40,5 | NULL | 2 |
| (Current groups) | NULL | 326,207,123,37,21,19,17 | NULL | 3 |
| Manual Merger | Working | 326+207+123+37+21+19+17 | 53.12% | 3 |
+--------------------------------------------------------------------------------+
```
The last row indicates that there is a manual merger running on partition 3 and that at this time `53.12%` of the work is complete.
When the merger is done, the table has fewer sorted row segment groups in partition 3:
```sql
SHOW COLUMNAR MERGE STATUS FOR sales;
```
```output
+------------------------------------------------------------+
| Merger | State | Plan | Progress | Partition |
+------------------------------------------------------------+
| (Current groups) | NULL | 741,16,1 | NULL | 0 |
| (Current groups) | NULL | 782,20 | NULL | 1 |
| (Current groups) | NULL | 701,40,5 | NULL | 2 |
| (Current groups) | NULL | 730,20 | NULL | 3 |
+------------------------------------------------------------+
```
During the optimization process, no partitions were merged into a single sorted row segment group as can be seen in the output shown above. Both optimistic and pessimistic mergers use an advanced algorithm which is optimized to do small chunks of work in the presence of concurrent writes and maintain data in a few sorted row segment groups, instead of attempting to merge all the data into a single sorted row segment group.
In cases when it is acceptable to sacrifice some time on data ingestion to achieve even higher `SELECT` performance, it is possible to run a manual command that merges data on each partition into a single sorted row segment group. The command `OPTIMIZE TABLE FULL` will merge the data on each partition into a single sorted row segment group, as shown below.
```sql
OPTIMIZE TABLE sales FULL;
SHOW COLUMNAR MERGE STATUS FOR groups;
```
```output
+---------------------------------------------------------+
| Merger | State | Plan | Progress | Partition |
+---------------------------------------------------------+
| (Current groups) | NULL | 758 | NULL | 0 |
| (Current groups) | NULL | 802 | NULL | 1 |
| (Current groups) | NULL | 746 | NULL | 2 |
| (Current groups) | NULL | 750 | NULL | 3 |
+---------------------------------------------------------+
```
When the table is in this state, any highly selective `SELECT` query will materialize one row segment per partition.
> **❗ Important**: Unlike `OPTIMIZE TABLE `, which takes the amount of time proportional to the size of recently loaded data, `OPTIMIZE TABLE FULL` takes an amount of time proportional to the order of magnitude of the size of the entire table, unless data in that table is already sorted.
## Inserts, Deletes, and Garbage Collection
When inserting a small number of rows into the columnstore table, an in-memory rowstore-backed segment is used to store the rows. As this rowstore-backed segment fills, the `background flusher` periodically flushes these rows to disk. A rowstore-backed segment can be flushed to disk manually by running `OPTIMIZE TABLE FLUSH`.
```sql
OPTIMIZE TABLE t FLUSH;
```
Deletes in columnstores are marked as deleted but otherwise left in place (refer to [Writing Columnstore Data](https://docs.singlestore.com/cloud/create-a-database/columnstore/writing-columnstore-data.md)). However, when a significant number of rows are deleted from a segment, the background merger rewrites those segments if the number of deleted rows is at least 1/8th of the desired segment size, and the sorted run isn't going to be merged otherwise. This rewrite happens per sorted run so it does not break the order of the run.
`MV_COLUMNSTORE_MERGE_STATUS` shows the details about the merger processes.
Unneeded columnstore segments stored in memory are eliminated in a process called garbage collection. A buffer manager maintains unused memory blocks for future use until no query or operation is using the memory anymore.
The garbage collection process automatically runs in the background.
***
Modified at: November 18, 2025
Source: [/cloud/create-a-database/columnstore/managing-columnstore-segments/](https://docs.singlestore.com/cloud/create-a-database/columnstore/managing-columnstore-segments/)
(An index of the documentation is available at /llms.txt)
---
# Universal Storage
Universal storage allows you to support large-scale Online Transaction Processing (OLTP) and Hybrid Transactional and Analytical Processing (HTAP) at a lower total cost of ownership (TCO). Universal storage is a continuing evolution of the [columnstore](https://docs.singlestore.com/cloud/create-a-database/columnstore.md), supporting transactional workloads that would have traditionally used the [rowstore](https://docs.singlestore.com/cloud/create-a-database/rowstore.md).
Although rowstores are well-suited for transaction processing, it can be costly to store large datasets in rowstores, as they store all data in RAM. Because columnstores are disk-based, it is more economical to store data in columnstores as opposed to rowstores.
## Current Features in Universal Storage
Currently, universal storage has five features that allow columnstores to process transactional workloads more efficiently:
* [Hash indexes on columnstores](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table.md) which may optionally require uniqueness.
* Subsegment access, which speeds up access to a row in a columnstore. For more details, see item 6 in [Creating Efficient Columnstore Queries](https://docs.singlestore.com/cloud/create-a-database/columnstore/how-the-columnstore-works/#UUID-a6ee7177-8029-15e5-a603-ff36c4e4ff41.md).
* [Row-level locking on columnstores](https://docs.singlestore.com/cloud/create-a-database/columnstore/locking-in-columnstores.md).
* Joins on columnstores, where [one of the tables in the join uses a highly selective filter](https://docs.singlestore.com/cloud/create-a-database/columnstore/highly-selective-joins.md).
* [Upserts](https://docs.singlestore.com/cloud/query-data/advanced-query-topics/performing-upserts.md) on columnstores.
Additionally, [sparse compression for rowstores](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table.md) enables wide tables with a large percentage of `NULL` values to be stored in as little as half of the RAM.
## Related Content
See [SingleStore's Patented Universal Storage - Part 4](https://www.singlestore.com/blog/singlestore-universal-storage-episode-4/) for a general discussion of all the capabilities of Universal Storage.
***
Modified at: October 18, 2024
Source: [/cloud/create-a-database/columnstore/universal-storage/](https://docs.singlestore.com/cloud/create-a-database/columnstore/universal-storage/)
(An index of the documentation is available at /llms.txt)
---
# Writing Columnstore Data
Unlike other columnstore implementations, SingleStore supports very fast, small-batch writes (such as single row inserts and updates) directly into columnstore tables.
In some cases, writes (inserts and updates) are implemented by storing newly written rows in a rowstore-oriented skiplist before flushing them to the column-oriented format. Rows are visible to reads as soon as they are committed to the rowstore-oriented skiplist.
In other cases, the rowstore-skiplist is bypassed and writes are made directly to the column-oriented format on disk.
The following explains the behavior of different operations that can be performed against a columnstore.
1. **Insert** - Inserts into a columnstore will either go into the rowstore-backed segment or a new columnstore-backed row segment. In the latter case, the inserts are written directly to disk.
If the engine variable `columnstore_disk_insert_threshold` has a low value, `INSERT...SELECT` `, INSERT ... ON DUPLICATE KEY UPDATE``, INSERT ... IGNORE` and `INSERT` write directly to disk, instead of writing first to rowstore-backed memory. Otherwise, `INSERT` first writes to rowstore-backed memory.
2. **Delete** - Deleting a row in a columnstore causes the row to be marked as deleted in the segment metadata, leaving the data in place within the row segment but not included in the query results. Disk space will not immediately free up because the data remains on the segment. The deleted data is still stored on the segment unless it is merged with another segment. Then the file is rewritten to update the segment metadata. Segments that contain only deleted rows are removed, and the optimization process covered below will compact segments that require optimization.
3. **Update** - An update in a columnstore is internally performed as a delete followed by an insert within a transaction.
If the `columnstore_disk_insert_threshold` engine variable has a low value, `UPDATE` writes directly to disk, instead of writing first to rowstore-backed memory. Otherwise, `UPDATE` first writes to rowstore-backed memory.
4. **Replace**
If the `columnstore_disk_insert_threshold` engine variable has a low value,`REPLACE` writes directly to disk, instead of writing first to rowstore-backed memory. Otherwise, `REPLACE` first writes to rowstore-backed memory.
5. **Optimization** - SingleStore has optimization routines that run automatically and can also be started manually. These routines attempt to automatically merge row segments together in order to improve query efficiency. DML statements can be performed while columnstore optimizations take place. For more information, see the [OPTIMIZE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/optimize-table.md) topic.
SingleStore recommends using the default setting for the `columnstore_disk_insert_threshold` variable, which does straight to disk automatically when the batch is large enough. Lowering the value will increase the creation of small files. This causes the inodes in the file system to fill up rapidly and will require more work for the merger process when merging all these small files. SingleStore does not recommend setting the `columnstore_disk_insert_threshold` variable to zero.
***
Modified at: March 8, 2024
Source: [/cloud/create-a-database/columnstore/writing-columnstore-data/](https://docs.singlestore.com/cloud/create-a-database/columnstore/writing-columnstore-data/)
(An index of the documentation is available at /llms.txt)
---
# Configuring the Columnstore to Work Effectively
> **⚠️ Warning**: Configuration options described in this section may have significant performance impact on the workload. Make sure to test on a staging environment first before deploying the configuration changes.
## Configuring Segment Size in Columnstore Tables
In SingleStore Helios, data in a columnstore table are organized into multiple row segments. For certain workloads, the size of row segments significantly affects performance. Considerations include:
* In general, larger segments compress better than smaller ones. This leads to less disk usage and faster scan across the table.
* On the other hand, smaller segments could benefit more from segment elimination. As a result, queries with highly selective filters on the columnstore index run faster with smaller segments.
In SingleStore Helios, the default size of the row segments is controlled by the global variable `columnstore_segment_rows`. By default, `columnstore_segment_rows` has a value of `1024000`, meaning that each segment contains `1024000` rows by default.
In addition to the global variable, it is possible to overwrite the global setting and set the segment size for a specific columnstore table. This can be done during the table creation, or by altering an existing table. For example:
```sql
CREATE TABLE t (id INT, SORT KEY (id) WITH (columnstore_segment_rows=100000));
SHOW CREATE TABLE t;
```
```output
+-------+-------------------------------------------------------------------------+
| Table | Create Table |
+-------+-------------------------------------------------------------------------+
| t | CREATE TABLE `t` ( |
| | `id` int(11) DEFAULT NULL, |
| | SORT KEY `id` (`id`) |
| | /*!90619 */ /*!90621 WITH(COLUMNSTORE_SEGMENT_ROWS=100000) */ |
| | ) |
+-------+-------------------------------------------------------------------------+
```
Now, modify the value of `columnstore_segment_rows` for this columnstore. The `MODIFY KEY keyName` clause identifies the index whose settings are to be changed (in this case, the columnstore index).
```sql
ALTER TABLE t MODIFY KEY id SET (columnstore_segment_rows=20000);
SHOW CREATE TABLE t;
```
```output
+-------+-----------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-----------------------------------------------------------------------------------+
| t | CREATE TABLE `t` ( |
| | `id` int(11) DEFAULT NULL, |
| | SORT KEY `id` (`id`) |
| | /*!90619 */ /*!90621 WITH(COLUMNSTORE_SEGMENT_ROWS=20000) */ |
| | ) |
+-------+-----------------------------------------------------------------------------------+
```
## Configuring the Rowstore-backed Segment Size in Columnstore Tables
In addition to the on-disk segments, each SingleStore Helios columnstore also has an in-memory rowstore-backed segment.
In some cases, inserts and updates will write to the rowstore-backed segment first. In these cases, the `background flusher` process periodically compresses those recently inserted rows and creates on-disk segments. In other cases, inserts and updates will bypass the rowstore-backed segment, and the writes are made to the column-oriented format on disk. See [Writing Columnstore Data](https://docs.singlestore.com/cloud/create-a-database/columnstore/writing-columnstore-data.md) for more information.
The size of the rowstore-backed segment is controlled by the global variable `columnstore_flush_bytes`. The `background flusher` process starts to create on-disk segments when the amount of data in the rowstore-backed segment exceeds `columnstore_flush_bytes`, with a default of `32 MB`. Additionally, insert and load operations are considered small-batch if they write to each partition less than `columnstore_flush_bytes * columnstore_disk_insert_threshold`, which is by default `16 MB` at a time. The amount of time (in seconds) the background flusher waits before trying to flush a table is set via `internal_columnstore_idle_flush_wait_seconds`. If the table row count has not changed in that period of time then the rows are flushed regardless of the row count. This flushes idle tables that have not reached the threshold.
The minimum size of the disk-backed row segment created by insert and load operations is controlled by the engine variable `columnstore_disk_insert_threshold` . It is a fractional value with a default of `0.5`. Note that if `OPTIMIZE TABLE FLUSH` is manually run, the minimum segment size can be much smaller.
Considerations about tuning the rowstore-backed segment size include:
* The rowstore-backed segment is stored in-memory. Therefore, the table consumes less memory when the rowstore-backed segment is smaller.
* The `background flusher` process can write more rows to disk at once if the rowstore-backed segment is larger, reducing the number of disk write operations during data ingestion.
Similar to `columnstore_segment_rows`, the `columnstore_flush_bytes` value can also be configured per-table with the following syntax:
```sql
CREATE TABLE t2 (id INT, SORT KEY (id) WITH (columnstore_flush_bytes=4194304, columnstore_segment_rows=100000));
ALTER TABLE t2 MODIFY KEY id SET (columnstore_flush_bytes=8388608);
```
## Advanced Columnstore Configuration
If your database utilizes unlimited storage, it might be beneficial to set the `columnstore_small_blob_combination_threshold` engine variable which is the maximum size of a columnstore blob.
SingleStore combines multiple columns from a segment into a single blob. This single blob size must be at most the `columnstore_small_blob_combination_threshold` value.
The `columnstore_small_blob_combination_threshold` engine variable refers to the maximum file size of two or more column blobs. It doesn't apply to the maximum size of individual column blobs. For example, consider the `columnstore_small_blob_combination_threshold` is set to 64mb and there are 3 column blobs sized 31mb, 31mb, and 92mb. The first column blob is 31mb and goes into a file. Then the second column blob is also 31mb. Since `columnstore_small_blob_combination_threshold` is greater than 62mb (the sum of the two column blobs), the second column blob is added to the file with the first column blob. When the third column blob (92mb) is processed, it can't fit into the existing file because the combined size would exceed the threshold. So the third column blob gets its own file, even though it's greater than the threshold value.
> **📝 Note**: SingleStore suggests only advanced users set this engine variable unguided unless told to do so under the direction of our support team.
The following is a use case where setting the maximum value of the `columnstore_small_blob_combination_threshold` variable is beneficial:
* A columnstore table contains a large number of columns, but only a few columns are queried.
* The local blob cache is cold or the data must be read from the remote object store, e.g. the table being read is larger than the cache.
* All blob files have been combined to total nearly 32Mb in size. If a column read by a query is small in comparison, then all 32Mb from the remote object store must be read to access the data for the small column.
Setting the `columnstore_small_blob_combination_threshold` engine variable to a smaller size can make this query run faster by reducing the amount of data that must be read from remote object storage.
***
Modified at: March 18, 2026
Source: [/cloud/create-a-database/configuring-the-columnstore-to-work-effectively/](https://docs.singlestore.com/cloud/create-a-database/configuring-the-columnstore-to-work-effectively/)
(An index of the documentation is available at /llms.txt)
---
# Creating a Columnstore Table
The default table type in SingleStore is columnstore. The default can be changed to rowstore by updating the `default_table_type` engine variable to rowstore. See [List of Engine Variables](https://docs.singlestore.com/cloud/reference/configuration-reference/engine-variables/list-of-engine-variables.md) for more details.
Currently, SingleStore Helios supports one sort key per table; however, if you do not want to define a key (e.g. if records are already inserted in the right order or you do not care about the sort order), `SORT KEY()`.
> **📝 Note**: `KEY() USING CLUSTERED COLUMNSTORE` is a legacy syntax that is equivalent to `SORT KEY()`. SingleStore recommends using `SORT KEY()`.
Here is an example of a query that creates a columnstore table:
```sql
CREATE TABLE products (
ProductId INT,
Color VARCHAR(10),
Price INT,
Qty INT,
SORT KEY (Price),
SHARD KEY (ProductId)
);
```
As with any other SingleStore Helios table, we define a `SHARD KEY` to explicitly control the data distribution. We define it on `ProductId` since sharding on a high cardinality identifier column generally allows for a more even distribution and prevents skew. It is also possible to randomly distribute data by either omitting the shard key, or defining an empty shard key `SHARD KEY()`. You can have at most one shard key that is defined on zero or more columns.
Your columnstore table definition can contain metadata-only unenforced unique keys, single-column and multi-column hash keys (which may be UNIQUE or PRIMARY), and a FULLTEXT key.
For more information on creating columnstore tables that use hash keys, see [USING HASH behavior](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table/#UUID-2d098a7e-1811-6223-8748-d20d3c8b53f6.md).
Besides the keys discussed so far in this section, you cannot add other keys to a columnstore table.
If a sort key is defined on a table, the rows of that table will be stored in a highly compressed columnar format on disk. Storage is optimized for efficient scan in the key order. Use of an empty key in the form of `SORT KEY()` is permitted and results in less expensive background maintenance of the columnstore table, without guaranteeing any particular order.
We describe the details of the format below. While SingleStore Helios can execute any query on a columnstore table that it can execute on a rowstore, some queries are more suitable for columnstore tables than others. Some queries that can benefit from using columnstore include:
* Queries that scan several columns out of a table with many columns. Columnstore table will only materialize columns that it actually needs to perform the query.
* Queries that scan a lot of data in sort key order. Scans in the columnstore key order are more CPU and memory efficient.
* Joins between two columnstore tables on the sort key. Such a join can be executed as a merge join, resulting in a good performance and low memory overhead.
* Queries with high selectivity filters on the sort key. By leveraging a technique called `segment elimination`, SingleStore Helios can open only those row segments that actually contain relevant rows, significantly improving the performance of queries with high selectivity.
Columnstore tables are also not constrained by the amount of available memory, unlike rowstore tables.
## Creating a Columnstore Table Using Standard CREATE TABLE Syntax
The columnstore as default feature allows you to create a columnstore table using standard `CREATE TABLE` syntax.
## The Benefit of Using the Columnstore for Transaction Processing
Although rowstores are well-suited for transaction processing, it can be costly to store large datasets in rowstores, as they store all data in RAM. Because columnstores are disk-based, it is more economical to store data in columnstores as opposed to rowstores.
The columnstore [continues to evolve to support transactional workloads](https://docs.singlestore.com/cloud/create-a-database/columnstore.md) that would have traditionally used the rowstore. At the same time, the columnstore provides the fastest query processing performance for analytical workloads, making it a good choice for a mix of both transactional and analytical requirements.
## Enabling Columnstore as Default
The `default_table_type` engine variable specifies whether `CREATE TABLE` creates a rowstore or columnstore table, by default.
> **📝 Note**: `default_table_type` is set to `columnstore` for clusters created with engine version 7.3 or newer. For clusters created with an engine version prior to 7.3, `default_table_type` remains at `rowstore`, even after the upgrade. You cannot change the value of `default_table_type`.
You can create a rowstore table with `CREATE ROWSTORE TABLE ...`, regardless of the setting of `default_table_type`.
## Conversion of Standard `CREATE TABLE` Syntax to Columnstore `CREATE TABLE` Syntax
When the `default_table_type` is `columnstore`, the query engine internally converts standard `CREATE TABLE` syntax to equivalent columnstore-specific `CREATE TABLE` syntax, as follows:
## `SORT KEY()`
The `SORT KEY()` clause is added, if you have not specified the clause explicitly. For example,
```sql
CREATE TABLE t(a INT, b INT);
```
is equivalent to:
```sql
CREATE TABLE t(a INT, b INT, SORT KEY());
```
## `KEY(...)`
## Single-Column Keys
`KEY()` is equivalent to `KEY() USING HASH`. For example,
```sql
CREATE TABLE t(a INT, b INT, KEY(a));
```
is equivalent to:
```sql
CREATE TABLE t(a INT, b INT, SORT KEY(), KEY(a) USING HASH);
```
## Multi-Column Keys
`KEY(,, ... )` is equivalent to `KEY(,,... ) USING HASH`. For example,
```sql
CREATE TABLE t(a INT, b INT, c INT, KEY(a,b));
```
is equivalent to:
```sql
CREATE TABLE t(a INT, b INT, SORT KEY(), KEY(a,b) USING HASH);
```
Using multi-column unique keys in a columnstore table is supported starting in engine version 7.5.
A query against `t` with an equality filter on `a`, an equality filter on `b`, or equality filters on both `a` and `b` could benefit from `KEY(a,b) USING HASH`. A query that uses both equality filters would be the most efficient.
Unlike other database products, SingleStore utilizes per-segment inverted indexes and cross-segment indexes to support multi-column keys while minimizing storage costs.
Each secondary index contains a collection of multiple cross-segment indexes, each of which is a hash table covering one or more segments. The background merger (An algorithm used by SingleStore that allows columnstore segments to maintain sort order (as close as possible), while data is being ingested or updated.) works to merge the hash tables to reduce the number of lookups necessary for a seek operation.
These data structures work together to accomplish these fast seeks as follows:
* The inverted index is built to map values of an index column to a posting list that stores row offsets within the segment with the value searched. The posting list logs which segment a specific value is located and uses row offsets to determine the value is located.

* The cross-segment indexes map values of each indexed column with the ID of the segment where the searched value is located. The cross-segment indexes also map to the starting location of the corresponding postings list in the inverted index for each segment. Lastly, for a multi-column index like the example above (`KEY(a,b) USING HASH)`), another collection of cross-segment indexes are built on the row of indexed columns to map from the hash of each tuple (`value_a` and `value_b`) to the starting locations of the corresponding per-segment postings lists for `value_a` and `value_b`.

## `UNIQUE KEY`
`UNIQUE KEY()` is created as `UNIQUE KEY() USING HASH`. For example,
```sql
CREATE TABLE t(a INT, b INT, SHARD(a), UNIQUE KEY(a));
```
is equivalent to:
```sql
CREATE TABLE t(a INT, b INT, SORT KEY(), SHARD(a), UNIQUE KEY(a) USING HASH);
```
> **📝 Note**: Columnstore tables do not support multiple unique keys. A unique key must contain all the columns of the shard key. The shard key cannot be empty in this case and can contain multiple columns.A columnstore table can either have a primary key or a unique key, but not both.
## `PRIMARY KEY`
A primary key can be defined for a columnstore table using the `PRIMARY KEY(column_name)` clause or the `PRIMARY KEY` keyword in the `CREATE TABLE` statement. For example:
```sql
CREATE TABLE t(a INT PRIMARY KEY, b INT);
```
```sql
CREATE TABLE t(a INT, b INT, PRIMARY KEY(a));
```
The index behavior is equivalent to defining a key as ``UNIQUE KEY `PRIMARY` (a) USING HASH``. However, semantically these definitions are not the same.
> **📝 Note**: A primary key must contain all the column(s) of the shard key.A columnstore table can either have a primary key or a unique key, but not both.
## Considerations When Using Hash Keys and Sort Keys
> **⚠️ Warning**: The previous section explained that in columnstore as default mode, a standard `CREATE TABLE` statement using `KEY()` stores `` as a hash key in the resulting columnstore table. Hash keys support fast equality lookups, but not fast range filters. If you want to use a range filter on a columnstore, you need to use a sort key `` by explicitly specifying `SORT KEY()` in your `CREATE TABLE` statement.
## Viewing the Storage Structure of a Table
> **📝 Note**: After creating a columnstore table using standard `CREATE TABLE` syntax, run [SHOW CREATE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/show-commands/show-create-table.md) if you wish to see the table’s full, explicit definition of keys and sharding.
## Converting an Existing Rowstore Table to a Columnstore Table
You can convert an existing rowstore table to a columnstore table by creating a new columnstore table, copying the data from the rowstore table to the columnstore table, dropping the rowstore table, and renaming the columnstore table to the rowstore table. For example, suppose you have an existing rowstore table `t` with the columns `a INT` and `b INT`. You can convert this table to a columnstore table as follows, assuming `default_table_type` is set to `columnstore`:
```sql
CREATE TABLE t2(a INT, b INT) AS SELECT * FROM t;
DROP TABLE t;
ALTER TABLE t2 RENAME TO t;
```
## Example Database Schema that is Created with Columnstore as Default
Suppose you want to create a database schema `track_visits` that tracks page visits on a website. For each page (URL) that is visited, you store the host name and path of the URL. For example, for the URL `myexample.com/a/b/`, the host name is `myexample.com` and the path is `a/b`.
For each page that is visited, you store the date/time of the visit and the user who visited the page. You also store the account that each user belongs to.
The schema contains the tables `accounts`, `users`, `webpages` and `webpage_visits`. The definitions for these tables are provided in the [Standard Syntax for Creating the Tables in the Schema](https://docs.singlestore.com/cloud/create-a-database/creating-a-columnstore-table/#UUID-bd806520-e67c-53d2-f56f-f0392e5dafde.md) section.
## Use Case for Using Default as Columnstore to Create the `track_visits` Schema
## Analytical Processing
Columnstores (as compared to rowstores) are optimized for analytical processing. With this schema, you can more quickly answer analytical questions such as:
* How many visits occurred within a particular time period?
* On average, how many visits are there per user?
* On average, how many users are there per account?
* How many unique webpages were clicked?
## Transactional Processing
You can utilize the [Universal Storage](https://docs.singlestore.com/cloud/create-a-database/columnstore/universal-storage.md) capabilities to perform transaction processing operations on the tables in the schema. For example:
* To find all of the webpage visits containing a particular hostname, you can run a query such as `SELECT * FROM webpages WHERE url_host = 'myexample.com';`. This query allows you take advantage of the hash index on `url_host`, which allows the query to run faster than if the hash index was not used.
* To find all of the webpages visited on a particular date and time, you can run a query such as `SELECT * FROM webpage_visits v JOIN webpages w ON v.page_id = w.id WHERE v.when_clicked = '2020-01-01 16:35:00';` This query does a highly selective join, as there are only a few records in `webpage_visits` that match the equality filter on `when_clicked`.
## Standard `CREATE TABLE` Syntax for Creating the Tables in the `track_visits` Schema
Following are the `CREATE TABLE` statements for the tables in the `track_visits` schema. The statements use standard `CREATE TABLE` syntax. The statements are run in columnstore as default mode.
```sql
CREATE DATABASE track_visits;
USE track_visits;
CREATE REFERENCE TABLE accounts(
id INT AUTO_INCREMENT,
name TEXT,
PRIMARY KEY(id),
UNIQUE KEY(name)
);
CREATE TABLE users (
id BIGINT AUTO_INCREMENT,
user_name TEXT,
account_id BIGINT,
PRIMARY KEY (id)
);
CREATE TABLE webpages(
id BIGINT AUTO_INCREMENT,
url_host TEXT,
url_path TEXT,
PRIMARY KEY (id),
KEY(url_host)
);
CREATE TABLE webpage_visits(
id BIGINT AUTO_INCREMENT,
user_id BIGINT,
page_id INT,
when_clicked DATETIME,
PRIMARY KEY (id),
KEY (user_id, page_id),
KEY (when_clicked)
);
```
## Storage Structure of Tables in the `track_visits` Schema
The following definitions show the structure of the tables in the `track_visits` schema after they are stored as a result of running the [standard CREATE TABLE statements](https://docs.singlestore.com/cloud/create-a-database/creating-a-columnstore-table.md).
> **📝 Note**: `INT`, and `BIGINT`, which are used in the standard `CREATE TABLE` statements, are stored as `INT(11)` and `BIGINT(20)`, respectively.In some cases, `TEXT` is stored as `BLOB` (they are equivalent).This behavior is independent of the columnstore as default feature.
## `accounts`
```sql
CREATE REFERENCE TABLE accounts(
id INT NOT NULL AUTO_INCREMENT,
name TEXT,
UNIQUE KEY `PRIMARY` (id) USING HASH,
UNIQUE KEY(name) USING HASH,
SORT KEY()
);
```
## `users`
```sql
CREATE TABLE users (
id BIGINT(20) NOT NULL AUTO_INCREMENT,
user_name TEXT,
account_id BIGINT,
SHARD(id),
UNIQUE KEY `PRIMARY` (id) USING HASH,
SORT KEY()
);
```
## `webpages`
```sql
CREATE TABLE webpages(
id BIGINT NOT NULL AUTO_INCREMENT,
url_host BLOB,
url_path BLOB,
SHARD(id),
UNIQUE KEY `PRIMARY` (id) USING HASH,
KEY(url_host) USING HASH,
SORT KEY()
);
```
## `webpage_visits`
```sql
CREATE TABLE webpage_visits(
id BIGINT(20) NOT NULL AUTO_INCREMENT,
user_id BIGINT(20),
page_id INT(11),
when_clicked DATETIME,
SHARD(id),
UNIQUE KEY `PRIMARY` (id) USING HASH,
KEY(user_id, page_id) USING HASH,
KEY (when_clicked) USING HASH,
SORT KEY()
);
```
## Querying `webpage_visits` Using a Range Filter
If you intend to query `webpage_visits` using a range filter on `when_clicked`, you could have made `when_clicked` the sort key. You could have done this using the following standard `CREATE TABLE` syntax.
```sql
CREATE TABLE webpage_visits(
id BIGINT AUTO_INCREMENT,
user_id BIGINT,
page_id INT,
when_clicked DATETIME,
PRIMARY KEY (id),
KEY (user_id, page_id),
SORT KEY (when_clicked)
);
```
The query engine would internally convert the standard `CREATE TABLE` syntax to equivalent columnstore-specific `CREATE TABLE` syntax, as follows:
```sql
CREATE TABLE webpage_visits(
id BIGINT AUTO_INCREMENT,
user_id BIGINT,
page_id INT,
when_clicked DATETIME,
UNIQUE KEY `PRIMARY` (id) USING HASH,
KEY (user_id) USING HASH,
KEY (page_id) USING HASH,
SORT KEY (when_clicked)
);
```
***
Modified at: September 17, 2025
Source: [/cloud/create-a-database/creating-a-columnstore-table/](https://docs.singlestore.com/cloud/create-a-database/creating-a-columnstore-table/)
(An index of the documentation is available at /llms.txt)
---
# Detecting and Resolving Data Skew
An important property of a distributed database is that the data gets distributed more or less evenly. In rare cases the data may be “skewed” out of balance. This topic discusses how skew can happen, how to detect it, and how to resolve it.
“Skew” is a condition in which a table’s data is unevenly balanced among partitions in the cluster. Probability being what it is, small amounts of skew are inevitable and harmless. By default, SingleStore distributes data based on a hash of the primary key. Since the hash values are unique and evenly distributed, this keeps skew to a minimum.
You can tell SingleStore to shard a table by a set of columns instead of the primary key. For example, consider a table of URLs from web domains. It might be defined as follows:
```sql
CREATE TABLE urls (
id BIGINT,
domain_id BIGINT,
path VARCHAR(8192),
first_seen INT UNSIGNED NOT NULL,
crawl count INT UNSIGNED NOT NULL,
SHARD KEY (domain_id)
);
```
As you can see, we are sharding on `domain_id`. Queries made against this table will compile and run just fine. However, it’s probable that some domains will have many more times the number of URLs. For example, the partition that contains links for “youtube.com” will almost certainly have more rows than average, throwing off the balance of the cluster. That unlucky partition containing “youtube.com” will not only have to store more data, it will probably be asked to do more work during `SELECT`, `UPDATE`, and `DELETE` queries. For best performance, you should choose a shard key that minimizes data skew.
## Measuring and Detecting Skew
> **📝 Note**: While bulk-loading data, recovering from a restart, or after deleting lots of data, it’s possible that one partition may temporarily show more memory use and memory skew than others, as memory allocation and garbage collection operations may not take effect immediately across partitions. This is normal, and corrects itself over time as the system reaches a new steady state.
You can use the following methods to measure and detect data skew.
## Method 1: Inspect memory settings
With any version of SingleStore, you can manually compare `maximum_table_memory` and `Alloc_table_memory` (memory used by tables) on each node:
```sql
SHOW VARIABLES LIKE "maximum_%";
```
```output
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| maximum_memory | 48291 |
| maximum_table_memory | 43462 |
+----------------------+-------+
```
```sql
SHOW STATUS EXTENDED LIKE "Alloc_table_memory";
```
```output
+--------------------+----------+
| Variable_name | Value |
+--------------------+----------+
| Alloc_table_memory | 43462 MB |
+--------------------+----------+
1 row in set (0.01 sec)
```
If memory consumption is significantly higher on specific nodes, skew is present. If memory consumption is fairly uniform across the leaf nodes, no skew is present.
## Method 2: Find the number of rows and memory use per partition
The built-in `INFORMATION_SCHEMA` database contains metadata about tables, columns, indexes, and partitions. In particular, the `TABLE_STATISTICS` table contains one row per table partition, and can be used to see if a given partition has a lot more rows than average:
```sql
SELECT
DATABASE_NAME,
TABLE_NAME,
ORDINAL AS PARTITION_ID,
ROWS,
MEMORY_USE
FROM INFORMATION_SCHEMA.TABLE_STATISTICS
WHERE TABLE_NAME = 'domains';
```
```output
+---------------+------------+--------------+-------+------------+
| DATABASE_NAME | TABLE_NAME | PARTITION_ID | ROWS | MEMORY_USE |
+---------------+------------+--------------+-------+------------+
| web | domains | 0 | 85916 | 11527936 |
| web | domains | 1 | 85925 | 11528512 |
| web | domains | 2 | 85427 | 11627712 |
| web | domains | 3 | 86185 | 11545152 |
| web | domains | 4 | 85592 | 11376128 |
| web | domains | 5 | 85549 | 11504448 |
...
```
## Method 3: Calculate the memory skew for all tables, per database
Use the [relative standard deviation (RSD)](http://en.wikipedia.org/wiki/Relative_standard_deviation) to calculate the memory skew across all partitions and tables in your database. The RSD is a decent way to measure “skewness”.
```sql
SELECT
DATABASE_NAME,
TABLE_NAME,
FLOOR(AVG(ROWS)) AS avg_rows,
ROUND(STDDEV(ROWS)/AVG(ROWS),3) * 100 AS row_skew,
FLOOR(AVG(MEMORY_USE)) AS avg_memory,
ROUND(STDDEV(MEMORY_USE)/AVG(MEMORY_USE),3) * 100 AS memory_skew
FROM INFORMATION_SCHEMA.TABLE_STATISTICS
GROUP BY 1, 2
HAVING SUM(ROWS) > 10000
ORDER BY row_skew DESC;
```
```output
+---------------+----------------------+----------+----------+--------------+-------------+
| DATABASE_NAME | TABLE_NAME | avg_rows | row_skew | avg_memory | memory_skew |
+---------------+----------------------+----------+----------+--------------+-------------+
| web | urls | 28881401 | 9.520 | 25733328291 | 3.200 |
| web | domains | 902817 | 0.100 | 111046491 | 0.200 |
...
```
A skew score of N means that there is about N% variation in the number of rows (or memory allocated) in a partition. As a general rule of thumb, skew less than 10% should not greatly affect system stability or performance and is not a cause for worry. If you do see persistent skew and observe other issues as well, such as a server running particularly “hot”, then you should further investigate the distribution of the values in your chosen shard keys.
## Method 4: Calculate the skew per partition for the columns in a table
Again, use the [relative standard deviation (RSD)](http://en.wikipedia.org/wiki/Relative_standard_deviation) to calculate the memory skew across all partitions in a specific tables in your database.
If the skew factor is high, that indicates that some partitions have very high cardinality and some have very low cardinality and can lead to long single-threaded operations.
Considering the `urls` table above, you can calculate the data skew per partition in the following example:
```sql
SELECT ROUND(STDDEV(id)/AVG(id),3)*100 AS group_skew,
PARTITION_ID()
FROM (SELECT id,
domain_id,
count(*)
FROM urls
GROUP BY 1, 2) sub
GROUP BY PARTITION_ID();
```
## Method 5: Show the data distribution for a table if you were to reshard on another column or set of columns
Run this query to check for data skew prior to making shard key changes:
```sql
SELECT with(leaf_pushdown=true)
SUM(c) rows,
PARTITION_ID()
FROM (SELECT count(*) c FROM GROUP BY ) reshuffle
GROUP BY PARTITION_ID();
```
Considering the `urls` table above, you can show the potential distribution of data if the table is resharded on a different column or set of columns. See the following example:
```sql
SELECT with(leaf_pushdown=true)
SUM(c) rows,
PARTITION_ID()
FROM (SELECT count(*) c FROM urls GROUP BY id) reshuffle
GROUP BY PARTITION_ID();
```
```output
+---------+----------------+
| rows | PARTITION_ID() |
+---------+----------------+
| 2005 | 1 |
| 1999 | 3 |
| 2001 | 4 |
+---------+----------------+
```
This example shows if the `urls` table is resharded on the `id` column, there would be a more even distribution of data on each partition.
## Resolving Data Skew
SingleStore distributes data based on the SHARD KEY specified in a table’s schema. If no SHARD KEY is explicitly specified, the PRIMARY KEY is used as the default SHARD KEY. If the SHARD KEY shards on a low cardinality column, data will accumulate on certain nodes. To resolve this, you should export your data, modify your schema, and then reload your data.
To export your data, see [Export Data](https://docs.singlestore.com/cloud/manage-data/export-data.md). After you backup your data, you can `DROP TABLE low_cardinality_shard_key_table`, and then `CREATE TABLE` with a higher cardinality SHARD KEY. When you reload the data, SingleStore will automatically shard your data based on the new SHARD KEY.
Example:
```shell
$ mysqldump -h 127.0.0.1 -u root my_db low_cardinality_shard_key_table --no-create-info > databackup.sql
```
```sql
DROP TABLE low_cardinality_shard_key_table;
source updated_shard_key_schema.sql;
```
***
Modified at: July 10, 2026
Source: [/cloud/create-a-database/detecting-and-resolving-data-skew/](https://docs.singlestore.com/cloud/create-a-database/detecting-and-resolving-data-skew/)
(An index of the documentation is available at /llms.txt)
---
# Multi-Value Hash Index (JSON)
Multi-Value Hash index optimizes lookups within JSON objects and arrays. It can efficiently find rows where a JSON array contains a specific value or where a specific key-path holds an exact value match.
For example, if an **orders** table has a JSON column **details** with the following data:
```JSON
{"product_id":[{"id":1001,"type":"flour"},{"id":1002,"type":"yeast"}]}
```
An index created on the **details** column at the path **\["product\_id"**, **"id"]** enables exceptionally fast lookups for **orders** by **product\_id.id**.
To index values at the top level in an array, specify an empty path array, such as, `"PATH":[]`. For example, if you have a column containing a top-level JSON array like `[1,2,3]`, you can accelerate searches for values within the array.
The multi-value hash index stores pairs of values along with the list of row IDs where that value occurs. Since each value is stored only once, the index remains compact even when values are repeated across many rows.
This index is fundamentally a hash index, leveraging the same high-performance technology as the regular columnar hash indexes.
## Syntax
```sql
-- Adding the multi-value index to a new table --
CREATE TABLE
( JSON NULL,
MULTI VALUE INDEX(col) INDEX_OPTIONS='');
-- Adding the multi-value index an to existing table column --
ALTER TABLE
ADD MULTI VALUE INDEX (col) INDEX_OPTIONS='';
```
where `` is a JSON object to specify the tokenizer and other metadata related to it.
```sql
'{"TOKENIZER":"MATCH_ANY", "PATH":[]}'
```
where `` is a comma-separated list of values that specify the path to the field that needs to be indexed. If an empty path array, such as, `"PATH":[]`, is specified, then the top-level elements in the array are indexed (such as \[1,2,3]).
## Using the Multi-Value Hash Index
The multi-value hash index can optimize queries that use the [JSON\_MATCH\_ANY](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-match-any.md) function. This function checks for the existence of values inside JSON data and can be used to find values that are valid JSON types (object, array, integer, float, string, boolean, or JSON `null`)
> **📝 Note**: To use the multi-value hash index, the [filter predicate](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-match-any/#section-idm234523191190095.md) in the `JSON_MATCH_ANY` function must use the `MATCH_PARAM_JSON` expression.When matching string values with `JSON_MATCH_ANY` and `MATCH_PARAM_JSON`, string values must be JSON strings with quotes.Use either of the following to create JSON strings:- Use [TO\_JSON](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/to-json.md) to convert a string to a JSON string.
> - Manually specify a quoted constant string literal, for example `'"val"'`.
**Note**: Typecasting to JSON using `:>JSON` does not automatically wrap an unquoted string into a JSON string. (However, casting works to convert numeric types to their respective JSON type. For example, `2.5:>JSON` converts `2.5` into a JSON double.)
**Supported Query Shapes**
```sql
JSON_MATCH_ANY(MATCH_PARAM_JSON() = , )
JSON_MATCH_ANY(MATCH_PARAM_JSON() <=> , )
JSON_MATCH_ANY(MATCH_PARAM_JSON() IN (, ..), '')
```
**Shorthand Syntax**
You can also use JSON shorthand syntax (`::` operators) in `JSON_MATCH_ANY` predicates.
```sql
JSON_MATCH_ANY(::?, MATCH_PARAM_JSON() = )
JSON_MATCH_ANY(::?, MATCH_PARAM_JSON() <=> )
JSON_MATCH_ANY(::?, MATCH_PARAM_JSON() IN (, ..))
```
`` can be a constant literal (such as a string, integer, float), a typecast operator (`:>`, `!:>`), a user-defined variable (UDV), a deterministic built-in expression (most built-in functions, except for non-deterministic ones like `UUID()` or `RAND()`), or a combination of these.
In general, the lookup value must remain constant during query execution. If the value changes per row, such as a column reference, then the index cannot be effectively used and the query falls back to a regular table scan.
The index is only used for queries that match the exact `` defined during index creation. For example, if the index is created on **addresses::city**, the query benefits from the index only when filtering values specifically under this path. It is not applied to deeper paths like **addresses::city::district** or to sibling keys like **addresses::zip**. To apply the index to any other path, you must create a separate index.
To check whether the index was used for your query filter, run an `EXPLAIN` query - the phrase **multi-value hash index** in the predicate under **ColumnStoreFilter** indicates that the index was used..
```sql
EXPLAIN SELECT col
FROM t
WHERE JSON_MATCH_ANY(MATCH_PARAM_JSON() = TO_JSON('type'), col, 'key1');
```
```output
+--------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+--------------------------------------------------------------------------------------------------------------+
| Project [t.col] |
| ColumnStoreFilter [JSON_MATCH_ANY(MATCH_PARAM_JSON() = TO_JSON('type'), t.col, 'key1') multi-value hash index] |
| ColumnStoreScan db.t, SORT KEY __UNORDERED () table_type:sharded_columnstore |
+--------------------------------------------------------------------------------------------------------------+
```
## Remarks
* Multi-value hash index is case-sensitive for JSON types.
* Multi-value hash index for JSON activates when matched using the following operators: `=`, `<=>`, and `IN()`.
* The following table lists the expressions that support Multi-Value Hash Index for each of these operators:
| Operator | Supported Expression |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `=`,`<=>` | - Constant literals, for example strings,
NULL, DOUBLE, INT, etc. - Typecast operators
:> and !:>, for example, 100001:>JSON. - User-defined variables (UDVs), for example:
SET @obj = '{"city": "New York"}':>JSON; SELECT a:>JSON FROM t WHERE JSON_MATCH_ANY(MATCH_PARAM_JSON()=@obj, a, 'city');
- Procedural SQL variables (stored procedure arguments and local variables).
- Nested constant (deterministic) built-in expressions, for example:
JSON_BUILD_ARRAY(JSON_SET_JSON('{}', 'a', @json), '{"a":4}':>JSON)
- A combination of all of the above.
|
| `IN()` | - Parameterized
IN lists with: - Literals of the same types
- Single argument built-in expressions of the same shape and literal types in the list, for example,
IN(HEX('a'), HEX('b')).
|
## Limitations
* The [filter predicate](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-match-any/#section-idm234523191190095.md) in `JSON_MATCH_ANY` must use the `MATCH_PARAM_JSON` expression.
* Only runtime constant expressions are supported for matching (i.e. UDV, builtins, typecasts, PSQL variables are supported; UDFs and column fields are not supported).
* Using `OR` inside a `JSON_MATCH_ANY` predicate (for example, `JSON_MATCH_ANY(MATCH_PARAM_JSON() = 12 OR MATCH_PARAM_JSON() = 1, a, 'a'))` disables index usage. Instead, use either an `IN` list or multiple `JSON_MATCH_ANY` filters.
* Only parameterized `IN` list is supported.
* Indexing multiple key paths for the same JSON field requires separate indexes, for example, to index both **a::k1** and **a::k2**, you must create two indexes.
* This index is supported only for columnstore tables.
* Multi-value index for JSON does not support the following:
* References to other unindexed fields on the right-hand side of an expression.
* Non-deterministic built-in functions, for example `RAND()`.
* `JSON_MATCH_ANY` predicate with `MATCH_ELEMENTS` option.
* `!=` and other comparison operators (excluding `=` and `<=>`).
* `NOT IN` lists.
## Examples
## Example 1- Searching `users` by `city`
Consider the following table definition:
```sql
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
created DATETIME(6) DEFAULT NOW(6),
data JSON
);
```
User records are stored in the `data` column as JSON documents with the following structure:
```sql
INSERT INTO users (data) VALUES
('{"id":1,"name":"Alice","addresses":[{"street":"123 Main St","city":"New York","zip":"10001"},{"street":"456 Oak Ave","city":"Los Angeles","zip":"90001"}]}'),
('{"id":2,"name":"Bob","addresses":[{"street":"789 Pine Ln","city":"Chicago","zip":"60601"}]}'),
('{"id":3,"name":"Charlie","addresses":[{"street":"101 Elm St","city":"New York","zip":"10002"},{"street":"222 Maple Dr","city":"Houston","zip":"77001"}]}');
```
Adding a multi-value Hash Index to the path "**addresses, city**" can significantly improve lookup performance.
```sql
ALTER TABLE users ADD MULTI VALUE INDEX (data)
INDEX_OPTIONS='{"TOKENIZER":"MATCH ANY","PATH":["addresses", "city"]}';
```
Find all `users` who live in Houston using the `JSON_MATCH_ANY` built-in function.
```sql
SELECT id, data::name FROM users
WHERE JSON_MATCH_ANY(MATCH_PARAM_JSON()='"Houston"', data, 'addresses', 'city');
```
```output
+----+------------+
| id | data::name |
+----+------------+
| 3 | "Charlie" |
+----+------------+
```
The following example rewrites the previous query using shorthand syntax:
```sql
SELECT id, data::name FROM users
WHERE JSON_MATCH_ANY(data::?addresses.city, MATCH_PARAM_JSON() = '"Houston"');
```
```output
+----+------------+
| id | data::name |
+----+------------+
| 3 | "Charlie" |
+----+------------+
```
To verify that the multi-value hash index was used, run the `EXPLAIN` query as:
```sql
EXPLAIN SELECT id, data::name FROM users
WHERE JSON_MATCH_ANY(MATCH_PARAM_JSON()='"Houston"', data, 'addresses', 'city');
```
```output
+-----------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-----------------------------------------------------------------------------------------------------------------------------+
| Gather partitions:all alias:remote_0 parallelism_level:segment |
| Project [users.id, JSON_EXTRACT_JSON(users.data,'name') AS `data::name`] |
| ColumnStoreFilter [JSON_MATCH_ANY(MATCH_PARAM_JSON() = '\"Houston\"',users.data,'addresses','city') multi-value hash index] |
| ColumnStoreScan db1.users, SORT KEY __UNORDERED () table_type:sharded_columnstore |
+-----------------------------------------------------------------------------------------------------------------------------+
```
## Example 2 - Multiple indexes
In this example, two separate multi-value hash indexes are used to optimize common lookup patterns on a JSON column for the following two fields:
* An integer field **eventId**
* A string array **tags**
These indexes help speed up queries that filter by **eventID** and check for specific tags without scanning the entire table.
1. Create a table.
```sql
CREATE TABLE events (
id BIGINT PRIMARY KEY,
created DATETIME(6),
payload JSON
);
```
2. Add multi-value hash indexes via `ALTER TABLE`.
```sql
ALTER TABLE events
ADD MULTI VALUE INDEX idx_event_id (payload)
INDEX_OPTIONS = '{"TOKENIZER": "MATCH ANY", "PATH": ["eventId"]}';
ALTER TABLE events
ADD MULTI VALUE INDEX idx_tags (payload)
INDEX_OPTIONS = '{"TOKENIZER": "MATCH ANY", "PATH": ["tags"]}';
```
3. Insert data into the table.
```sql
INSERT INTO events VALUES
(1, NOW(6), JSON_BUILD_OBJECT('eventId', 101, 'tags', JSON_BUILD_ARRAY('sports', 'outdoor', 'fun'))),
(2, NOW(6), JSON_BUILD_OBJECT('eventId', 202, 'tags', JSON_BUILD_ARRAY('music', 'concert'))),
(3, NOW(6), JSON_BUILD_OBJECT('eventId', 101, 'tags', JSON_BUILD_ARRAY('sports', 'indoor')));
```
4. Query using both the indexed fields:
```sql
SELECT *
FROM events
WHERE JSON_MATCH_ANY(MATCH_PARAM_JSON() = 101:>JSON,
payload, 'eventId')
AND JSON_MATCH_ANY(MATCH_PARAM_JSON() = TO_JSON('sports'),
payload, 'tags');
```
```output
+----+----------------------------+---------------------------------------------------+
|id | created | payload |
+----+----------------------------+---------------------------------------------------+
| 1 | 2025-04-29 15:36:52.797432 | {"eventId":101,"tags":["sports","outdoor","fun"]} |
| 3 | 2025-04-29 15:36:52.797432 | {"eventId":101,"tags":["sports","indoor"]} |
+----+----------------------------+---------------------------------------------------+
```
The following example rewrites the previous query using shorthand syntax:
```sql
SELECT *
FROM events
WHERE JSON_MATCH_ANY(payload::?eventId, MATCH_PARAM_JSON() = 101:>JSON)
AND JSON_MATCH_ANY(payload::?tags, MATCH_PARAM_JSON() = TO_JSON('sports'));
```
```output
+----+----------------------------+---------------------------------------------------+
| id | created | payload |
+----+----------------------------+---------------------------------------------------+
| 3 | 2026-04-02 17:36:43.595620 | {"eventId":101,"tags":["sports","indoor"]} |
| 1 | 2026-04-02 17:36:43.595620 | {"eventId":101,"tags":["sports","outdoor","fun"]} |
+----+----------------------------+---------------------------------------------------+
```
5. Verify index usage from the query `EXPLAIN`:
```sql
EXPLAIN SELECT * FROM events
WHERE JSON_MATCH_ANY(MATCH_PARAM_JSON() = 101:>JSON, payload, 'eventId')
AND JSON_MATCH_ANY(MATCH_PARAM_JSON() = TO_JSON('sports'), payload, 'tags');
```
```output
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Gather partitions:all alias:remote_0 parallelism_level:segment |
| Project [events.id, events.created, events.payload] |
| ColumnStoreFilter [JSON_MATCH_ANY(MATCH_PARAM_JSON() = (101:>JSON COLLATE utf8mb4_bin NULL), events.payload, 'eventId') multi-value hash index AND JSON_MATCH_ANY(MATCH_PARAM_JSON() = TO_JSON('sports'), events.payload, 'tags') multi-value hash index] |
| ColumnStoreScan db1.events, SORT KEY __UNORDERED () table_type:sharded_columnstore |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```
***
Modified at: July 14, 2026
Source: [/cloud/create-a-database/multi-value-hash-index-json/](https://docs.singlestore.com/cloud/create-a-database/multi-value-hash-index-json/)
(An index of the documentation is available at /llms.txt)
---
# Optimizing Table Data Structures
This guide assumes the reader is familiar with the following concepts:
* How to [connect to SingleStore Helios](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools.md)
* Creating tables and [running queries](https://docs.singlestore.com/cloud/query-data.md) in a SQL database
* [Why you would add an index to a table](https://docs.singlestore.com/cloud/query-data/query-tuning.md)
## In this section
* [Key Considerations for Understanding Your Workload](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/key-considerations-for-understanding-your-workload.md)
* [Shard Keys](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/shard-keys.md)
* [Choosing Rowstore Keys](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/choosing-rowstore-keys.md)
* [Choosing a Columnstore Key](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/choosing-a-columnstore-key.md)
***
Modified at: March 15, 2023
Source: [/cloud/create-a-database/optimizing-table-data-structures/](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/)
(An index of the documentation is available at /llms.txt)
---
# Choosing a Columnstore Key
Columnstore tables have exactly one index, the sort key. Using this sort key, columnstores group the rows into logical segments, where each segment contains data for many rows. The sort key controls the ordering of data in the blobs that compose the segment’s data. Data within a segment is stored on disk into segment files containing the same field for many rows. This enables two important capabilities. One is to scan each column individually; in essence, being able to scan only the columns that are needed to execute a query with a high degree of locality. The other capability is that columnstores lend themselves well to compression; for example, repeating and similar values can be easily compressed together.
In addition, SingleStore Helios stores metadata for each row segment in memory, which includes the minimum and maximum values for each column contained within the segment. This metadata is used at query execution time to determine whether a segment can possibly match a filter, a process known as segment elimination.
For example, we will use this columnstore table:
```sql
CREATE TABLE products (
ProductId INT,
Color VARCHAR(10),
Price INT,
Quantity INT,
SORT KEY (Price)
);
```
The following table represents a logical arrangement of the data in a single partition of the database:
| ProductId | Color | Price | Quantity |
| --------- | ----- | ----- | -------- |
| 1 | Red | 10 | 2 |
| 2 | Red | 20 | 2 |
| 3 | Black | 20 | 2 |
| 4 | White | 30 | 2 |
| 5 | Red | 20 | 2 |
| 6 | Black | 10 | 2 |
| 7 | White | 25 | 2 |
| 8 | Red | 30 | 2 |
| 9 | Black | 50 | 2 |
| 10 | White | 15 | 2 |
| 11 | Red | 5 | 2 |
| 12 | Red | 20 | 2 |
| 13 | Black | 35 | 2 |
| 14 | White | 30 | 2 |
| 15 | Red | 4 | 2 |
Since this is a columnstore table, the data is split into segments. Column segments typically contain on the order of tens of thousands of rows; in this example, the segment size is 5 rows for readability. In addition, we will use the convention “x N” to indicate that a value is repeated N times.
*Row segment #1 of 3*:

*Row segment #2 of 3*:

*Row segment #3 of 3*:

In this example, we can see there are 3 segments containing different ranges of the `Price` column (4-15, 20-25, and 30-50). Each segment has the same number of rows and is organized data by column. For each column, we store the minimum and maximum values in the segment as metadata.
## Segment Elimination
The single most important consideration for columnstore tables is setting a sort key. Each segment file contains metadata that holds the minimum and maximum values for the rows in the segment. The minimum/maximum value metadata is used at query execution time to determine whether a segment can possibly match a filter; if not, the segment is skipped entirely and no data is examined. This functionality is called segment elimination because the segment is eliminated from the scan.
For queries that filter on the sort key column of the columnstore index, segment elimination is typically very efficient as row segments within each row segment group will not have overlapping segments.
For example, in the above table the query `SELECT AVG(Price), AVG(Qty) FROM Products WHERE Price BETWEEN 1 AND 10;` will eliminate all segments except row segment #1 Price 4-15.
The segment size (number of rows per segment) also impacts query execution with respect to the sort key. A smaller segment size means that a smaller number of rows are read from the segments that pass segment elimination. Column segments typically contain on the order of tens of thousands of rows.
Indexing further cuts down on the number of rows scanned when a select query with a `WHERE` clause is executed. If the table has an index for the columns in the `WHERE` clause, the engine can quickly determine the location of the matching rows position to seek without having to look at all the data. This is much faster than reading every row sequentially.
Sub-segment elimination is also supported. Refer to [Understanding Sort Key Selection](https://docs.singlestore.com/cloud/create-a-database/understanding-sort-key-selection.md) for more information.
## Ordered Scans
Ordered scan over a sort key is faster than sorting a table. A query that sorts with a sort key can benefit from running an ordered columnstore scan instead of performing a normal columnstore scan.
## Questions to Ask When Choosing a Columnstore Key:
* Is the data always filtered by some column (e.g. insert timestamp or event type)? Ensure that the common columns for all queries are in the sort key to improve segment elimination.
* Is the data generally inserted in order by some column (e.g. insert timestamp)? It’s best to put that column first in the sort key to minimize the amount of work required by the background columnstore segment merger.
* Does one column in your key have a higher cardinality than the other? It’s best to put the lowest cardinality columns first to increase the likelihood that segment elimination will be able to affect later columns.
## Check Your Understanding
**Q**: Can the columnstore key and the shard key be different?
**A**: Absolutely – they are not related at all. It is very common to pick a shard key that matches other rowstore tables (e.g. `event_id`) to improve join performance and to pick an unrelated columnstore key that matches the common filters on the table (e.g. `event_timestamp` or `event_type`).
**Q**: Is `(insert_datetime6, region_id)` a good columnstore key?
**A**: Not necessarily, because the number of distinct microsecond precision timestamps is likely very high. The partitioning of data into segments will likely be entirely controlled by `insert_datetime6` and not use `region_id`. This means that queries scanning microseconds of data will get good segment elimination, because they’ll match fewer segments. However, queries that scan days or months of data would not benefit from segment elimination on `region_id`. If the data is frequently accessed days or months at a time, it would be better to truncate the precision of the timestamp. For example, use a datetime type or a computed column of `DATE_TRUNC('hour', insert_datetime6)`. In general, your columnstore key should not be more precise than your query filters.
For more information, see [How the Columnstore Works](https://docs.singlestore.com/cloud/create-a-database/columnstore/how-the-columnstore-works.md).
***
Modified at: July 24, 2025
Source: [/cloud/create-a-database/optimizing-table-data-structures/choosing-a-columnstore-key/](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/choosing-a-columnstore-key/)
(An index of the documentation is available at /llms.txt)
---
# Choosing Rowstore Keys
You may define indexes, also called keys, on SingleStore Helios rowstore tables. SingleStore Helios uses these keys to efficiently find specific rows.
There are two storage types for rowstore indexes: a lockfree skiplist and a lockfree hash table. In both cases, we use lockfree data structures to optimize the performance of concurrent updates to the table.
* By default, indexes are stored as skiplists, which have similar functional and performance characteristics as B-trees in other databases. A skiplist is a data structure optimized for ordered data that stores rows in collections of increasingly smaller ordered lists. Queries can quickly seek data by binary searching using the different sized lists and can quickly scan over ranges of data by iterating over the largest list. For multi-column indexes, query filters must match a prefix of the index column list to be able to take advantage of the index.
* A hash table is a data structure optimized for fast lookups, which stores rows in a sparse array of buckets indexed by a hash function on the relevant columns. Queries can quickly find exact match data by examining only the bucket identified by the hash function, but cannot easily scan over a subset of the table. For multi-column indexes, query filters must match all of the index columns to be able to take advantage of the index. Due to this inflexibility, we discourage the use of hash indexes. They should only be used when there is a demonstrated need and measurable benefit on your particular dataset and workload.
Another consideration when choosing an index is the overhead of adding another index. Each added index uses extra memory for the additional data structures – on average about 40 bytes per row – and slightly slows inserts due to the additional data structures that need to be updated.
Each rowstore table may have at most one primary key and optionally many secondary keys. Scans on the primary key are generally somewhat faster than on secondary keys. For example, if the data was inserted in primary key order, the rows would be in memory order for the primary key and have better cache locality for the primary key than for a secondary key.
For more information, refer to the following two resources:
* [The Story Behind SingleStore’s Skiplist Indexes](https://www.singlestore.com/blog/what-is-skiplist-why-skiplist-index-for-memsql/)
* [Indexes for filters](https://docs.singlestore.com/cloud/query-data/query-tuning/#UUID-751c4d8c-49b4-edcb-9638-9e0af5b1d807.md)
## Check Your Understanding
**Q**: For the table, `CREATE ROWSTORE TABLE t(a INT, b INT, KEY (a, b))`, will the query `SELECT SUM(a) FROM t WHERE b = 3` benefit from the index?
**A**: No, since the only column in the filter list, `b`, is not a prefix of the key `(a, b)`, the query cannot benefit from the index. The query `SELECT SUM(a) FROM t WHERE a = 3` would be able to benefit from the index since `a` is a prefix of the key `(a, b)`.
***
Modified at: February 22, 2023
Source: [/cloud/create-a-database/optimizing-table-data-structures/choosing-rowstore-keys/](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/choosing-rowstore-keys/)
(An index of the documentation is available at /llms.txt)
---
# Key Considerations for Understanding Your Workload
Before attempting any schema design, it is critical to understand the nature of the workload. Ask yourself the following questions before getting started:
* Is data loaded in trickles, large batches, or concurrent inserts? Is data frequently updated? See the [Load Data](https://docs.singlestore.com/cloud/load-data.md) and [Concurrent Multi-Insert Examples](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples.md) pages to learn more.
* Is data ingest speed more important than query performance? See the [Query Tuning](https://docs.singlestore.com/cloud/query-data/query-tuning.md) page for more information.
* Are the queries mostly working with a small subset of rows related to the entire dataset (probably 0.1% or less)? Are the queries dealing with the entire dataset or a big subset of the data? See the [Use the Workload Manager](https://docs.singlestore.com/cloud/user-and-cluster-administration/use-the-workload-manager-and-set-resource-limits/use-the-workload-manager.md) page to learn more.
* Which tables do you tend to join and what columns do you use to join them? See the [Query Performance Tools](https://docs.singlestore.com/cloud/query-data/query-tuning/query-performance-tools.md) page for more information on how to improve join performance.
* What columns do you tend to use in filters? See the [Query Performance Tools](https://docs.singlestore.com/cloud/query-data/query-tuning/query-performance-tools.md) page for more information about how to improve query filtering performance.
***
Modified at: February 6, 2025
Source: [/cloud/create-a-database/optimizing-table-data-structures/key-considerations-for-understanding-your-workload/](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/key-considerations-for-understanding-your-workload/)
(An index of the documentation is available at /llms.txt)
---
# Shard Keys
The second consideration when putting data into SingleStore Helios is choosing the shard key for a table. Data is distributed across the SingleStore Helios cluster into a number of partitions on the leaf nodes. The shard key is a collection of the columns in a table that are used to control how the rows of that table are distributed. To determine the partition responsible for a given row, SingleStore Helios computes a hash from all the columns in the shard key to the partition ID. Therefore, rows with the same shard key will reside on the same partition.
For example, the table below has the shard key that contains only the `first` column. All people with the same first name will be stored on the same partition.

## Check Your Understanding
**Q**: Why are there restrictions on `ALTER`ing or `UPDATE`ing the shard key of a table?
**A**: Unlike adding a new index to a rowstore table (which only requires adding information to existing data without moving it), `ALTER`ing the shard key requires moving the table to different partitions. Similarly, `UPDATE`ing a column in the shard key could require a row to be moved to a different partition.
**Q**: Why is the shard key required to be a subset of the primary key for a rowstore table?
**A**: The primary key of a rowstore table requires that there are no duplicate rows. We can only enforce uniqueness by ensuring that all potentially duplicate data is on the same partition.
## Choosing a Shard Key
Shard keys are specified at the time of `CREATE TABLE`. Once created, the shard key for a table cannot be modified. There are two competing considerations when sharding data:
* Distributing data evenly across partitions
* Partitioning data on columns you frequently filter or join
First, distributing data evenly makes capacity planning much easier since the system will use its resources uniformly. Query performance can also suffer when the data is skewed or unevenly distributed, because there can be slow partitions. Multi-partition queries cannot run faster than the slowest partition involved.
Second, queries perform significantly better and use fewer resources when the optimizer can precisely understand what partitions are used. SingleStore Helios only has to involve a single partition if the query filter matches the shard key, which greatly reduces cluster resource usage for high concurrency workloads. Similarly, joins of multiple tables that have the same shard key will be performed locally on the leaf partition rather than redistributing the data around the cluster, resulting in much faster joins that can be done at significantly higher concurrency. Joins of tables with different shard keys, or distributed joins, are substantially slower and more resource-intensive. Here, the order of the shard keys between one or more tables being joined must be the same in order to see this increase in performance. The only other affect of shard order is that rowstore [skiplist indexes](https://docs.singlestore.com/cloud/create-a-database/other-schema-concepts.md) are created on the same columns chosen for the shard key. However, this order can always be redefined.
For example, the following query is considered “single partition” because the filter clause (`where first = ‘john'`) includes the columns of the shard key. The aggregator only needs to talk to one partition to get the data.

For more about identifying and understanding the performance implications of single partition queries (and more), see the [Query Tuning](https://docs.singlestore.com/cloud/query-data/query-tuning.md) guide.
## Skewed Partitions
A shard key should ensure that the rows are (almost) evenly distributed across partitions. The two concerns specified above, typically, run into conflict when the data is skewed. For example, `first` is probably a poor shard key in the table above, because some first names are much more common than others. In cases like these, it is generally more important that the data be evenly distributed so that the storage and query processing requirements are balanced across the cluster. If the partitions are unbalanced, some partitions may face significantly higher workload than others for distributed queries. These partitions may become the limiting factor on parallelized operations. Hence, you should choose shard keys carefully to avoid problematic skewed partitions. In the example above, `user` is probably a better choice of shard key. It will be more evenly distributed, and it is likely to be a filter for queries against the table. If you want a table to get truly uniform sharding, you may also shard on an auto-increment column.
## Cardinality
A shard key reduces the cardinality across the set of columns it contains. `GROUP BY`s execute more efficiently when they match the shard keys, because it reduces the amount of data transfer that is required, which subsequently allows more efficient computations.
## Joins
If the join conditions match the shard keys, colocated data reduces the computational needs for join operations. Hence, ensure that the join conditions match shard keys as much as possible.
## Single-Partition Queries
Queries which perform an equality filter on a shard key value can be executed against a single partition, instead of fanning out to all the partitions.
## More Ways to Distribute Data
In addition to specifying a key the system will use to shard the table, you may also distribute data as follows:
* Keyless sharding is the default for tables with no primary key and no explicit shard key. You can explicitly declare a table as keyless sharded by specifying a shard key with an empty list of columns: `shard key () ...` With keyless sharding, data is distributed uniformly across partitions in most cases. Cases when the data becomes non uniform typically occur because `INSERT … SELECT` statements are optimized to insert locally into the same partition. This makes these operations substantially faster, but it does mean that they can cause skew where there wasn’t before or amplify existing skew. To remove skew in these cases, you can force the `INSERT … SELECT` to redistribute the data with the `force_random_reshuffle` query hint. See more about this in the [INSERT](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/insert.md) reference topic. Keyless sharding also makes it impossible to do single partition queries or local (collocated) joins, because rows are not associated with specific partitions via an explicit key value. The following are examples of `CREATE TABLE` statements which will cause keyless sharding to be used.
```sql
CREATE TABLE t1(a INT, b INT);
CREATE TABLE t1(a INT, b INT, SHARD KEY());
```
* Data in reference tables is duplicated on every node in the cluster, including aggregators. This makes it possible to do local joins between reference tables and any other tables; however, the table consumes a large amount of cluster storage because a copy of the entire table is stored on every node. Furthermore, reference tables replicate synchronously to the aggregators and asynchronously to the leaves, dramatically limiting the performance of writes. For star schema workloads, reference tables are ideal for small, slowly changing dimension tables.
## Questions to Ask When Choosing a Shard Key
* Does this table have a primary key? *Make sure there is a shard key and that it is a subset of the primary key.*
* Do you frequently join on a specific set of columns (e.g. `WHERE users.id = action.user_id and users.country = action.country`)? *Try to make the shard key a subset of the joined columns. Shard order should be the same between tables to accomplish this.*
* Do you frequently filter on a specific set of columns (e.g. `WHERE user_id = 17 and date = '2007-06-14'`)? Try to make the shard key a subset of the filtered columns.
> **📝 Note**: Filtering on a range of the shard key (e.g. `WHERE user_id BETWEEN 2 and 12`) can negatively affect the performance of your query. Multiple partitions may need to be scanned, thereby slowing the retrieval of your result set.
* Do you have high concurrency queries? *Choose a shard key that allows these queries to be single partition.*
* Is your data skewed for your current choice of shard key? *Try to add additional columns to the shard key to ensure even distribution.*
* Do you need to `UPDATE` or `ALTER` any fields in the shard key? *Remove those fields from the shard key.*
* Is this a small, infrequently changing table that needs to be on every node in the cluster to guarantee local joins? *Use a reference table instead of sharding the table.*
In addition to these questions, see the [Detecting and Resolving Data Skew](https://docs.singlestore.com/cloud/create-a-database/detecting-and-resolving-data-skew.md) topic for more information.
## Check Your Understanding
**Q**: Why can the SingleStore Spark Connector load data directly into the leaf partitions for keyless sharding only?
**A**: If there is keyless sharding, data can be placed anywhere in the cluster. Since the leaf partitions are fully functional databases, the spark connector can connect directly to load the data in parallel. If a shard key is used, the connector must use an aggregator to ensure that data is inserted into the correct partition.
**Q**: Why does SingleStore Helios use the primary key as a shard key if there is no explicit shard key?
**A**: It is very common to query tables with a filter on the primary key; in addition, the uniqueness constraint of primary keys guarantees that data will not be skewed.
**Q**: Why is it generally better to use a shard key with the fewest number of columns, as long as it’s not skewed?
**A**: We can only optimize queries to run against a single partition when they filter or join on the entire shard key. A smaller shard key is likely to match more queries.
**Q**: Why is it faster to run queries that group by the shard key?
**A**: When the grouping matches the shard key, queries are faster because the `GROUP BY` can be executed locally on each partition. This effect is much more pronounced when the groups are high-cardinality.
## Related Topics
* [Sharding](https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-singlestore-helios/sharding.md)
* [Understanding Shard Key Selection](https://docs.singlestore.com/cloud/create-a-database/understanding-shard-key-selection.md)
***
Modified at: September 16, 2025
Source: [/cloud/create-a-database/optimizing-table-data-structures/shard-keys/](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/shard-keys/)
(An index of the documentation is available at /llms.txt)
---
# Other Schema Concepts
## Reference Database
When a user creates a database, two transaction logs are created for each partition of that database, in addition one special transaction log is created called the **reference database**. This database holds metadata about the whole database (for example, schemas of tables and stored procedures) as well as the data for special tables called reference tables. The reference database is replicated to each node in a cluster because every node needs this metadata. Further, reference tables take advantage of this database to implement joins that do not need to go over the network. The reference database has its master on the master aggregator, and only the master aggregator can write to it (this is why only the MA can execute DDL queries).
## Reference Tables
**Reference tables** are relatively small tables that do not need to be distributed and are present on every node in the cluster. Reference tables are implemented via primary-secondary replication to every node in the cluster from the master aggregator to the leaves asynchronously. Replication enables reference tables to be dynamic: updates that you perform to a reference table on the master aggregator are quickly reflected on every machine in the cluster. Since reference tables are replicated to every node in the cluster, it eliminates the need to transfer the table’s data across the network during query execution. Reference tables should mostly be used for tables that change rarely, because the write operations on reference tables consume a lot more resources.
SingleStore Helios aggregators can take advantage of reference tables’ ubiquity by pushing joins between reference tables and a distributed table onto the leaves. Imagine you have a distributed `clicks` table storing billions of records and a smaller `customers` table with just a few million records. Since the `customers` table is small, it can be replicated on every node in the cluster. If you run a join between the `clicks` table and the `customers` table, then the bulk of the work for the join will occur on the leaves.
> **❗ Important**: Reference tables are a convenient way to implement **dimension tables**.
**Best Practices for using Reference Tables**
* Do not use reference tables to store a large number of rows, e.g. more than a few million rows.
* If your workload requires intensive searches for individual rows (say, for OLTP-type operations), use a rowstore reference table.
* Use columnstore reference tables to store dimension tables for a data warehouse type schema, with a typical star-join query and non-intensive updates.
* Reference tables must have explicit primary keys.
## DDL Forwarding for Reference Tables
Data Definition Language (DDL) commands for reference tables can be run from the master aggregator or a child aggregator node. DDL commands run on a child aggregator are forwarded to the master aggregator and propagated from there. (See [Cluster Management Commands](https://docs.singlestore.com/cloud/reference/sql-reference/cluster-management-commands.md) for more information.)
## DML Forwarding for Reference Tables
Data Manipulation Language (DML) commands for reference tables can be run from the master aggregator or a child aggregator node, however, with some exceptions. The following DML commands must be run directly on the master aggregator; they will fail with an error when run on a child aggregator.
* The `LOAD DATA` command
* Query profiling commands such as `PROFILE` and `SHOW PROFILE` if the `sync_permissions`[engine variable](https://docs.singlestore.com/cloud/reference/configuration-reference/engine-variables/list-of-engine-variables/#sync-variables-lists.md) is set to `ON`.
* DML statements used in stored procedures
* DML queries that reference temporary tables
* DML queries in multi-statement transactions that are enclosed within BEGIN and COMMIT transaction statements.
DDL commands run on a child aggregator are forwarded to the master aggregator and propagated from there. (See [Cluster Management Commands](https://docs.singlestore.com/cloud/reference/sql-reference/cluster-management-commands.md) for more information.)
## Temporary Tables
Temporary tables can be created as Columnstore or Rowstore tables. For more information, see [CREATE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table.md). Rowstore temporary tables are created in memory. Temporary tables exist for the duration of a client session. This means they are scoped to the connection that opened them, cannot be queried by other users, and are dropped once the connection has ended. They can also be dropped manually without removing the connection.
SingleStore Helios does not write logs or take snapshots of temporary tables. Temporary tables are designed for temporary, intermediate computations. Since temporary tables are neither persisted nor replicated in SingleStore Helios, they have high availability disabled. This means that if a node in a cluster goes down and a failover occurs, all the temporary tables on the cluster lose data. Whenever a query references a temporary table after a node failover, it returns an error. For example,
```
"Temporary table is missing on leaf due to failover. The table will need to be dropped and recreated."
```
> **❗ Important**: To prevent loss of data on node failover, use SingleStore Helios tables that have high availability enabled.
Views cannot reference temporary tables because temporary tables only exist for the duration of a client session. Although SingleStore Helios does not materialize views, views are available as a service for all clients, and so cannot depend on client session-specific temporary tables.
`CREATE TEMPORARY TABLE` can be run on any aggregator, not just the master aggregator. Temporary tables are sharded tables, and can be modified and queried like any “permanent” table, including distributed joins.
## Global Temporary Tables
Another type of temporary table is the global temporary table. Like temporary tables, they are not persisted.
> **📝 Note**: Global temporary tables are not supported for columnstore.
Unlike temporary tables, global temporary tables are shared across sessions, i.e. they exist beyond the duration of a session. They are never automatically dropped and must always be dropped manually. They can also be queried by other users since they are not session dependent.
Global temporary tables can be used as a temporary space for processing data that can be accessed from multiple connections, for example, performing ETL (Extract, Transform, and Load) operations on modern dynamic databases.
If failover occurs, global temporary tables lose data and enter an errored state; they need to be dropped and recreated. However, dropping a global or non-global temporary table does not drop its plancache from the disk and retains the cache if the table is recreated with the same schema.
DDL such as `CREATE ROWSTORE GLOBAL TEMPORARY TABLE` and DML for global temporary tables can be run on a master, or a child aggregator node.
**Note:** Both global temporary tables and non-global temporary tables cannot be altered.
## Types of Indexes
SingleStore Helios, like all standard SQL databases, allows the creation of indexes on tables, which speed up certain access patterns. As with MySQL, SingleStore Helios supports two index type keywords. The BTREE keyword is for compatibility with MySQL syntax and will create the default SingleStore Helios skiplist index instead. The sort key index type is for [columnstore tables](https://docs.singlestore.com/cloud/create-a-database/columnstore.md).
> **📝 Note**: `KEY() USING CLUSTERED COLUMNSTORE` is a legacy syntax that is equivalent to `SORT KEY()`. SingleStore recommends using `SORT KEY()`.
## Skiplist Indexes
The default index type in SingleStore Helios is a skiplist. Skiplists in SingleStore Helios are meant to replace the B-Tree indexes used by most other databases, including MySQL. Skiplists are optimized to run in memory as they can be implemented lock free and offer extremely fast insert performance. Like B-Trees, they offer an expected O(log(n)) lookup performance and can be traversed in sorted order.
Unlike B-Trees in MySQL, skiplists in SingleStore Helios are uni-directional (singly linked). Each column in a compound skiplist index can be specified as ascending (`ASC`) or descending (`DESC`). The default is `ASC`. Which one you pick will not impact lookup performance, but it does impact scan performance depending on the direction the index is scanned. Scanning a skiplist in reverse order is approximately twice as costly as scanning in forward order. So, if you have an `ASC` index and you run a query that would traverse the index in descending order (`ORDER BY DESC` for example), then the query will require a more expensive iteration than if the index were `DESC`.
SingleStore Helios supports skiplists only on rowstore tables. For more information on what a skiplist is and why it is used in SingleStore Helios see: [The Story Behind SingleStore’s Skiplist Indexes](https://www.singlestore.com/blog/what-is-skiplist-why-skiplist-index-for-memsql/)
## Columnstore Indexes
Columnstore indexes leverage columnstore technology to efficiently store and retrieve large numbers of values from disk (using flash or SSD is recommended). Because columnstore indexes are backed by disk and don’t have the requirement that all data must fit in memory, they are typically very useful for analytical workloads. SingleStore Helios currently supports sort key indexes which, when added to a table, will make the entire table structure backed by the columnstore. Currently columnstore indexes cannot be combined with in-memory row store indexes on the same table. For more information about using columnstore indexes in SingleStore Helios, see [How the Columnstore Works](https://docs.singlestore.com/cloud/create-a-database/columnstore/how-the-columnstore-works.md).
## Hash Indexes
Due to the restrictive case detailed above, `HASH` indexes should only be used when there is a demonstrated need and measurable benefit on your particular dataset and workload. In these specific cases, `HASH` indexes provide fast exact-match access to unique values. This is because the hash index is stored in a sparse array of buckets indexed by a hash function on the relevant columns eg: `hash(column_a, column_b)`. Queries can quickly find exact match data by examining only the bucket identified by the hash function. However they cannot easily scan over a subset of the index. For multi-column indexes, query filters must match all of the index columns to be able to take advantage of the index. SingleStore Helios supports `HASH` indexes on both columnstore and rowstore tables. For more information, see [USING HASH behavior](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table/#UUID-2d098a7e-1811-6223-8748-d20d3c8b53f6.md) and [Highly Selective Joins](https://docs.singlestore.com/cloud/create-a-database/columnstore/highly-selective-joins.md).
> **⚠️ Warning**: For rowstore tables, a `HASH` index will only be utilized if the query filters on all the columns in a multi-column `HASH` index.For columnstore tables, a `HASH` index will be utilized on all or any of the columns in a multi-column `HASH` index.
Consider an example table:
```sql
CREATE TABLE t(a int, b int, INDEX(a, b) USING HASH);
```
Suppose we are running queries like:
```sql
SELECT * FROM t WHERE a < 3;
```
`EXPLAIN` shows us that since we are performing a range scan and not filtering on all the columns in our hash index, a full Table Scan is performed.
```sql
EXPLAIN SELECT * FROM t WHERE a < 3;
```
```output
+------------------------------------------------+
| EXPLAIN |
+------------------------------------------------+
| Gather partitions:all |
| Project [t.a, t.b] |
| Filter [t.a < 3] |
| TableScan db.t |
+------------------------------------------------+
```
The hash index is only utilized if the query uses only equality predicates, and filters on all columns in the hash index.
```sql
EXPLAIN SELECT * FROM t WHERE a=3 AND b=7;
```
```output
+--------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+--------------------------------------------------------------------------------------------------------------------------+
| Gather partitions:all |
| Project [t.a, t.b] |
| IndexRangeScan db.t, KEY a (a, b) USING HASH storage:lf_hashtable scan:[a = 3 AND b = 7] |
+--------------------------------------------------------------------------------------------------------------------------+
```
> **❗ Important**: A query on a columnstore table that employs an equality filter on a column that has a hash index defined on that column will always use the hash index. For this reason, if the filter is very unselective (returns many records), the hash index should not be used.
## Runtime Plan Choosing
SingleStore Helios can dynamically select which index to use for a query at runtime. Instead of collecting statistics and building histograms, SingleStore Helios can compute these statistics for a given query on-demand by inspecting its indexes. If a query can match more than one index, SingleStore Helios compiles an execution plan for each choice, along with the necessary expression logic to cheaply analyze and evaluate which plan to choose at runtime. This process eliminates the need to manually recompute statistics on indexes.
## Index Hints
SingleStore Helios supports the following index hint syntax:
```sql
tbl_name [index_hint]
index_hint:
USE {INDEX | KEY} (index_list)
| IGNORE {INDEX | KEY} (index_list)
| FORCE {INDEX | KEY} (index_list)
index_list:
index_name [, index_name] ...
```
For example:
```
SELECT * FROM t1 USE INDEX(idx_name);
--OR
SELECT * FROM t1 FORCE INDEX(idx_name);
```
* `USE` and `FORCE` hints force the use of one of the specified indexes to run the query. In SingleStore Helios, there is no difference between a `USE` and `FORCE` hint.
* `IGNORE` hints disallow the specified indexes from being used to run the query.
The `EXPLAIN ` statement can be used to show which indexes the query considers and which one it will actually use.
## Index Commands
* [CREATE INDEX](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-index.md)
* [DROP INDEX](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/drop-index.md)
* [SHOW INDEX, SHOW INDEXES, SHOW KEYS](https://docs.singlestore.com/cloud/reference/sql-reference/show-commands/show-index-show-indexes-show-keys.md)
* [SHOW INDEXES](https://docs.singlestore.com/cloud/reference/sql-reference/show-commands/show-index-show-indexes-show-keys.md)
* [SHOW KEYS](https://docs.singlestore.com/cloud/reference/sql-reference/show-commands/show-index-show-indexes-show-keys.md)
* [EXPLAIN](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/explain.md)
## Related Commands
An index may also be specified when creating or altering tables.
* [CREATE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table.md)
* [ALTER TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/alter-table.md)
## Related Topics
* Training: [SingleStore Helios Indexes](https://training.singlestore.com/learn/course/internal/view/elearning/616/memsql-indexes)
***
Modified at: September 13, 2024
Source: [/cloud/create-a-database/other-schema-concepts/](https://docs.singlestore.com/cloud/create-a-database/other-schema-concepts/)
(An index of the documentation is available at /llms.txt)
---
# Rowstore
A rowstore in SingleStore refers to a table storage format that stores data in rows, with all the fields of a row stored together in the same physical location. Rowstores are entirely in-memory, meaning they store data in the main memory (RAM) rather than on disk. This avoids disk I/O and significantly speeds up data access and manipulation.
Rowstores are ideal for Online Transaction Processing (OLTP) and hybrid transactional/analytical (HTAP) applications that involve frequent point lookups, small inserts, updates, and deletes. Rowstore indexes in SingleStore are of two types - lockfree skiplists and hash tables. Skiplists maintain rows in sorted order to provide fast key lookups and range filters. Hash tables use a hash of the indexed columns to enable efficient exact-match queries. Both structures are optimized for in-memory access and enable high concurrency without traditional locking.
Key advantages of rowstore tables include:
* Rapid inserts and updates, even for large datasets
* Fast retrieval of specific rows, leading to an improved random seek performance
* Support for multiple indexes providing flexible query patterns
The total combined size of all rowstore tables is limited by the total available RAM (A computer's short-term memory. It is where the data that the processor is currently using is stored temporarily. RAM can be accessed much faster than data on a hard disk, solid-state disk, or another long-term storage device, which is why RAM capacity is so important for system performance.) on the leaf nodes in the cluster. It is important to reserve a reasonable amount of RAM, say 20%, for query execution. So the effective total rowstore table capacity will be reduced by this amount.
> **📝 Note**: Rowstore is no longer the default table storage format. As of version 7.3 of SingleStore, Columnstore is the default table storage format.
This section provides a conceptual overview of SingleStore Helios’s rowstore and includes considerations for optimizing your database performance using the rowstore.
## Creating a Rowstore Table
Typically you will specify a shard key and one or more indexes for a rowstore, although a shard key and indexes are optional. A primary key, which is enforced to be unique, is also supported.
On rowstore tables, when the shard key is not the same column as the primary key, a skiplist index (A data structure optimized for ordered data that allows for queries to quickly seek data by binary searching.) will also implicitly be created on the shard key columns.
> **❗ Important**: SingleStore supports both ordered (skiplist) and hash indices (A data structure optimized for fast equality lookups by a key.) on rowstore tables.
Here is an example of a statement that creates a rowstore table:
```sql
CREATE ROWSTORE TABLE products (
ProductId INT,
Color VARCHAR(10),
Price INT,
dt DATETIME,
KEY (Price),
SHARD KEY (ProductId)
);
```
We define a `SHARD KEY` to explicitly control the data distribution. We define it on `ProductId` since sharding on a high cardinality column or columns generally allows for a more even distribution and prevents skew. The KEY specified on `Price` causes an index to be created on the `Price` column.
It is also possible to randomly distribute data by either omitting the shard key, or defining an empty shard key `SHARD KEY()`, as long as no primary key is defined.
## Rowstore keys
Rowstores with multiple indexes support very fast seeking to find one or a small number of rows via several different keys, or “access paths.” SingleStore Helios rowstores are able to provide extremely fast lookup along multiple different access paths with low variance in response time from query to query.
The following statement creates a `products` table with keys on both `Price` and `Color`, and a unique (primary) key on `ProductId`.
```sql
CREATE ROWSTORE TABLE products (
ProductId INT,
Color VARCHAR(10),
Price INT,
dt DATETIME,
KEY (Price),
KEY (Color),
PRIMARY KEY(ProductId),
SHARD KEY (ProductId)
);
```
Primary keys must contain all the columns in the shard key so they can be enforced efficiently by looking at data in only a single shard (partition). Creating a primary key without specifying a shard key automatically shards on the primary key.
You can also create a key by creating an index on a rowstore using the [CREATE INDEX](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-index.md) statement.
## Rowstore persistence
Rowstore data is fully persistent and updates on rowstore tables are done in transactions. Persistence is implemented for rowstores using periodic snapshots of the in-memory data, and a write-ahead log, which are both stored on a file system to make them permanent. If a SingleStore Helios node restarts, all its rowstore data will be recovered from the snapshots and log and the in-memory state for the rowstore will be rebuilt.
## Garbage collection
Unneeded columnstore segments stored in memory are eliminated in a process called garbage collection. A buffer manager maintains unused memory blocks for future use until no query or operation is using the unused memory anymore.
The garbage collection process automatically runs in the background.
## Porting applications to SingleStore Helios rowstores
If you are porting an application from another database that uses a disk-based rowstore structure based on B-tree, ISAM or a similar access method, you should start by using a SingleStore Helios rowstore with a key for each index on the original system. If the original system had a “heap” access method (unordered rowstore), you can start with a SingleStore Helios rowstore with no key.
## OLTP operations on large data sets
For OLTP operations on large tables, the total cost of provisioning enough RAM, and possibly enough servers, when using rowstores, can become a significant concern for some users. If this is the case, and the application doesn’t need the very fastest row lookup time, consider using columnstore tables with hash indexes on the most frequently-used lookup key columns instead. Or, for wide tables with many null values, the total cost of ownership (TCO) can be reduced by using rowstore tables with [SPARSE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table.md) data compression.
## Related content
See [The Story Behind SingleStore’s Skiplist Indexes](https://www.singlestore.com/blog/what-is-skiplist-why-skiplist-index-for-memsql) for details about how standard rowstore table indexes are implemented in SingleStore Helios.
## Rowstore Sizing Estimations
In order to estimate the total memory used for a rowstore table, we simply need to estimate the amount of memory used for each row, and then multiply that by the number of rows in the table.
## Memory Use Per Row
* **data**: memory use of each column in the table, which can be found by utilizing the size per each data type listed in [Data Types](https://docs.singlestore.com/cloud/reference/sql-reference/data-types.md).
* Be sure to consider changes in size that result from a column being nullable.
* **metadata overhead**: 24 bytes
* **index(es)**:
* **40 bytes** per skiplist index
* Skiplist indexes are created on rowstore tables by default in the following situations: if no primary key is specified, with the primary key unless otherwise specified, and when added explicitly after the table has already been been created.
* **32 bytes** per hash index
* Hash indexes are created on Rowstore tables in the following situations: with the primary key when specified, and when added explicitly after the table has already been created.
* For more information about keys and indexes see [Understanding Keys and Indexes in SingleStore](https://docs.singlestore.com/cloud/create-a-database/understanding-keys-and-indexes-in-singlestore.md).
## Memory Use Per Table
Based on the memory use per row, memory use for Rowstore tables has the following base formula:
`(data + 64 bytes + (index size * number of secondary indexes)) * number of rows`
`data` is the data size based on number of columns and their respective [Data Type](https://docs.singlestore.com/cloud/reference/sql-reference/data-types.md), `64 bytes` is the metadata overhead + the primary key index (or the index created in its place where one isn't specified), `index size` is the size of the index type of any additional indexes on the table, `number of secondary indexes` is the number of additional indexes, and `number of rows` is the total number of rows in a given table.
## Additional Sizing Estimates for Rowstore Table Overhead
* Additional indexes and columns cause overhead to increase. The amount of increase depends on index and data type.
* Every partition in a database will consume the same amount of table overhead. For example, if a leaf node has 8 partitions, and a table has a constant overhead of 32 MB, that lead will consume at least 256 MB of memory for that table.
* Per row, a table with `SPARSE` compression enabled consumes 4 bytes per every 8 `SPARSE` columns, plus an additional 8 bytes.
* Deleted rows consume an additional 40 bytes, plus 8 bytes per index until they are physically deleted by the engine.
* `DELETE` queries mark rows as deleted; they don't physically delete them right away. The row is removed at a later time when garbage collection runs, and the version can be safely deleted. Row garbage collection runs in the background, however [OPTIMIZE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/optimize-table.md) can be used to force it to run immediately. Note that `OPTIMIZE TABLE` can result in a performance impact and should be run with caution.
***
Modified at: November 18, 2025
Source: [/cloud/create-a-database/rowstore/](https://docs.singlestore.com/cloud/create-a-database/rowstore/)
(An index of the documentation is available at /llms.txt)
---
# Specifying Unenforced Unique Constraints
You can specify the `UNENFORCED` option on a `UNIQUE` constraint to disable enforcement of the constraint. This means that SingleStore does not prevent you from inserting duplicate rows, and cannot guarantee that the constraint is true. An unenforced unique constraint is informational: the query planner may use the unenforced unique constraint as a hint to choose better query plans.
Unenforced unique constraints are useful on columnstore tables since on a columnstore table, an unenforced unique constraint is a logical-only index - there is no physical storage for the index. SingleStore supports unique constraints on both single-column and multiple-column keys in a columnstore reference table.
Adding or altering a unique index is not supported on existing columnstore tables.
On a rowstore table, an unenforced unique constraint is stored physically as a regular non-unique index.
The `RELY` and `NORELY` options specify how the query planner may use the unenforced unique constraint. These options determine whether or not we depend on the index-provided constraint for ensuring correctness in execution.
The `NORELY` option, which is the default, specifies that query semantics should not rely on the unenforced uniqueness constraint - queries will always return correct results regardless of whether the unenforced unique constraint is true or not. SingleStore may use a `NORELY` unenforced unique constraint to inform statistical estimates. The query planner assumes the number of unique values in a table is equal to the row count of a table.
The `RELY` option specifies that SingleStore may choose query plans which assume that the unenforced unique constraint is true - queries are only guaranteed to return correct results if the constraint is true, and queries may return incorrect results if there are duplicate rows. You should only use the `RELY` option if you know the constraint is valid, e.g. if some process in your application enforces the constraint. SingleStore may use a `RELY` unenforced unique constraint to inform statistical estimates as well as eliminate redundant joins, for example.
## Syntax
To specify a unique constraint as unenforced, add the `UNENFORCED` option to the index declaration, for example like:
```sql
UNIQUE KEY (col1, col2) UNENFORCED
```
The syntax for the `UNENFORCED` clause is
```sql
UNENFORCED [RELY | NORELY]
```
If neither `RELY` nor `NORELY` is specified, the default is `NORELY`.
The `UNENFORCED` clause is an optional index\_option clause in the unique index declaration syntax found in [CREATE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table.md), [ALTER TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/alter-table.md), or [CREATE INDEX](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-index.md).
For example, as part of a `CREATE TABLE` statement:
```sql
CREATE TABLE t (id INT, SORT KEY (id), UNIQUE KEY (id) UNENFORCED RELY);
```
## Unenforced Foreign Key Constraints
Foreign keys in SingleStore are column(s) in a table that establish a link or relationship with a `UNIQUE KEY` of another table. It defines the referential integrity between related tables, ensuring the values in the `FOREIGN KEY` column(s) have corresponding values in the `PRIMARY KEY` column of the referenced table.
Foreign key enforcement is not supported, but `FOREIGN KEY` syntax can be supported in SingleStore by setting the `ignore_foreign_key` [engine variable](https://docs.singlestore.com/cloud/reference/configuration-reference/engine-variables/list-of-engine-variables/#sync-variables-lists.md) to `ON`. The default value for `ignore_foreign_keys` is `OFF`.
## Syntax
```sql
FOREIGN KEY [foreign_key_name](col1,..., coln) REFERENCES table_referenced (col_referenced));
```
## Example
```sql
-- Referenced Table --
CREATE TABLE parent (pid INT PRIMARY KEY, col1 INT);
-- Foreign Key Table --
CREATE TABLE child (cid INT PRIMARY KEY, pid INT, FOREIGN KEY fkey(pid) REFERENCES parent(pid));
```
If you are migrating an existing application that already has foreign key syntax onto SingleStore, it can make the process easier to set `ignore_foreign_keys` to `ON`.
## Checking Foreign Keys in an Application or Stored Procedure
Since SingleStore doesn't enforce foreign keys, if your application requires foreign key relationships to be maintained, you may wish to check foreign key relationships in application software. The most common use of a foreign key relationship is to ensure that a one-to-many relationship is maintained between two tables. For example, you may have a rule that any row in the `child` table must have a corresponding row in the `parent` table.
You may be able to enforce this entirely on the client side (with no database queries needed) by making sure that all transactions update the database in such a way that every child has a parent. Or, you may wish to check the constraint by running database queries in your application before doing database operations that might violate it. For example, **before** inserting into the `child` table like:
```sql
INSERT INTO child VALUES (100, 1);
```
your application can run a `SELECT` statement on the `parent` table:
```sql
SELECT count(*) FROM parent WHERE pid = 1;
```
If the result is not `1`, your application can signal an error and not run the `INSERT` statement. Detecting a foreign key violation like this generally indicates an issue with the application logic that needs to be corrected.
***
Modified at: February 28, 2024
Source: [/cloud/create-a-database/specifying-unenforced-unique-constraints/](https://docs.singlestore.com/cloud/create-a-database/specifying-unenforced-unique-constraints/)
(An index of the documentation is available at /llms.txt)
---
# Understanding How Datatype Can Affect Performance
## Comparing Mismatched Datatypes
Using comparisons between mismatched data types may degrade query performance and may use unsafe type conversions which can yield undesirable query results. SingleStore will display a warning for queries with potentially problematic comparisons between mismatched data types in the `EXPLAIN` and `information_schema` records for the query.
These warnings do not necessarily indicate a problem, and you may have valid reasons for comparing different data types. But these data type mismatches are flagged to help you identify potential problems that you may not be aware of.
When you see these warnings, you should check whether the data types are expected to be different. You may wish to consider changing the data types of the fields or values involved. You may also wish to consider adding explicit type conversion operations, such as the [cast operators](https://docs.singlestore.com/cloud/reference/sql-reference/conditional-functions/cast-or-convert.md) or functions like [STR\_TO\_DATE](https://docs.singlestore.com/cloud/reference/sql-reference/date-and-time-functions/str-to-date.md) which convert between different types.
These warnings can be seen in `EXPLAIN `, `information_schema.plancache.plan_warnings`, `information_schema.mv_queries.plan_warnings`, and the `PlanWarnings` column of `show plancache` in textual form, as well as in `EXPLAIN JSON `, `information_schema.plancache.plan_info`, and `information_schema.mv_queries.plan_info` in JSON form.
## Example
An example of these warnings is the following:
```sql
CREATE TABLE t (id VARCHAR(50), PRIMARY KEY (id));
EXPLAIN SELECT * FROM t WHERE id = 123;
```
```output
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| WARNING: Comparisons between mismatched datatypes which may involve unsafe datatype conversions and/or degrade performance. Consider changing the datatypes, or adding explicit typecasts. See https://docs.singlestore.com/docs/mismatched-datatypes for more information. |
| |
| WARNING: Comparison between mismatched datatypes: (`t`.`id` = 123). Types 'varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL' vs 'bigint(20) NOT NULL'. |
| |
| Gather partitions:all alias:remote_0 |
| Project [t.id] |
| Filter [t.id = 123] |
| TableScan db.t, PRIMARY KEY (id) |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```
In this example, the query involves the expression `t.i = 123`, where `t.i` is a string field. When a numeric value is compared to a string, the string is converted to a numeric value, e.g. the string `'123'` is converted to the number `123`.
This comparison may be problematic for multiple reasons:
* The mismatched data types may indicate a mistake in how the query is written or how the table is defined. The query may behave differently than intended and yield undesired results. For example, all of the strings `'123'`, `'123.0'`, `'0123'`, and `'123abc'` compare equal to the integer `123`, so while the query may be intended to retrieve a single row with the specified `id`, this equality comparison may yield multiple rows whose `id` values all compare equal to `123`.
* The mismatched data types negatively impact the performance of the query. If the field and constant were either both strings or both integers, the query plan would be able to use the index to efficiently seek to lookup the matching `id`. But because there are many possible string `id`s that match the number `123`, which do not come in any particular order in terms of string lexicographic order, the query cannot seek into the index and instead must scan all the rows of the table.
## Data Type Conversion
The global sync variable `data_conversion_compatibility_level` controls the way certain data conversions are performed. This variable can have the following possible values: '6.0', '6.5', '7.0','7.5', and '8.0'. Higher values introduce stricter checking of values and will error for conversions that worked at lower levels. For example, the `'7.0'` level will fail the conversion of `'abc'` to an integer value, while the `'6.0'` level will silently convert it to a NULL or 0.
The following table lists the data type conversion checks and behavior changes that are introduced with each `data_conversion_compatibility_level` value. Note that the data type conversion checks introduced in a compatibility level are preserved in subsequent levels.
| data\_conversion\_compatibility\_level | Data Type Conversion Checks |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `6.0` | - The lowest data type conversion compatibility level.
- Default value for SingleStore engine versions lower than 8.0.
|
| `6.5` | - Error on integer overflows and underflows in
INSERT statements. This check applies to all INTEGER data types, including BIGINT, INT, MEDIUMINT, SMALLINT, TINYINT, BIT, and BOOL. - Error on string inputs to
VARCHAR columns that are too short to store the data. This check is run against INSERT statements. - Error on string inputs to
LONGBLOB, MEDIUMBLOB, BLOB, TINYBLOB, LONGTEXT, MEDIUMTEXT, TEXT, and TINYTEXT columns that are too short to store the data. This check is run against INSERT statements. - Error on invalid string to int conversion in
INSERT statements. Only strings with valid characters will be converted to integers.
|
| `7.0` | - Error on string inputs to
CHAR columns that are too short to store the data. This check is run against INSERT statements. - Error on inputs to
BINARY columns that are too short to store the data. This check is run against INSERT statements. - Error on decimal inputs that do not match the size specified in the
DECIMAL column definition. This check is run against INSERT statements. - Error on invalid or out-of-range date inputs to
DATE, DATETIME, DATETIME(6), and YEAR columns in INSERT statements. - Errors on zero value date inputs into
DATE, DATETIME, and DATETIME(6) columns in INSERT statements. - Arithmetic operations involving
DATE and INT values are performed by converting the INT data into intervals (days) instead of converting both data types to DOUBLE.
|
| `7.5` | - Error on invalid string to
DECIMAL conversion in INSERT statements. Only strings with valid characters undergo numeric conversion.
|
| `8.0` | - Errors on conversions from
STRING to DATE like data types instead of generating NULL or 0. - Default value beginning in version 8.0.
|
| `8.1` | - Errors on the invalid or out-of-range timestamp inputs to
TIMESTAMP and TIMESTAMP(6) columns in INSERT statements.
|
***It’s recommended to set the `data_conversion_compatibility_level` variable to the highest available value for new application development.*** SingleStore supports in-place change (An in-place change in a database refers to modifying the data or schema of the database without requiring a full data migration or recreation of the database. It allows you to make changes to the database while minimizing downtime and preserving existing data.) of `data_conversion_compatibility_level` for versions 8.0.24 and newer. This allows you to change your `data_conversion_compatibility_level` even if one of your shard keys is a persisted computed column. Prior to this, shard keys that were persisted computed columns could become logically corrupted when changing the `data_conversion_compatibility_level`. For existing applications, it’s also recommended to use the highest available level, but it’s recommended that you test your application before deploying this change. In particular, changing the value of `data_conversion_compatibility_level` can change the behavior of expressions in computed columns.
If a computed column value changes due to a change in `data_conversion_compatibility_level`; columnstore sorting, indexes, and sharding can become logically corrupted. SingleStore does not recompile an existing plan when `data_conversion_compatibility_level` or `sql_mode` changes.
> **📝 Note**: `sql_mode` is persisted to the `CREATE TABLE` statement. Therefore, the computed column of a table always uses the `sql_mode` that the table is created with, which may be different from the current `sql_mode`.
If a persisted computed column is also a shard key and the `data_conversion_compatibility_level` has been changed, rows can move to a different partition. Updating the row will move it to the correct partition automatically, but some queries won’t be able to find the correct partition to fetch a row when they otherwise would.
For example, see how expression evaluation may behave differently under the two levels:
```sql
SET GLOBAL data_conversion_compatibility_level = '6.0';
SELECT CAST('2023-01-31' AS DATE) + 1;
```
```output
+--------------------------------+
| CAST('2023-01-31' AS DATE) + 1 |
+--------------------------------+
| 20230132 |
+--------------------------------+
```
```sql
SET GLOBAL data_conversion_compatibility_level = '8.0';
SELECT CAST('2023-01-31' AS DATE) + 1;
```
```output
+--------------------------------+
| CAST('2023-01-31' AS DATE) + 1 |
+--------------------------------+
| 20230201 |
+--------------------------------+
```
## Finding Incorrect Computed Shard Key Values
You can find all of the incorrect computed shard key values with a SQL query that searches for records where the computed columns are not equal to the value of their computed column expression.
First, set the `allow_modifying_sysvars_with_computed_shard_key` engine variable to `ON`. This will allow you to change the `data_conversion_compatibility_level` on databases that contain tables with a persisted computed column as the shard key. Otherwise, an error would be generated.
```sql
SET GLOBAL allow_modifying_sysvars_with_computed_shard_key = ON;
```
Consider a `dates` table where dates are inserted into the table as strings. Then those dates must be converted to the `DATE` format and 1 day is added to the inserted date. The persisted computed column is the shard key and the current `data_conversion_compatibility_level` is `6.0`.
```sql
CREATE TABLE dates (date_str TEXT
,date_int AS CONVERT(CONVERT(date_str, DATE) + 1, SIGNED INT) PERSISTED INT
,SHARD KEY(date_int));
```
```sql
INSERT dates VALUES('2023-01-31'), ('2023-01-30');
```
```sql
SELECT * FROM dates;
```
```output
+------------+----------+
| date_str | date_int |
+------------+----------+
| 2023-01-30 | 20230131 |
| 2023-01-31 | 20230132 |
+------------+----------+
```
Next, follow these steps:
1. Set the `data_conversion_compatibility_level` to your desired version:
2. Compare the computed column with a `SELECT` statement with a `WHERE` filter that finds rows where the computed column is not equal to the value of its computed column expression. For example:
```sql
SET GLOBAL data_conversion_compatibility_level = '8.0';
```
> **📝 Note**: When creating a query to find values where the computed column changed, make sure that it is not using a shard key lookup, which might not find the desired row due to the change in shard key value.For example, the query used to search for changed computed columns uses a full columnstore scan, which you can verify using `EXPLAIN`:```sql
> EXPLAIN SELECT * FROM dates
> WHERE date_int <> CONVERT(CONVERT(date_str, DATE) + 1,
> SIGNED INT);
>
> ``````output
>
> +----------------------------------------------------------------------------------------------+
> | EXPLAIN |
> +----------------------------------------------------------------------------------------------+
> | Gather partitions:all alias:remote_0 parallelism_level:segment |
> | Project [r.date_str, r.date_int] |
> | Top limit:[?] |
> | ColumnStoreFilter [r.date_int <> CAST(DATE_ADD(DATE(r.date_str), INTERVAL 1 DAY) AS SIGNED)] |
> | ColumnStoreScan test1.r, SORT KEY __UNORDERED () table_type:sharded_columnstore |
> +----------------------------------------------------------------------------------------------+
> 4 rows in set (0.00 sec)
>
> ```
3. Once the affected rows have been identified, delete the row and re-insert it.
* Create a temporary table where the data will be backed up:
```sql
CREATE TEMPORARY TABLE tmp_dates LIKE dates;
```
* Insert the record(s) with the incorrect shard key value into the temporary table to back up the data. As previously explained, the value for `date_str` = ‘2023-01-31’ has been recomputed to a valid value:
```sql
INSERT INTO tmp_dates (date_str)
SELECT * FROM dates
WHERE date_int <> CONVERT(CONVERT(date_str, DATE) + 1, SIGNED INT);
```
```sql
SELECT * FROM tmp_dates;
```
```output
+-------------+-----------+
| date_str | date_int |
+-------------+-----------+
| 2023-01-31 | 20230201 |
+-------------+-----------+
```
* Using the query that finds rows where the computed column is not equal to the value of its computed column expression (#3), delete those rows from the temporary table:
```sql
DELETE FROM dates WHERE date_int <> CONVERT(CONVERT(date_str, DATE) + 1, SIGNED INT);
Query OK, 1 row affected (0.06 sec)
Records: 1 Duplicates: 0 Warnings: 0
```
```sql
SELECT * FROM dates;
```
```output
+------------+----------+
| date_str | date_int |
+------------+----------+
| 2023-01-30 | 20230131 |
+------------+----------+
```
* Insert the data from the temporary table back into `dates` and confirm the `date_int` column is not valid under the new `data_conversion_compatibility_level`.
```sql
INSERT INTO dates (date_str) SELECT date_str from tmp_dates;
```
```sql
SELECT * FROM dates;
```
```output
+------------+----------+
| date_str | date_int |
+------------+----------+
| 2023-01-30 | 20230131 |
| 2023-01-31 | 20230201 |
+------------+----------+
```
* Drop the temporary table:
```sql
DROP TABLE tmp_dates;
```
4. Lastly, set the `allow_modifying_sysvars_with_computed_shard_key` engine variable back to its default setting of `OFF`.
The procedure above is one possible way to repair persisted computed column shard keys that may have changed after you change `data_conversion_compatibility_level`. Other ways are also possible–any update to a row will recompute a persisted computed column. However, setting a field value to itself may not update the row due to logic created to optimize updates by doing nothing when an update is known to have no effect. For example, if `t.A` is `5` in a row in table `t`, and you try to update `t.A` to `5`, the operation may not have any effect and not trigger recalculation of any persisted computed columns in the row.
## Handling invalid source database DATE and DATETIME values during Flow migrations
When using SingleStore Flow to migrate data from supported source databases into SingleStore, the source data may contain non-standard or invalid DATE or DATETIME values such as `0001-01-01 07:07:24` or `0000-12-01`. If the `data_conversion_compatibility_level` is set to a stricter setting such as `8.1`, loading this data can fail with an error such as:
```sql
Error(PGT54): Table core_data.`mage_order` stage 3 error java.sql.SQLException: (conn=142441) Leaf Error (node-83201ac7-c278-4902-8df7-ab7902e5adb3-leaf-ag2-0.svc-83201ac7-c278-4902-a1f2-600f50d9b580:3306): Invalid DATE/TIME in type conversion for column 'col_datetime'
```
To work around this issue without modifying the source data, the compatibility level can be temporarily set to an earlier version such as `6.5`:
```sql
SET GLOBAL data_conversion_compatibility_level = '6.5';
```
For example, the following executes successfully:
```sql
SELECT @@data_conversion_compatibility_level;
DROP TABLE IF EXISTS date_tbl;
CREATE TABLE date_tbl (
id INT PRIMARY KEY NOT NULL,
d DATETIME
);
INSERT date_tbl VALUES (1, '0001-01-01 07:07:24.000000');
SELECT * FROM date_tbl;
```
> **❗ Important**: By default, SingleStore recommends using the highest available `data_conversion_compatibility_level` to enforce strict validation. Lowering it can allow non‑standard or invalid data to be inserted across the entire cluster. Use this workaround only in exceptional cases (for example, short-term Flow migrations that must preserve these values), and restore the highest supported compatibility level as soon as possible.
## Best Practices to Avoid Data Corruption
* Review the computed column expressions when changing `data_conversion_compatibility_level`.
* Perform application upgrade tests.
For example, if a computed column contains corrupted data and you have to switch to a higher `data_conversion_compatibility_level`, you may need to drop the computed column before changing the level. Once the level is increased, add the computed column to the table. Alternatively, if a persisted computed column is used in a columnstore key, you may have to create a new table and select data into this new table. After copying the data, drop the old table and rename the new table.
The following examples demonstrate how the behavior of expressions may change if `data_conversion_compatibility_level` is changed.
**Example 1**
```sql
SET GLOBAL data_conversion_compatibility_level = '6.0';
```
```sql
SELECT DATE('2019-04-20') + 2;
```
```output
+------------------------+
| DATE('2019-04-20') + 2 |
+------------------------+
| 20190422 |
+------------------------+
```
**Example 2**
```sql
SET GLOBAL data_conversion_compatibility_level = '7.0';
```
```sql
SELECT DATE('2019-04-20') + 2;
```
```output
+------------------------+
| DATE('2019-04-20') + 2 |
+------------------------+
| 2019-04-22 |
+------------------------+
```
The following example shows the error message generated if a zero value is attempted to be inserted into a `DATE`, `DATETIME`, or `DATETIME(6)` column if the `data_conversion_compatibility_level` is set to `7.0` or higher.
```sql
SET GLOBAL data_conversion_compatibility_level = '7.0';
```
```sql
CREATE TABLE dates (dt DATETIME);
INSERT INTO dates VALUES ('0000-00-00');
```
```output
ERROR 2363 (HY000): Leaf Error: Invalid DATE/TIME in type conversion
```
See the table on the [Time and Date](https://docs.singlestore.com/cloud/reference/sql-reference/data-types/time-and-date.md) page for examples of zero values for `DATE`, `DATETIME`, and `DATETIME(6)` data types. This page also discusses how date (and time) values are implicitly converted from string literals (e.g., '2023-02-03') and how to use date and time functions to perform explicit conversions from string literals.
***
Modified at: October 18, 2021
Source: [/cloud/create-a-database/understanding-how-datatype-can-affect-performance/](https://docs.singlestore.com/cloud/create-a-database/understanding-how-datatype-can-affect-performance/)
(An index of the documentation is available at /llms.txt)
---
# Understanding Keys and Indexes in SingleStore
This page seeks to explain behaviors of and interaction between keys and indexes in SingleStore. A key is a logical concept in relational databases, whereas an index is a physical artifact that assists with processing operations faster or enforcing uniqueness.
For basic keys, there is a one to one relationship with indexes. If the syntax `KEY(...)` (alone), or `PRIMARY KEY(...)` is used in `CREATE TABLE` when defining a given key, an index is created. For all other types of keys that can be defined, an index is not automatically created. For more information about the implications of defining each type of key and/or index, see the below comparison table. In general, this documentation follows MySQL terminology when discussing keys and indexes.
| **Key or Index** | **Function** | **Table Compatibility** | **Notes and Limitations** | **Column Compatibility** |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Shard key** | Responsible for distribution of data across partitions. Shard key columns should be as unique as possible. | A shard key (unique or non-unique) can be defined for either columnstore or rowstore tables. See[Sharding](https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-singlestore-helios/sharding.md)and[Choosing a Shard Key](https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-singlestore-helios/sharding/#section-idm4501210417348832654841869645.md)for more information. | If a shard and/or primary key is not defined for a given table, that table becomes keylessly sharded.If a primary key is defined, but a shard key is not, the primary key becomes the shard key.Only one primary key per table can be created.The shard key must be a subset of the columns in the primary key, if one is defined.Sharded tables do not support unique keys (unless the unique key contains all columns of the shard key).Sharded tables do not support`UPDATE`queries that modify the shard key.Sharded tables do not support`UPDATE...LIMIT`.To prevent an index on from being created on a shard key, use the`METADATA_ONLY`option when creating the shard key. This will decrease memory usage, but it can cause queries to run slower. | N/A |
| **Primary key** | A group of 1 or more columns from a table that uniquely identifies a row in the table, and serves to prevent data skew. | A primary key can be defined for either columnstore or rowstore tables. See[Optimizing Table Data Structures](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures.md)for guidance on choosing a primary key. | The primary key must contain all columns in the shard key.`KEY(...)`is the same as`PRIMARY KEY(...),`except that the latter enforces uniqueness. | N/A |
| **Columnstore sort key** | Stores data on disk in a columnstore format. | Columnstore sort keys may only be defined on columnstore tables. See[Choosing a Columnstore Key](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures.md)for more information. | A columnstore sort key can be created using the`SORT KEY()`syntax in a`CREATE TABLE`statement. When a key is specified, a sort key index is created, which defines the order in which rows are sorted in the columnstore table. The sort key can be specified as ascending or descending. When a key is not specified, no index is created and the columnstore data is stored unsorted. If you want to create an unsorted columnstore table, you can specify an empty key using`SORT KEY()`.`KEY() USING CLUSTERED COLUMNSTORE`is a legacy syntax that is equivalent to`SORT KEY()`.SingleStorerecommends using`SORT KEY()`. | N/A |
| **Rowstore key** | Creates an index on a column or group of columns to support fast lookups, or uniqueness enforcement. | A rowstore key may only be defined on rowstore tables. See[Rowstore keys](https://docs.singlestore.com/cloud/create-a-database/rowstore.md)and[Choosing Rowstore Keys](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures.md)for more information. | The index created with this key can be defined as a skiplist or hash index. | N/A |
| **Skiplist index** | A skiplist is a data structure optimized for ordered data that allows for queries to quickly seek data by binary searching. Skiplists inSingleStore Heliosare meant to replace the B-Tree indexes used by most other databases, including MySQL. | Skiplist indexes may only be defined on rowstore tables. See[Skip List Indexes](https://docs.singlestore.com/cloud/create-a-database/other-schema-concepts.md)for more information. | This is the default index type for rowstore tables, unless otherwise specified. | N/A |
| **Hash index** | A hash table is a data structure optimized for fast equality lookups by a key. | A hash index can be defined for either columnstore or rowstore tables. See[Hash Table Indexes](https://docs.singlestore.com/cloud/create-a-database/other-schema-concepts.md)for more information and the syntax to define this type of index. | Only one unique hash index per table can be created, and one or multiple columns are allowed per hash index. | Cannot be created on columns with the following dataypes:`FLOAT`,`REAL`, or`DOUBLE` |
| **Full-text index** | Full-text search allows searching for words or phrases in a large body of text through an inverted index. | Full-text indexes may only be defined on columnstore tables. See[Create Table with FULLTEXT Columns](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table/#UUID-5a7c66e9-736e-ce79-7a7e-1106691d9e5a.md)for the syntax to define this type of index. | N/A | Can only be created on columns with the following data types:`CHAR`,`VARCHAR`,`TEXT`, and`LONGTEXT` |
| **Vector Index** | The vector index provides Approximate Nearest Neighbor (ANN) search which finds a set of k nearest neighbors very efficiently. | Vector indexes may only be defined on columnstore tables.Refer to[Vector Indexing](https://docs.singlestore.com/cloud/reference/sql-reference/vector-functions/vector-indexing.md)for the syntax to define this type of index | N/A | A vector index must be built on a single column of type`VECTOR (, [F32])`where``is the number of dimensions.The element type is restricted to`F32`. |
| **Geospatial index** | A geospatial index can be defined on columns containing spatial data and serves to speed up queries on them. | Geospatial indexes may only be defined on rowstore tables. See[Working with Geospatial Features](https://docs.singlestore.com/cloud/developer-resources/functional-extensions/working-with-geospatial-features.md)for the syntax to define this type of index. | N/A | Can only be created on columns with the following data types:`GEOGRAPHY`, and`GEOGRAPHYPOINT` |
| **Multi-Value Hash Index** | Maps values to the row IDs containing the value. | Multi-value hash index is useful in searching for elements within composite data structures like arrays, BSON documents, etc.Refer to[Multi-Value Hash Index (BSON)](https://docs.singlestore.com/cloud/reference/sql-reference/bson-functions/multi-value-hash-index-bson.md)or[Multi-Value Hash Index (JSON)](https://docs.singlestore.com/cloud/create-a-database/multi-value-hash-index-json.md)for creating multi-key indexes on the respective column types. | N/A | Multi-value hash index is supported only on JSON and BSON type columns. |
***
Modified at: October 1, 2025
Source: [/cloud/create-a-database/understanding-keys-and-indexes-in-singlestore/](https://docs.singlestore.com/cloud/create-a-database/understanding-keys-and-indexes-in-singlestore/)
(An index of the documentation is available at /llms.txt)
---
# Understanding Shard Key Selection
## Shard Key
The shard key is a table column or multiple columns used to control how the rows of that table are distributed. Shard keys are vital in a distributed database like SingleStore. They are responsible for distribution of data across partitions. Shard key columns should be as unique as possible.
To determine the partition responsible for a given row, SingleStore computes a hash from all the columns in the shard key and uses this hash to assign the partition ID. Therefore, rows with the same value for the shard key column will reside on the same partition.
## Data Distribution into Partitions
Data is distributed amongst the partitions in the leaf nodes based on the shard key selected when a table is created. Rows with the same shard key value are stored in the same partition, even if they are in a different table.
For example, the table below has the shard key that contains only the `first` column. All people with the same first name will be stored on the same partition.
```sql
DROP TABLE IF EXISTS people;
CREATE ROWSTORE TABLE people (
user VARCHAR(24),
first VARCHAR(24),
last VARCHAR(24),
SHARD KEY(first)
);
```
Inside the node, values within the `first` column attempt to distribute evenly across all partitions.

But using a first name column as the shard key can create data skew because some first names are more common than others. Data skew occurs when data is unevenly distributed across partitions.
If `first` is used as the shard key, the data could be distributed amongst the partitions as follows. SingleStore computes a hash from all the columns in the shard key and uses this hash to assign the partition. Rows with the same value for the shard key column will reside on the same partition.

In the first partition, three of the rows have the same shard key value ("alex") so the rows would be assigned to the same partition. For the row with the shard key value of "tom", the hash computation just happened to assign this row to the first partition. This is the case with the other three partitions. The data in the `people` table is distributed unevenly across partitions resulting in data skew. If this table had millions of rows, the data skew could be even more pronounced.
When data is skewed, some partitions will store more data than others, throwing off the balance of the cluster. Those partitions with more data than the average will probably be asked to do more work during `SELECT`, `UPDATE`, and `DELETE` queries. Since a query executes as fast as its slowest partition, data skew affects overall performance.
Choosing an appropriate shard key for a table is important for minimizing data skew. In the `CREATE TABLE` example, the `user` column would be a better choice for the shard key, in terms of even data distribution. It will be more evenly distributed, and it is likely to be a filter for queries against the table. However, it is best **not** to use a varchar column as the shard key at all because of the inherent potential for data skew. Also, varchar data types take longer to process during query execution. Since `JOIN` operations are generally performed on the shard key, using a varchar data type as the shard key can impact performance. In our example, you would get optimal data distribution by creating an auto-increment `id` column as the shard key.
```sql
DROP TABLE IF EXISTS people;
CREATE ROWSTORE TABLE people (
id INT AUTO_INCREMENT PRIMARY KEY,
user VARCHAR(24),
first VARCHAR(24),
last VARCHAR(24),
SHARD KEY(id)
);
```
On a rowstore table, if a primary key is specified without a shard key, then the primary key will be used as the shard key. If the table doesn't have a primary key or a shard key, the engine will perform keyless sharding on that table. This means the engine generates a random number using a hash function, then maps the resulting random number to a partition.
The `METADATA_ONLY` option on the `SHARD KEY` syntax prevents an index being created on the shard key. It will decrease overall memory usage. It can cause queries to run slower. It can only be used when creating your table.
## Resolving Data Skew
SingleStore does not support the use of `ALTER TABLE` to add or change shard keys on existing tables. If your data becomes skewed, there are a couple of workarounds to reduce the skew in a table.
One method to reduce skew in a table is by using the `INSERT INTO… SELECT` to redistribute the data with the `force_random_reshuffle` query hint. A common use case for this hint is on keyless sharded tables, as it allows forced redistribution of data among partitions, rather than inserting it locally into the same partition.
Create a table without a specified shard key:
```sql
DROP TABLE IF EXISTS people;
CREATE ROWSTORE TABLE people (
id INT,
user VARCHAR(24),
first VARCHAR(24),
last VARCHAR(24)
);
```
Create another table with one shard key:
```sql
DROP TABLE IF EXISTS people_1;
CREATE ROWSTORE TABLE people_1 (
id INT AUTO_INCREMENT,
user VARCHAR(24),
first VARCHAR(24),
last VARCHAR(24),
SHARD KEY(id)
);
```
Create another table with multiple shard keys:
```sql
DROP TABLE IF EXISTS people;
CREATE ROWSTORE TABLE people (
id INT AUTO_INCREMENT,
user VARCHAR(24),
first VARCHAR(24),
last VARCHAR(24),
SHARD KEY(id,user)
);
```
INSERT INTO...SELECT using force\_random\_reshuffle:
```sql
INSERT INTO people_1 (id, user, first, last)
SELECT WITH(force_random_reshuffle=1) *
FROM people;
```
Run the following query to confirm the data is no longer skewed:
```sql
SELECT
DATABASE_NAME,
TABLE_NAME,
ORDINAL AS PARTITION_ID,
ROWS,
MEMORY_USE
FROM INFORMATION_SCHEMA.TABLE_STATISTICS
WHERE TABLE_NAME = 'people_1';
```
## Questions to Ask When Choosing Shard Keys
* Does this table have a primary key? *Make sure there is a shard key and that it is a subset of the primary key.*
* Do you frequently join on a specific set of columns? *Try to make the shard key a subset of the joined columns. Shard order should be the same between tables to accomplish this. For example, if you frequently join an `id` and `user_id` column, one of those columns should be the shard key.*
* Do you frequently filter on a specific set of columns? *Try to make the shard key a subset of the filtered columns.*
> **📝 Note**: Filtering on a range of the shard key can negatively affect the performance of your query. Multiple partitions may need to be scanned, thereby slowing the retrieval of your result set.
* Do you have high concurrency queries? *Choose a shard key that allows these queries to be single partition.*
* Is your data skewed for your current choice of shard key? *Try to add additional columns to the shard key to ensure even distribution.*
* Do you need to `UPDATE` or `ALTER` any fields in the shard key? *Remove those fields from the shard key.*
* Is this a small, infrequently changing table that needs to be on every node in the cluster to guarantee local joins? *Use a reference table instead of sharding the table.*
## Local Joins and Distributed Joins
A local join is a join that can be executed in the partition where the data is currently stored. The tables that are joined must have a shard key that matches the join condition. The best way to accomplish this is to set the shard key on the column that you will be frequently joining on. In our first example of the `people` table with `id` as the shard key, say we are joining to an `address` table within the same database. To ensure your joins execute locally, make sure `id` is a column and a shard key in the `address` table.
A distributed join is a join where the shard key that matches the join condition is stored on different partitions. Distributed joins occur in 2 ways:
1\) Repartition:
* Each partition opens connections to every node.
* Because the join requires the table to be sharded on the join condition, the query optimizer will create an internal, temporary results table in memory. This table will contain the results set at that stage of the query with a shard key that matches the join condition.
2\) Broadcast:
* Occurs when one of the joining tables is small. Therefore, no cost is incurred by sending a copy of the table to each node.
* After the broadcast of the table, the join is performed on the partition where the larger table is stored.
A join between tables residing in different databases which reside in different partitions will be resolved through a distributed operation (broadcast or repartition) even if the shard keys of the tables match.
## Performance differences between repartition and broadcast operations
Queries that require distributed joins, i.e. queries which involve Broadcasts or Repartitions, generally require much larger numbers of connections and threads than other queries.
In most scenarios, the default settings for workload management will schedule your workload appropriately to utilize cluster resources without exhausting connection and thread limits.
## Related Topics
* [Sharding](https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-singlestore-helios/sharding.md)
* [Shard Keys](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures/shard-keys.md)
***
Modified at: June 18, 2026
Source: [/cloud/create-a-database/understanding-shard-key-selection/](https://docs.singlestore.com/cloud/create-a-database/understanding-shard-key-selection/)
(An index of the documentation is available at /llms.txt)
---
# Understanding Sort Key Selection
## Sort Key
The sort key is an index that groups rows of columnstore tables into logical segments, where each segment contains data for many rows. The sort key can be defined on a single column or multiple columns of a columnstore table.
To specify a sort key, use `SORT KEY`. The sort key order can be specified as ascending (`SORT KEY()`) or descending (`SORT KEY( DESC)`). A columnstore sort key cannot be altered once the table has been created. To create an unsorted columnstore table, specify an empty sort key using `SORT KEY()`.
A table scan using a sort key scans the table in the order of the sort key. A sort key cannot be used to scan a table in the reverse order of the sort key order.
The following example creates a table, `t1`, with a sort key on `col1` in descending order. In the first query in the example below, the sort order in the query (`DESC`) matches the sort order of the `SORT KEY`, and the table is scanned using the `SORT KEY`. In the second query, the sort order in the query (`ASC`) does not match the sort order of the `SORT KEY`, and the `SORT KEY` is not used in the table scan.
```sql
CREATE TABLE t1(col1 int, SORT KEY(col1 DESC));
EXPLAIN SELECT * FROM t1 ORDER BY col1 DESC;
```
```output
+------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+------------------------------------------------------------------------------------------------------------------+
| GatherMerge [remote_0.col1 DESC] partitions:all alias:remote_0 |
| Project [t1.col1] |
| OrderedColumnStoreScan test1.t1, KEY col1 (col1 DESC) USING CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+------------------------------------------------------------------------------------------------------------------+
```
```sql
EXPLAIN SELECT * FROM t1 ORDER BY col1;
```
```output
+-----------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-----------------------------------------------------------------------------------------------------------+
| GatherMerge [remote_0.col1] partitions:all alias:remote_0 |
| Project [t1.col1] |
| Sort [t1.col1] |
| ColumnStoreScan test1.t1, KEY col1 (col1 DESC) USING CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+-----------------------------------------------------------------------------------------------------------+
```
The following example creates a table with an empty sort key.
```sql
CREATE TABLE t1(col1 int, SORT KEY( ));
EXPLAIN SELECT * FROM t1;
```
```output
+---------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+---------------------------------------------------------------------------------------------------------+
| Gather partitions:all alias:remote_0 |
| Project [t1.col1] |
| ColumnStoreScan test8.t1, KEY __UNORDERED () USING CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+---------------------------------------------------------------------------------------------------------+
```
> **📝 Note**: `KEY() USING CLUSTERED COLUMNSTORE` is a legacy syntax that is equivalent to `SORT KEY()`. SingleStore recommends using `SORT KEY()`.
SingleStore recommends defining a shard key to explicitly control the data distribution. The following example defines a shard key on `id`. Sharding on a high cardinality identifier column generally allows for more even distribution and prevents skew. Refer to [Understanding Shard Key Selection](https://docs.singlestore.com/cloud/create-a-database/understanding-shard-key-selection.md) for more information.
```sql
CREATE TABLE people (
id INT AUTO_INCREMENT,
user VARCHAR(24),
first VARCHAR(24),
last VARCHAR(24),
SORT KEY (user),
SHARD KEY (id)
);
```
Setting the shard key and the sort key on the same column improves data compression.
Refer to [Managing Columnstore Segments](https://docs.singlestore.com/cloud/create-a-database/columnstore/managing-columnstore-segments.md) for additional information about columnstore segments.
## Segment Elimination
The single most important consideration for columnstore tables is setting a sort key. Each segment file contains metadata that holds the minimum and maximum values for the rows in the segment. The minimum/maximum value metadata is used at query execution time to determine whether a segment can possibly match a filter; if not, the segment is skipped entirely and no data is examined. This functionality is called segment elimination because the segment is eliminated from the scan.
For queries that filter on the sort key column of the columnstore index, segment elimination is typically very efficient as row segments within each row segment group will not have overlapping segments.
The segment size (number of rows per segment) also impacts query execution with respect to the sort key. A smaller segment size means that a smaller number of rows are read from the segments that pass segment elimination. Column segments typically contain on the order of tens of thousands of rows.
Indexing further cuts down on the number of rows scanned when a select query with a `WHERE` clause is executed. If the table has an index for the columns in the `WHERE` clause, the engine can quickly determine the location of the matching rows position to seek without having to look at all the data. This is much faster than reading every row sequentially.
The figures below show three segments of the `people` table. The segment size is 3 rows for readability.
Segment #1 of 3 - `user` values aa - jl

Segment #2 or 3 - `user` values jm - rl

Segment #3 of 3 - `user` values rm - zz

If a query is searching for a person whose first name starts with an "a", then only the first segment is scanned. The other two segments are eliminated from the scan since those `user` values are "jm - zz".
## Ordered Scans
Ordered scan over a sort key is faster than sorting a table. A query that sorts with a sort key can benefit from running an ordered columnstore scan instead of performing a normal columnstore scan.
## Sub-segment Elimination
Sub-segment elimination improves performance by eliminating data at the sub-segment level during query processing and thus extends the performance improvements provided by segment elimination.
Segments consist of blocks of 4096 rows each. With sub-segment elimination, statistics are collected for blocks and are used during query processing to eliminate blocks. Sub-segment elimination is restricted to sort key columns.
A segment with the default size (`columnstore_segment_rows = 1,024,000`) would have 1,024,000 / 4,096 = 250 sub-segments. Queries with highly selective predicates using flexible parallelism are expected to see performance improvements due to sub-segment elimination.
Consider a table and a query as follows:
```sql
CREATE TABLE sales(id INT, dt DATETIME, itemnum INT, qty FLOAT, price numeric(18,4), SORT KEY(dt));
SELECT itemnum, SUM(qty*price)
FROM sales
WHERE dt BETWEEN "2024-09-20 17:00:00" AND "2024-09-20 17:01:00"
GROUP BY all;
```
This query has a very narrow time range (a highly selective predicate) on the `dt` column, and the `dt` column is the sort key. Sub-segment elimination will be applied to this query and is expected to improve the performance of this query.
The following figure shows how sub-segment elimination can greatly reduce the number of rows read and significantly improve performance.

Segments that were created before sub-segment elimination was introduced, or which were created when the `enable_block_stats_use_in_query` engine variable was set to `OFF`, will not have block-level statistics and will not benefit from sub-segment elimination. Such segments will need to be rebuilt to benefit from sub-segment elimination.
The engine variable `enable_block_stats_use_in_query` is set to `ON` by default.
## Multi-Column Sort Keys
Sort keys can be defined on multiple columns, which can improve performance in certain cases.
## Storage
The following examples show how a table is stored with a single-column sort key followed by how the table is stored with a two-column sort key.
The data in a partition is broken into segments based on the sort key order and the segment size. (Refer to [Configuring the Columnstore to Work Effectively](https://docs.singlestore.com/cloud/create-a-database/configuring-the-columnstore-to-work-effectively.md) for more information.)
Create a table named `INTEGERS` with a single-column sort key.
```sql
CREATE TABLE INTEGERS (
A int,
B int,
SORT KEY (A)
);
```
The data in the `INTEGERS` table will be sorted on column `A`, and then broken into segments, so that segments contain contiguous values of column `A`.
The figure below shows how the data is stored with the single-column sort key. If the integers 1 - 10 are inserted into columns A and B, and the segment size is 8, the first three columnstore segments would look as follows. The segmentation is defined by the sort key order.

For a multi-column sort key, the data in a partition is also broken into segments based on the sort key order and the segment size.
The command below creates a table named `INTEGERS` with a multi-column sort key on columns `A` and `B`.
```sql
CREATE TABLE INTEGERS (
A int,
B int,
SORT KEY (A,B)
);
```
The data in this table will be sorted on column `A`, and secondarily on column `B`, and then broken into segments so each segment contains a contiguous segment of data in that (multi-column) sort order.
The figure below shows how the data is stored with the multi-column sort key. If the integers 1 - 10 are inserted into columns `A` and `B`, and the segment size is 10, the first three columnstore segments would look as follows. The segmentation is defined by the sort key order - sorting the data first on the values in `A`, and then secondarily on the values in column `B`.

## Example
Creating multi-column sort keys on a table can improve query performance. For example, queries on a table with date and region columns would be expected to benefit from a sort key defined on both columns (`SORT KEY (date, region)`). This sort key definition clusters the table on date and region columns, so that segments contain values with similar date and region values. This in turn makes encoding more effective so the data is better compressed. For queries on this table that filter on date and region columns, the engine eliminates segments and sub-segments that do not meet the filter criteria, reducing the amount of scanning needed for the query. Efficient encoding also helps reduce I/O during the scan.
## Questions to Ask When Choosing Sort Keys
* Is the data always filtered by some column (e.g. insert timestamp or event type)? Ensure that the common columns for all queries are in the sort key to improve segment elimination.
* Is the data generally inserted in order by some column (e.g. insert timestamp)? It’s best to put that column first in the sort key to minimize the amount of work required by the background columnstore segment merger.
* Does one column in your key have a higher cardinality than the other? It’s best to put the lowest cardinality columns first to increase the likelihood that segment elimination will be able to affect later columns.
## Related Topics
* [Understanding Shard Key Selection](https://docs.singlestore.com/cloud/create-a-database/understanding-shard-key-selection.md)
* [Managing Columnstore Segments](https://docs.singlestore.com/cloud/create-a-database/columnstore/managing-columnstore-segments.md)
* [How the Columnstore Works](https://docs.singlestore.com/cloud/create-a-database/columnstore/how-the-columnstore-works.md)
***
Modified at: August 6, 2026
Source: [/cloud/create-a-database/understanding-sort-key-selection/](https://docs.singlestore.com/cloud/create-a-database/understanding-sort-key-selection/)
(An index of the documentation is available at /llms.txt)
---
# Using JSON
## About JSON in SingleStore
SingleStore exposes a Javascript Object Notation (JSON) (An open standard file format and data interchange format that uses human-readable text to store and transmit data objects consisting of attribute–value pairs and arrays.) column type that implements the [JSON standard](http://http://www.ietf.org/rfc/rfc4627.txt).
You can define columns in SingleStore tables using the [JSON Type](https://docs.singlestore.com/cloud/reference/sql-reference/data-types/json-type.md). Analytics on these JSON columns is very efficient as SingleStore automatically columnarizes JSON data. A schema is inferred from JSON keys and the data is split into columns by key path and stored in an encoded [Parquet-like format](https://docs.singlestore.com/cloud/create-a-database/columnstore/columnstore-seekability-using-json/#section-idm413515222379322.md).
The JSON data is stored as if you had created a schema with separate columns for every field. As a result, queries on JSON columns read only the parts of a JSON object that are relevant to a query and therefore have excellent performance.
SingleStore provides a set of JSON functions for extracting, searching, analyzing, and modifying JSON data, including:
* [JSON\_EXTRACT\_\](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-extract-type.md), to extract values out of JSON documents at specified keypaths.
* Shorthand syntax, `::` operators, to extract values out of JSON documents. The `::` operators are convenient aliases for the `JSON_EXTRACT_` functions and follow the same rules.
* JSON shorthand syntax is a path that uses `::` as a separator.
* [JSON\_MATCH\_ANY](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-match-any.md), to check for the existence of values in a JSON document or array based on a path and a filter.
* [JSON\_TO\_ARRAY](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-to-array.md), to convert a JSON array to a SingleStore array.
* `JSON_TO_ARRAY` can be used in combination with [TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/table.md) to operate on values of a JSON array as SQL rows. This functionality is similar to `UNNEST` in other database systems.
JSON columns can be searched using SingleStore's [Java Lucene](https://lucene.apache.org/core/)-compatible [full-text search](https://docs.singlestore.com/cloud/developer-resources/functional-extensions/working-with-full-text-search.md) and indexed with the [Multi-Value Hash Index (JSON)](https://docs.singlestore.com/cloud/create-a-database/multi-value-hash-index-json.md). In addition, JSON columns can be indexed using computed columns; refer to [Indexing Data in JSON Columns](https://docs.singlestore.com/#UUID-2ccafa6b-ead7-016d-adca-79fb8d0bdade.md) for more information.
SingleStore has a native BSON data type, plus [SingleStore Kai](https://docs.singlestore.com/cloud/reference/singlestore-kai.md), a MongoDB®-compatible API. The BSON data is stored in columns just like JSON data, and can be indexed with the [Multi-Value Hash Index (BSON)](https://docs.singlestore.com/cloud/reference/sql-reference/bson-functions/multi-value-hash-index-bson.md) and computed columns.
An alternative to using the `JSON` type is to map JSON fields to individual columns and use SQL queries to access the JSON data. Refer to [Load JSON Files with LOAD DATA](https://docs.singlestore.com/cloud/load-data/load-data-from-files/load-data-from-json-files/load-json-files-with-load-data.md) for information about how to map `JSON` fields to SingleStore columns during the loading process.
## JSON Data Encodings
The default encoding for `JSON` columns is `SeekableJson`. As described above, this encoding is very efficient as it columnarizes the JSON. A schema is inferred from JSON keys and the data is split into columns by keypath and stored in an encoded Parquet-like format. Refer to [Columnstore Seekability using JSON](https://docs.singlestore.com/cloud/create-a-database/columnstore/columnstore-seekability-using-json.md) for more information.
`JSON` columns may also be encoded with the [string encodings](https://docs.singlestore.com/cloud/reference/sql-reference/data-types/encoding-string-data-in-columnstore-tables.md) `SeekableLZ4` and `SeekableStringRunLength`. These encodings compress data, but do not support efficient searches or extraction. SingleStore recommends using `SeekableLZ4` and `SeekableStringRunLength` only for columns on which JSON values will be extracted as a whole.
**Note**: The information on this page is intended for use with `JSON` columns created with `SeekableJson` encoding or its precursor `JSONParquet`. Using functions described on this page on `JSON` columns with a string encoding will result in poor performance.
## Examples
The following table is used in the examples. Note the `printings` array is intended to indicate the number of copies of the book printed in each printing; `printings` data is in millions of books and is not accurate.
```sql
CREATE TABLE books_json (id INT, books JSON);
INSERT INTO books_json VALUES
(1, '{
"title": "Onyx Storm",
"author": "Rebecca Yarros",
"details": {
"publisher": "Entangled:Red Tower Books",
"numpages": 544,
"publication date": "January 21, 2025",
"printings": [2,1.3],
"series": "The Empyrean"
}
}'
),
(2, '{
"title": "The Maid",
"author": "Nita Prose",
"details": {
"publisher": "Ballantine Books",
"numpages": 385,
"publication date": "January 4, 2022",
"printings": [0.5,0.75,1.2]
}
}'
),
(3, '{
"title": "The Last Letter",
"author": "Rebecca Yarros",
"details": {
"publisher": "Entangled:Amara",
"numpages": 432,
"publication date": "February 26, 2019",
"printings": [0.25,0.5,0.5]
}
}'
);
```
## Example 1: Extract Values from JSON Using the `::` Operators
The `::`, `::$`, and `::%` operators can be used to extract fields, strings, and SQL doubles from JSON documents. In the example below:
* `books::title` extracts the `title` field,
* `books::$title` extracts the `title` field as a SQL string,
* `books::details::%numpages` extracts the `numpages` field as a double, and
* `` books::details::printings::%`0` `` extracts the 0th element of the `printings` array.
Backticks (\`) are required around numeric keys, as shown with `` `0` `` above
Refer to [Using the ::$ and ::% Operators](https://docs.singlestore.com/#UUID-36dc6fd4-161c-cbc2-4a87-556e9d33d4dd.md) for details.
```sql
SELECT id,
books::title AS title,
books::$title AS title_string,
books::details::%numpages AS numpages,
books::details::printings::%`0` AS first_printing
FROM books_json
ORDER BY id;
```
```output
+------+-------------------+-----------------+----------+----------------+
| id | title | title_string | numpages | first_printing |
+------+-------------------+-----------------+----------+----------------+
| 1 | "Onyx Storm" | Onyx Storm | 544 | 2 |
| 2 | "The Maid" | The Maid | 385 | 0.5 |
| 3 | "The Last Letter" | The Last Letter | 432 | 0.25 |
+------+-------------------+-----------------+----------+----------------+
```
## Example 2: Extract Values from JSON using `JSON_EXTRACT_`
The [JSON\_EXTRACT\_](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-extract-type.md) functions can be used to extract values from a JSON document in addition to the path expression syntax shown in Example 1. The `JSON_EXTRACT_` functions can be used when you want to use variables or expressions in the keypath. The keypath in `JSON_EXTRACT_` functions is a comma-separated list of object keys or zero-indexed array positions.
Below is a query similar to the query in Example 1, expressed using `JSON_EXTRACT_` functions.
```sql
SELECT id,
JSON_EXTRACT_JSON(books,'title') AS title,
JSON_EXTRACT_STRING(books,'title') AS title_string,
JSON_EXTRACT_BIGINT(books,'details','numpages') AS numpages,
JSON_EXTRACT_DOUBLE(books,'details','printings',1-1) AS first_printing
FROM books_json
ORDER BY id;
```
```output
+------+-------------------+-----------------+----------+----------------+
| id | title | title_string | numpages | first_printing |
+------+-------------------+-----------------+----------+----------------+
| 1 | "Onyx Storm" | Onyx Storm | 544 | 2 |
| 2 | "The Maid" | The Maid | 385 | 0.5 |
| 3 | "The Last Letter" | The Last Letter | 432 | 0.25 |
+------+-------------------+-----------------+----------+----------------+
```
Note that the expression `1-1` is used to extract the value in position 0 in the `printings` array. Such expressions are supported in `JSON_EXTRACT_` functions, but not when using the `::` operators.
A `JSON_EXTRACT_` on a nested key will only scan the column for that key, not the entire JSON document. For example, `JSON_EXTRACT_JSON(jsondata,'details','title') AS title`, will only scan the column for the `title` key.
## Example 3: Find Existence of Values and Paths using JSON\_MATCH\_ANY
The [JSON\_MATCH\_ANY](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-match-any.md) and [JSON\_MATCH\_ANY\_EXISTS](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-match-any.md) functions can be used to find the existence of values matching predicates and paths in JSON documents.
The `JSON_MATCH_ANY` function returns true if a value exists in the JSON at the filter path for which the filter predicate evaluates to true. The `JSON_MATCH_ANY_EXISTS` function returns true if there is a value (possibly null) in the JSON at the filter path.
The following is an example of using `JSON_MATCH_ANY` to find books that are part of `The Empyrean` series.
```sql
SELECT id, books::$title AS title, books::details::$series AS series
FROM books_json
WHERE JSON_MATCH_ANY(books::?details.series, MATCH_PARAM_STRING_STRICT() = "The Empyrean");
```
```output
+------+------------+--------------+
| id | title | series |
+------+------------+--------------+
| 1 | Onyx Storm | The Empyrean |
+------+------------+--------------+
```
## Example 4: Aggregate Elements in a JSON Array Value using REDUCE
The [REDUCE](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/reduce.md) function can be used to aggregate elements in a JSON array value. SingleStore recommends using the `REDUCE` function when aggregating elements within a JSON array in a row.
Refer to [Example 5](https://docs.singlestore.com/#section-idm234948461588865.md) for an example of aggregating JSON array values across multiple rows which takes advantage of [JSON Array Performance Enhancements](https://docs.singlestore.com/#section-idm323419580718356.md).
The `REDUCE` function applies an expression to each element of an array and returns a single value. In the following example, `REDUCE` is used to sum the elements of the printings array for each row. The result is the total number of copies of each book that have been printed.
```sql
SELECT books::$title,
REDUCE(
0 :> double,
JSON_TO_ARRAY(books_json.books::details::printings),
REDUCE_ACC() + REDUCE_VALUE()
) AS total_printed_by_book
FROM books_json;
```
```output
+-----------------+-----------------------+
| books::$title | total_printed_by_book |
+-----------------+-----------------------+
| The Maid | 2.45 |
| The Last Letter | 1.25 |
| Onyx Storm | 3.3 |
+-----------------+-----------------------+
```
In this example:
1. The `JSON_TO_ARRAY` function converts the array in the JSON field `jsondata::books::details::printings` to a SQL array.
2. The `REDUCE` function takes as input
1. An initial value: `0:>double`.
2. A SQL array: the result of `JSON_TO_ARRAY`.
3. An accumulator expression: `(REDUCE_ACC() + REDUCE_VALUE())`, which specifies that the array elements should be summed.
## Example 5: Use the `::` Operators in UPDATE Statements
You can use the `::` operators for JSON keypaths in [UPDATE](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/update.md) queries. The `::` operators are simply convenient aliases for the [JSON\_SET\_\](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-set-type.md) functions and follow the same rules.
The following query updates the number of pages in the book, `Onyx Storm`.
```sql
UPDATE books_json
SET books::details::%numpages = 545
WHERE books::$title = "Onyx Storm";
```
To add a printing for the book `Onyx Storm`, use [JSON\_ARRAY\_PUSH\_\](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-array-push-type.md) as follows.
```sql
UPDATE books_json
SET books::details::printings = JSON_ARRAY_PUSH_DOUBLE(books::details::printings, 1.5)
WHERE books::$title = "Onyx Storm";
```
To add a series to the book `The Maid`.
```sql
UPDATE books_json
SET books::details::$series = 'Molly the Maid'
WHERE books::$title = "The Maid";
```
View the resulting updates.
```sql
SELECT JSON_PRETTY(books)
FROM books_json
WHERE books::$title = "The Maid";
```
```output
+---------------------------------------------+
| {
"author": "Nita Prose",
"details": {
"numpages": 385,
"printings": [
0.5,
0.75,
1.2
],
"publication date": "January 4, 2022",
"publisher": "Ballantine Books",
"series": "Molly the Maid"
},
"title": "The Maid"
} |
+---------------------------------------------+
```
## Example 6: Convert an Array (List) of JSON Objects to a Table
Use the `JSON_TO_ARRAY` function and the `TABLE` built-in function to convert a list of JSON objects to a table.
Create a table with a column to hold a JSON value and insert data into that table.
```sql
CREATE TABLE json_list_example (json_list JSON);
INSERT INTO json_list_example values(
'[
{
"title": "Onyx Storm",
"author": "Rebecca Yarros",
"numpages": 544
},
{
"title": "The Last Letter",
"author": "Rebecca Yarros",
"numpages": 432
}
]');
```
In the following query, the syntax `JOIN TABLE(JSON_TO_ARRAY(json_list))` converts the objects in the `json_list` column to a table, that is, each object in the JSON list is turned into a row in the table.
* The `JSON_TO_ARRAY` function converts the JSON array to a SingleStore `ARRAY`.
* The `TABLE` function converts a SingleStore `ARRAY` to a column named `table_col` that contains one row for each array entry.
* The `JOIN` clause is required when using the `TABLE` function on an existing SingleStore table.
```sql
SELECT json_list_as_table.table_col AS books_col
FROM json_list_example JOIN TABLE(JSON_TO_ARRAY(json_list)) AS json_list_as_table;
```
```output
+----------------------------------------------------------------------+
| books_col |
+----------------------------------------------------------------------+
| {"author":"Rebecca Yarros","numpages":544,"title":"Onyx Storm"} |
| {"author":"Rebecca Yarros","numpages":432,"title":"The Last Letter"} |
+----------------------------------------------------------------------+
```
The `JSON_AGG` function can be used to combine the rows in the table into a single row and re-create the original JSON array.
```sql
WITH books_table AS (
SELECT json_list_as_table.table_col AS books_col
FROM json_list_example JOIN TABLE(JSON_TO_ARRAY(json_list)) AS json_list_as_table
)
SELECT JSON_AGG(books_col) FROM books_table;
```
```output
+----------------------------------------------------------------------------------------------------------------------------------------+
| JSON_AGG(books_col) |
+----------------------------------------------------------------------------------------------------------------------------------------+
| [{"author":"Rebecca Yarros","numpages":544,"title":"Onyx Storm"},{"author":"Rebecca Yarros","numpages":432,"title":"The Last Letter"}] |
+----------------------------------------------------------------------------------------------------------------------------------------+
```
## Example 7: Aggregate Elements in JSON Arrays Across Rows using TABLE and JSON\_TO\_ARRAY
Use the [TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/table.md) and [JSON\_TO\_ARRAY](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-to-array.md) functions to aggregate values from JSON arrays across rows. Aggregations over results of the `JOIN TABLE(JSON_TO_ARRAY())` operation are optimized to reduce the amount of data read. Queries will retrieve only the parts of the JSON column relevant to the query instead of fetching the entire JSON object from disk. Refer to [JSON Array Performance](https://docs.singlestore.com/#section-idm323419580718356.md) for details.
The following example uses the `TABLE` and `JSON_TO_ARRAY` functions to sum the elements in the printings array across all rows for each author.
```sql
SELECT books::$author AS author, SUM(JSON_EXTRACT_DOUBLE(i.table_col)) AS total_printed_by_author
FROM books_json
JOIN TABLE(
JSON_TO_ARRAY(books_json.books::details::printings)) AS i
GROUP BY author;
```
```output
+----------------+-------------------------+
| author | total_printed_by_author |
+----------------+-------------------------+
| Rebecca Yarros | 4.55 |
| Nita Prose | 2.45 |
+----------------+-------------------------+
```
In this example:
1. The `JSON_TO_ARRAY` function converts the array in the JSON field `books_json.books::details::printings` to a SQL array.
2. The `TABLE` function converts this array into a table.
3. The `JOIN` clause `FROM books_json JOIN TABLE(JSON_TO_ARRAY(books_json.books::details::printings)) AS i` creates a table that contains:
1. For each row in the `books_json` table:
1. One row for each element in the `printings` array in that row.
2. This row contains the values from the columns in the `books_json` table and a column, `table_col`, which contains the array value.
4. Finally, the `SELECT` and `GROUP BY` aggregate over the table created in step 3.
In this example, which aggregates over multiple JSON documents, SingleStore only reads the `author` and `printings` values to compute the result. Additional JSON values, such as `title`, `publisher`, and `numpages`, will not be read making the query execution very efficient.
**Note**: The `JSON_EXTRACT_DOUBLE()` function in the `SELECT` clause is necessary to use the `JSON_TO_ARRAY` optimization. If that function is removed, the query will execute, but will not use the optimization.
## Managing Collections of Metadata
JSON is useful for managing a collection of diverse data, represented as name-value pairs, that might otherwise be cumbersome to refactor into a formalized key-value table, or that might be stored in a table that is sparsely populated. For example, suppose an organization had an asset management application using SingleStore Helios to track all the information about its physical assets. The asset data is diverse—what’s relevant for a desk differs from what’s important for a server machine or a company car. All assets might have common attributes, such as asset tag ID, asset type, asset name, and description. Each type of asset might have unique attributes, such as size and weight dimensions, hostname and IP address, or gas mileage.
Instead of creating a highly granular table to manage all data as key-value pairs, this organization could simply create a SingleStore Helios table using a JSON column to efficiently manage the unique attribute data. With this design:
* Each asset gets a row in the table.
* Attributes that are common to all assets have their own column in the table. These columns allow you to query on common features and quickly narrow down the final result set as much as possible (for example, filtering by asset type).
* The various, remaining attributes associated with each asset are stored in a JSON column (which might be named something like `property_bag`). For example, the JSON column for an office desk asset could include JSON data such as size, weight, and number of drawers. The JSON data for a server machine could include rack location, number of cores, and MAC address.
## DDL: Defining Tables with JSON Columns
Any SingleStore Helios table can contain one or more columns of data type `JSON`. A JSON column can optionally be suffixed with `NOT NULL`.
## Comparing JSON and LONGTEXT Columns
A JSON column is analogous to a `LONGTEXT` column in the following ways:
* JSON columns can store arbitrarily large JSON values in a normalized text representation.
* JSON columns have the same storage requirement, as if the JSON value were stored in a text column.
The primary difference is that JSON data is stored in a normalized format, which makes many operations faster than if the data were stored manually in a text column. The following is an example of non-normalized data, which is valid JSON but is relatively difficult to parse:
```json
'{ "b\u000a": 1,"a": 2 ,"a":3 } '
```
Normalized data, on the other hand, is easier to parse because duplicate keys are merged, the data is sorted by keys, and extraneous whitespace is removed.
```json
'{"a":3,"b\n":1}'
```
SingleStore recommends storing JSON data in `JSON` columns and not in `LONGTEXT` columns. `JSON` columns validate the JSON values and provide [Unicode Support](https://docs.singlestore.com/#UUID-e72c5528-d96b-6095-ab75-bf514f7f247a.md). If storage space and memory use is a concern, and search and extraction are not required on the column, use a string encoding on the column. Refer to [Columnstore Seekability using JSON](https://docs.singlestore.com/cloud/create-a-database/columnstore/columnstore-seekability-using-json.md) for more information.
## Defining JSON Columns
Defining a JSON column in a SingleStore Helios table is as simple as specifying the JSON data type in the `CREATE TABLE` command:
```sql
CREATE TABLE assets (
tag_id BIGINT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
properties JSON NOT NULL);
```
## JSON Collation
The collation for a JSON column can be set explicitly using a `COLLATE` clause. When the collation is not set explicitly, the collation is controlled by the `json_collation` engine variable.
Refer to [Sync Variables Lists](https://docs.singlestore.com/cloud/reference/configuration-reference/engine-variables/list-of-engine-variables/#sync-variables-lists.md), [Character Set and Collation Override](https://docs.singlestore.com/cloud/reference/sql-reference/character-encoding/character-set-and-collation-override.md), [Unicode Support](https://docs.singlestore.com/#UUID-e72c5528-d96b-6095-ab75-bf514f7f247a.md), and [Character Encodings and Collation](https://docs.singlestore.com/#UUID-00e2ca08-8dc7-bc24-f268-b6bfde552e6a.md) for more information.
## Indexing Data in JSON Columns
JSON columns are not indexed directly - they are indexed using computed columns. For the fastest performance, you should not use JSON built-ins or `::` notation in your filters. Instead, create a computed column that includes the JSON column in the computation, and then use the computed column for the index. In this way, the index gets updated only when the relevant JSON data is updated in a row.
```sql
CREATE TABLE assets (
tag_id BIGINT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
properties JSON NOT NULL,
weight AS properties::%weight PERSISTED DOUBLE,
license_plate AS properties::$license_plate PERSISTED LONGTEXT,
KEY(license_plate), KEY(weight));
```
JSON computed columns that are indexed will be utilized by the optimizer more efficiently. Queries that use indexed computed columns as filters or sorts, will perform faster by avoiding expression evaluation, and by seeking into or searching the indexes rather than scanning tables. In the following examples, we will use the `::` notation in the filtering and sorting clauses to illustrate how the optimizer matches the computed columns.
```sql
EXPLAIN SELECT * FROM assets
WHERE properties::$license_plate = "VGB116";
```
```output
+------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+------------------------------------------------------------------------------------------------------------------+
| Gather partitions:all alias:remote_0 |
| Project [assets.tag_id, assets.name, assets.description, assets.properties, assets.weight, assets.license_plate] |
| ColumnStoreFilter [assets.license_plate = 'VGB116' index] |
| ColumnStoreScan test1.assets, KEY __UNORDERED () USING CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)
```
```sql
EXPLAIN SELECT * FROM assets
ORDER BY properties::%weight;
```
```output
+------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+------------------------------------------------------------------------------------------------------------------+
| GatherMerge [remote_0.weight] partitions:all alias:remote_0 |
| Project [assets.tag_id, assets.name, assets.description, assets.properties, assets.weight, assets.license_plate] |
| Sort [assets.weight] |
| ColumnStoreScan test1.assets, KEY __UNORDERED () USING CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)
```
## DML: Accessing Data in JSON Columns
This section describes how to insert and update data in a SingleStore Helios table with one or more JSON columns.
## Inserting Data into a JSON Column
When inserting a row in a table, specifying JSON data is straightforward. For example: Given a table `t` defined as `CREATE TABLE test_table(col_a TEXT, col_b JSON);`, you can insert a row into `test_table` as follows:
```sql
INSERT INTO test_table(col_a,col_b) VALUES ('hello','{"x":"goodbye","y":"goodnight"}');
```
## Columnstore Tables Having JSON Columns with Null Values or Empty Arrays
By default, SingleStore Helios preserves columnstore JSON `NULL` values and empty arrays. To change this behavior and disable this setting, set the `preserve_original_colstore_json` global variable to `OFF`. This flag preserves the original columnstore JSON for any new data that is loaded; it does not update the existing data. By default, this variable is set to `AUTO` (same as `ON`).
## Behavior When `preserve_original_colstore_json` is Set to `OFF`
When you store a JSON column in a columnstore table (and `preserve_original_colstore_json` is set to `OFF`), then null values and empty arrays in the JSON object are handled as follows when the object is written to the columnstore:
* Name/value pairs with the value `NULL` are normally removed from the JSON object.
* Name/value pairs containing empty arrays are normally removed from the JSON object.
* If the JSON object has only the value `NULL` or `[]`, the value is replaced with `NULL`.
Example commands you can use to store data are `INSERT`, `UPDATE`, and `LOAD DATA`.
An example `INSERT` scenario follows. Consider a table that is defined as:
```sql
CREATE TABLE json_empty_values_table(a INT, b JSON, SORT KEY (a));
```
Insert five rows into the table:
```sql
INSERT INTO json_empty_values_table VALUES (1, '{"v":null}');
INSERT INTO json_empty_values_table VALUES (2, '{"w":[]}');
INSERT INTO json_empty_values_table VALUES (3, '{"x":"foo","y":null,"z":[]}');
INSERT INTO json_empty_values_table VALUES (4, 'null');
INSERT INTO json_empty_values_table VALUES (5, '[]');
```
Manually flush the inserted data to the columnstore:
```sql
OPTIMIZE TABLE json_empty_values_table FLUSH;
```
Query the table:
```sql
SELECT * FROM json_empty_values_table ORDER BY a;
```
```output
+------+-----------------------------+
| a | b |
+------+-----------------------------+
| 1 | {"v":null} |
| 2 | {"w":[]} |
| 3 | {"x":"foo","y":null,"z":[]} |
| 4 | null |
| 5 | [] |
+------+-----------------------------+
```
## Accessing Fields in a JSON Object
To access a field of a JSON object stored in a column, use the name of the column suffixed with `::keyName`. For example, if column data contains `{"bits":[true,false]}`, then the expression `data::bits` evaluates to the JSON value `[true,false]`.
## Converting a JSON String Value into a SQL String
The `::` operator, when applied to a string column of a JSON object, returns the value of the string enclosed in quotes. Use the `::$keyname` operator to return the value of the string without the enclosing quotes.
For example, consider a table `TestJSON `that contains a JSON column `data`.
```sql
INSERT INTO TestJSON VALUES ('{"first":"hello"}');
```
Retrieve the value of the `data `column using `::` and `::$` operators:
```sql
SELECT data::first, data::$first FROM TestJSON;
```
```output
+-------------+--------------+
| data::first | data::$first |
+-------------+--------------+
| "hello" | hello |
+-------------+--------------+
```
In this example, the `data `JSON column contains two string values.
```sql
INSERT INTO TestJSON VALUES ('{"first":"hello", "second":"world"}');
```
To retrieve the concatenated SQL string, use the `::$` operator:
```sql
SELECT CONCAT(data::$first, ' ', data::$second) FROM TestJSON;
```
```output
+------------------------------------------+
| CONCAT(data::$first, ' ', data::$second) |
+------------------------------------------+
| hello world |
+------------------------------------------+
```
## Converting a JSON Number or Boolean Value into a SQL DOUBLE
To transparently convert a JSON number or Boolean value into a SQL `DOUBLE`, use the name of the column suffixed with `::%keyname`. For example, if column data contains `{"valid":true,"value":3.14}`, then `data::%valid` is 1 and `data::%value` is 3.14.
## Using the ::$ and ::% Operators
If the `::$` or `::%` access operator is used on a JSON field that is not of the appropriate type, SingleStore converts the JSON result to a string or a double according to the rules defined for `JSON_EXTRACT_`.
The `::` access operators are convenient aliases for the `JSON_EXTRACT_` built-in functions and follow the same rules. The `::` operator does not work on the output of user-defined functions (UDFs), such as `SELECT udf_name(1)::key`, or on expressions. It also does not work with non-scalar types (`RECORD`, `ARRAY`) because it is not a struct field accessor. Note that `ROW` is an expression that returns a `RECORD` type, not a type itself. Applying the `::` operator to a `RECORD` value, such as `table.row_col::field_name`, returns an error. For UDF outputs, use the `JSON_EXTRACT_` functions. For `RECORD` types, use the individual named columns.
SingleStore uses the `::` operator in the following contexts:
| Context | Syntax | Description | Example |
| --------------------------- | ----------------------------- | -------------------------------------------------------- | ------------------------------------ |
| JSON field extraction | `column::key` | Extracts a value from a JSON column by key | `metadata::name` |
| Nested JSON extraction | `column::key1::key2` | Navigates nested JSON objects | `details::address::city` |
| `JSON`type casting | `column::$key`,`column::%key` | Extracts a value as a string (`$`) or numeric (`%`) type | `data::$name`,`data::%age` |
| Subvalue path in`LOAD DATA` | `col <- path::key` | Maps nested JSON fields during data loading | `publisher_s2 <- details::publisher` |
| Remote table reference | `link::database.table` | References a table on a remote linked server | `mylink::remote_db.orders` |
In addition, The `::` operators require that numeric keys be specified with backticks (\`).
The following `SELECT` statement returns the 2nd (zero-indexed) array element of the array `{"a":[1,2,3,4]}`. A syntax error will be returned if the backticks (\`) are not included.
```sql
SELECT json, json::a::`2`
FROM (SELECT '{"a":[1,2,3,4]}' AS json) sub;
```
```output
+-----------------+--------------+
| json | json::a::`2` |
+-----------------+--------------+
| {"a":[1,2,3,4]} | 3 |
+-----------------+--------------+
```
In addition, backticks can be used for non-numeric key names and array indexes, which is useful if the key name or index contains a space.
The following query is valid and will return the same output as the query above.
```sql
SELECT json, json::`a`::`2`
FROM (SELECT '{"a":[1,2,3,4]}' AS json) sub;
```
```output
+-----------------+----------------+
| json | json::`a`::`2` |
+-----------------+----------------+
| {"a":[1,2,3,4]} | 3 |
+-----------------+----------------+
```
The following is the same logical query except the array index 2 has been replaced by the expression `1+1` and the `JSON_EXTRACT_JSON` function is used.
While this example uses a simple expression `(1+1)`, more functions such as `DAYOFWEEK` and more complex expressions can be used.
Refer to [JSON\_EXTRACT\_\](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-extract-type.md) for details.
```sql
SELECT json, JSON_EXTRACT_JSON(json, "a", 1+1)
FROM (SELECT '{"a":[1,2,3,4]}' AS json) sub;
```
```output
+-----------------+--------------+
| json | json::a::`2` |
+-----------------+--------------+
| {"a":[1,2,3,4]} | 3 |
+-----------------+--------------+
```
## Accessing Nested JSON Objects
To access nested JSON objects, chain the colon-colon operator to form a `keypath`. For example, `data::address::street` means the `street` field of the `address` field of the `data` column.
> **📝 Note**: If one of the keys in the keypath is not present in the nested object, then the `entire` colon-colon expression yields SQL `NULL`.
## Working with Nested Arrays in a JSON Column
Consider a table defined as:
```sql
CREATE TABLE json_tab (`id` INT(11) DEFAULT NULL,`jsondata` JSON COLLATE utf8_bin);
```
Insert values as follows:
```sql
INSERT INTO json_tab VALUES
( 8765 ,' {"city":"SFO","sports_teams":[{"sport_name":"football","teams": [{"club_name":"Raiders"},{"club_name":"49ers"}]},
{"sport_name":"baseball","teams" : [{"club_name":"As"},{"club_name":"SF Giants"}]}]}') ;
INSERT INTO json_tab VALUES
( 9876,'{"city":"NY","sports_teams" : [{ "sport_name":"football","teams" : [{ "club_name":"Jets"},{"club_name":"Giants"}]},
{"sport_name":"baseball","teams" : [ {"club_name":"Mets"},{"club_name":"Yankees"}]},
{"sport_name":"basketball","teams" : [{"club_name":"Nets"},{"club_name":"Knicks"}]}]}');
```
Query the table:
```sql
WITH t AS(
SELECT id, jsondata::city city , table_col AS sports_clubs FROM json_tab JOIN TABLE(JSON_TO_ARRAY(jsondata::sports_teams))),
t1 AS(
SELECT t.id, t.city, t.sports_clubs::sport_name sport, table_col AS clubs FROM t JOIN TABLE(JSON_TO_ARRAY(t.sports_clubs::teams)))
SELECT t1.id, t1.city,t1.sport,t1.clubs::club_name club_name FROM t1;
```
```output
+------+-------+--------------+-------------+
| id | city | sport | club_name |
+------+-------+--------------+-------------+
| 9876 | "NY" | "football" | "Jets" |
| 9876 | "NY" | "football" | "Giants" |
| 9876 | "NY" | "baseball" | "Mets" |
| 9876 | "NY" | "baseball" | "Yankees" |
| 9876 | "NY" | "basketball" | "Nets" |
| 9876 | "NY" | "basketball" | "Knicks" |
| 8765 | "SFO" | "football" | "Raiders" |
| 8765 | "SFO" | "football" | "49ers" |
| 8765 | "SFO" | "baseball" | "As" |
| 8765 | "SFO" | "baseball" | "SF Giants" |
+------+-------+--------------+-------------+
```
You can also further filter the results by applying conditions. For example, to find the city with the "Yankees" club, run the following query:
```sql
WITH t AS
(SELECT id, jsondata::city city , table_col AS sports_clubs FROM json_tab JOIN TABLE(JSON_TO_ARRAY(jsondata::sports_teams))),
t1 AS
(SELECT t.id, t.city, t.sports_clubs::sport_name sport, table_col AS clubs FROM t JOIN TABLE(JSON_TO_ARRAY(t.sports_clubs::teams)))
SELECT t1.id, t1.city,t1.sport,t1.clubs::club_name club_name FROM t1 WHERE t1.clubs::$club_name = 'Yankees';
```
```output
+------+------+------------+-----------+
| id | city | sport | club_name |
+------+------+------------+-----------+
| 9876 | "NY" | "baseball" | "Yankees" |
+------+------+------------+-----------+
```
## Nested JSON Ingest
Working with a nested JSON ingest requires an additional escape as the value being inserted is interpreted as a SQL string first. Therefore, the backslash (\\) symbol needs an escape in addition to the JSON escape (‘\’):
```sql
CREATE TABLE test_json(col_a json);
INSERT INTO test_json VALUES ('{"addParams": "{\\"Emp_Id\\":\\"1487\\",
\\"Emp_LastName\\":\\"Stephens\\",\\"Emp_FirstName\\":\\"Mark\\",\\"Dept\\":\\"Support\\"}"}');
```
```sql
SELECT * FROM test_json;
```
```output
+------------------------------------------------------------------------------------+
| col_a |
+------------------------------------------------------------------------------------+
| {"addParams":"{\"Emp_Id\":\"1487\", |
| \"Emp_LastName\":\"Stephens\",\"Emp_FirstName\":\"Mark\",\"Dept\":\"Support\"}"} |
+------------------------------------------------------------------------------------+
```
## Using Colon-Colon Notation in UPDATE Queries
You can use the colon-colon notation for JSON keypaths in [UPDATE](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/update.md) queries. For example, the following two `UPDATE` queries perform the same operation:
```sql
UPDATE users SET userdata::name::$first = 'Alex';
UPDATE users SET userdata = JSON_SET_STRING(userdata, 'name', 'first', 'Alex');
```
In fact, these access operators are simply convenient aliases for the `JSON_SET_` built-in function (see [JSON\_SET\_\](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-set-type.md)), and they follow all the same rules.
## Field Name Syntax for JSON Access and UPDATE Queries
In both the JSON access and update contexts, each field name must either:
* follow the syntax for a valid SQL identifier, or
* be escaped with backticks in the same manner as a SQL identifier
For example, the following two [SELECT](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/select.md) queries perform the same operation:
```sql
SELECT ticker_symbol FROM stocks WHERE statistics::%`P/E` > 1.5;
SELECT ticker_symbol FROM stocks WHERE JSON_EXTRACT_DOUBLE(statistics, 'P/E') > 1.5;
```
When using the `JSON_EXTRACT_` form of the query (see [JSON\_EXTRACT\_\](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-extract-type.md) ), there is no constraint on the contents of the keystring. A JSON object can contain any string as a key, even `""`, or a string with `"embedded\u0000nulls"`. For more information on extracting JSON data, see [JSON LOAD DATA](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/load-data/#UUID-390757f0-40b4-4d47-acec-d7c9a4c84ceb.md).
## JSON Performance
The following example will demonstrate how to improve JSON seekability by utilizing sub-segments.
Begin by turning off or disabling the variable:
```sql
SET GLOBAL use_seekable_json = OFF;
```
Create a database and change to the newly created database..
```sql
CREATE DATABASE orders;
USE orders;
```
Create a table with id as an integer and set as the primary key
```sql
CREATE TABLE orders(id INT PRIMARY KEY not null, order_doc json, sort KEY(id));
```
Create a stored procedure to generate documents until it has reached a specific number nearest to the power of two > = n.
```sql
DELIMITER //
CREATE OR REPLACE PROCEDURE gen_orders(n INT) AS
DECLARE
i INT;
c INT;
m INT;
BEGIN
DELETE FROM orders;
INSERT INTO orders
VALUES (
1,
'{
"id" : 1,
"time" : "2022-11-17 23:03:54",
"lineitems" : [
{
"line_num" : 1,
"SKU" : 688968,
"description" : "Apple iPhone 14 Plus",
"qty" : 1
},
{
"line_num" : 2,
"SKU" : 6514052,
"description" : "Energizer - MAX AA Batteries (8 Pack), Double A Alkaline Batteries",
"qty" : 3
},
{
"line_num" : 3,
"SKU" : 6457697,
"description" : "Star Wars - Galactic Snackin Grogu",
"qty" : 1
}
]
}'
);
i = 1;
WHILE i < n LOOP
SELECT MAX(id) INTO m
FROM orders;
INSERT INTO orders
SELECT
id + m,
new_order_doc(order_doc, id + m)
FROM orders;
SELECT COUNT(*) INTO c
FROM orders;
i += c;
END LOOP;
END
//
DELIMITER ;
```
Create a function that will change the input order\_doc into a new one with random data, and a new id.
```sql
DELIMITER //
CREATE OR REPLACE FUNCTION new_order_doc(order_doc JSON, new_id INT)
RETURNS JSON AS
DECLARE
j JSON;
lineitems JSON;
l1 JSON;
l2 JSON;
l3 JSON;
BEGIN
j = json_set_double(order_doc, "id", new_id);
j = json_set_string(j, "time", NOW());
lineitems = json_extract_json(j, "lineitems");
l1 = json_extract_json(lineitems, 0);
l2 = json_extract_json(lineitems, 1);
l3 = json_extract_json(lineitems, 2);
lineitems = json_array_push_json('[]', mutate_lineitem(l1));
lineitems = json_array_push_json(lineitems, mutate_lineitem(l2));
lineitems = json_array_push_json(lineitems, mutate_lineitem(l3));
j = json_set_json(j, "lineitems", lineitems);
RETURN j;
END
//
DELIMITER ;
```
Create a function to use the mutate\_lineitem.
```sql
DELIMITER //
CREATE OR REPLACE FUNCTION mutate_lineitem(item JSON)
RETURNS JSON AS
DECLARE
j JSON;
BEGIN
j = json_set_double(item, "SKU", FLOOR(RAND() * 10 * 1000 * 1000));
j = json_set_string(j, "description", UUID());
j = json_set_double(j, "qty", CEIL(3 * RAND()));
RETURN j;
END
//
DELIMITER ;
```
Generate eight million rows of test data.
```sql
CALL gen_orders(8*1024*1024);
```
Create a stored procedure that will measure the average lookup time.
```sql
DELIMITER //
DELIMITER //
CREATE OR REPLACE PROCEDURE get_avg_time(n INT) AS
DECLARE
_id INT;
_od JSON;
_oid INT;
m INT;
st DATETIME(6);
et DATETIME(6);
BEGIN
SELECT MAX(id) INTO m
FROM orders;
st = NOW(6);
FOR i IN 1..n LOOP
_oid = CEILING(m * RAND());
SELECT
id,
order_doc
INTO
_id,
_od
FROM orders
WHERE id = _oid;
END LOOP;
et = NOW(6);
ECHO
SELECT (TIMESTAMPDIFF(MICROSECOND, st, et) / 1000000.0) / n AS avg_time;
END
//
DELIMITER ;
```
Before obtaining the average query time make sure the table has been optimized and all the data is in columnstore format.
```sql
OPTIMIZE TABLE orders FULL;
```
Obtain average query time.
```sql
CALL get_avg_time(100);
```
```output
+------------+
| avg_time |
+------------+
| 1.73598285 |
+------------+
1 row in set (2 min 53.61 sec)
```
To measure the new query time, enable to variable.
```sql
SET GLOBAL use_seekable_json = ON
```
Create a second table using the same format as the first table.
```sql
CREATE TABLE orders2 LIKE orders;
```
Use the same data from the first table and make sure to optimize the new table.
```sql
INSERT INTO orders2 SELECT * FROM orders;
```
```sql
OPTIMIZE TABLE orders2 FULL;
```
Update the stored procedure `get_avg_time` by changing *orders* to *orders2* in both places.
```sql
DELIMITER //
CREATE OR REPLACE PROCEDURE get_avg_time(n INT) AS
DECLARE
_id INT;
_od JSON;
_oid INT;
m INT;
st DATETIME(6);
et DATETIME(6);
BEGIN
SELECT MAX(id) INTO m
FROM orders2;
st = NOW(6);
FOR i IN 1..n LOOP
_oid = CEILING(m * RAND());
SELECT
id,
order_doc
INTO
_id,
_od
FROM orders2
WHERE id = _oid;
END LOOP;
et = NOW(6);
ECHO
SELECT (TIMESTAMPDIFF(MICROSECOND, st, et) / 1000000.0) / n AS avg_time;
END
//
DELIMITER ;
```
Run the `get_avg_time` stored procedure again with the changed table name.
```sql
CALL get_avg_time(100);
```
```output
+------------+
| avg_time |
+------------+
| 0.03216373 |
+------------+
1 row in set (3.47 sec)
```
## JSON Array Performance
Aggregations over array objects using the `JOIN TABLE(JSON_TO_ARRAY())` operation are optimized in SingleStore to run efficiently on large batches of rows in parallel. The optimization also reduces the amount of data read from the JSON column by retrieving only the necessary data instead of fetching the entire JSON object.
The `JSON_TO_ARRAY` optimization requires the column created by the `TABLE` function (`table_col`) be wrapped in a `JSON_EXTRACT_()` function. A `JSON_EXTRACT_()` function can be used to directly extract a value as shown in Example 7 in the Introduction, or the shorthand (`::`) syntax can be used when there are keys to extract, as is shown in the following examples.
The following example uses the [TPC-H](https://www.tpc.org/tpch/) data. [Load this TPC-H data](https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/next-steps-and-examples/sample-data/load-tpc-h-data-into-singlestore.md) into your cluster, and run the following queries to modify the data for the current use case:
```sql
ALTER TABLE orders ADD COLUMN lineitems_json JSON;
CREATE TABLE new_table (
l_orderkey bigint(11) NOT NULL,
lineitems JSON
);
INSERT INTO new_table
SELECT l_orderkey,
JSON_AGG(
JSON_BUILD_OBJECT(
'l_partkey', l_partkey,
'l_suppkey', l_suppkey,
'l_linenumber', l_linenumber,
'l_quantity', l_quantity,
'l_extendedprice', l_extendedprice,
'l_discount', l_discount,
'l_tax', l_tax,
'l_returnflag', l_returnflag,
'l_linestatus', l_linestatus,
'l_shipdate', l_shipdate,
'l_commitdate', l_commitdate,
'l_receiptdate', l_receiptdate,
'l_shipinstruct', l_shipinstruct,
'l_shipmode', l_shipmode,
'l_comment', l_comment
)
) as lineitems
FROM lineitem
GROUP BY l_orderkey;
UPDATE orders o
JOIN new_table t ON o.o_orderkey = t.l_orderkey
SET o.lineitems_json = t.lineitems;
```
Here are a few sample query structures that benefit from the optimization.
* The following query calculates the total number of line items for each shipping mode by aggregating and grouping on the JSON array columns:
```sql
SELECT t.table_col::$l_shipmode, sum(t.table_col::%l_quantity) as quantity
FROM orders
JOIN TABLE(JSON_TO_ARRAY(lineitems_json)) t
GROUP BY t.table_col::$l_shipmode;
```
```output
+--------------------------+-----------+
| t.table_col::$l_shipmode | quantity |
+--------------------------+-----------+
| MAIL | 218541962 |
| FOB | 218469194 |
| RAIL | 218553230 |
| AIR | 218525124 |
| REG AIR | 218617001 |
| SHIP | 218576988 |
| TRUCK | 218454537 |
+--------------------------+-----------+
```
* The following query calculates the total number of line items for each order priority:
```sql
SELECT o_orderpriority as priority, sum(t.table_col::$l_quantity) as quantity
FROM orders JOIN TABLE(JSON_TO_ARRAY(lineitems_json)) t
GROUP BY o_orderpriority;
```
```output
+-----------------+-----------+
| priority | quantity |
+-----------------+-----------+
| 3-MEDIUM | 305731841 |
| 5-LOW | 305656541 |
| 2-HIGH | 306112515 |
| 1-URGENT | 306300507 |
| 4-NOT SPECIFIED | 305936632 |
+-----------------+-----------+
```
* The following query performs an intricate aggregation operation over multiple fields:
```sql
SELECT
t.table_col::$l_returnflag as r,
t.table_col::$l_linestatus as s,
sum(t.table_col::%l_quantity) as sum_qty,
sum(t.table_col::%l_extendedprice) as sum_base_price,
sum(t.table_col::%l_extendedprice * (1 - t.table_col::%l_discount)) as sum_disc_price,
avg(t.table_col::%l_quantity) as avg_qty
FROM orders
JOIN TABLE(JSON_TO_ARRAY(lineitems_json)) t
GROUP by r, s
```
```output
+---+---+-----------+--------------------+--------------------+--------------------+
| r | s | sum_qty | sum_base_price | sum_disc_price | avg_qty |
+---+---+-----------+--------------------+--------------------+--------------------+
| A | F | 377518399 | 566065727797.2633 | 537759104278.07465 | 25.500975103007097 |
| R | F | 377732830 | 566431054976.0034 | 538110922664.7574 | 25.50838478968014 |
| N | F | 9851614 | 14767438399.169971 | 14028805792.211407 | 25.522448302840946 |
| N | O | 764635193 | 1146548935600.9531 | 1089215873201.9531 | 25.498214140059787 |
+---+---+-----------+--------------------+--------------------+--------------------+
```
## Limitation
* The optimization is only applied to the first dimension of an array.
## Implementation Considerations
This section describes some unique behaviors in SingleStore Helios’s implementation of the JSON standard (RFC 4627).
## Infinities and NaNs
SingleStore Helios does not attempt to support entities such as the `nan` (“not a number”) entity, as in `{"value":nan}`. Although the JavaScript language supports `nan` and positive and negative infinities, neither the JSON standard nor SQL’s `DOUBLE` type provide any way to represent such non-finite values. If your application requires these special values, you might try using `null`, `0.0`, or strings (such as `"nan"` and `"inf"`) in their place.
## Unicode Support
JSON strings can contain any of the 65536 Unicode characters in the Basic Multilingual Plane (BMP), either directly as themselves or escaped with JSON’s `\uABCD` notation. JSON normalization converts all such ASCII escape sequences into UTF-8 byte sequences, except for those characters that must remain `\u`-encoded to keep the string valid JSON.
> **⚠️ Warning**: Characters outside of the Basic Multilingual Plans in JSON strings are not supported with escaped notation and may result in incorrect results.
In SingleStore, a backslash (`\`) literal in a string must be escaped with a backslash. Therefore, pattern strings containing backslashes will have two backslash characters (`\\`).
Here is an example of how to use escaped notation for characters in the BMP:
```sql
SELECT '{"a":"\\u00F9"}' :> JSON;
```
```output
+---------------------------+
| '{"a":"\\u00F9"}' :> JSON |
+---------------------------+
| {"a":"ù"} |
+---------------------------+
```
Like MySQL, SingleStore Helios supports characters outside the Basic Multilingual Plane (characters whose codepoints are in the range 0x10000 to 0x10FFFF). This includes some uncommon Chinese characters and symbols such as emojis.
The `json_collation` engine variable must be set to `utf8mb4_bin` for these characters to work. Refer to [Sync Variables Lists](https://docs.singlestore.com/cloud/reference/configuration-reference/engine-variables/list-of-engine-variables/#sync-variables-lists-2.md) for more information.
## Character Encodings and Collation
`Collation` provides a set of rules to use when comparing characters in a character set. By default, JSON columns use the collation specified in the `json_collation` engine variable ([Sync Variables Lists](https://docs.singlestore.com/cloud/reference/configuration-reference/engine-variables/list-of-engine-variables/#sync-variables-lists-3.md)). The collation of a JSON column affects the following:
* Output of `SELECT DISTINCT`, `ORDER BY`, and other queries that compare entire values.
* Identification of duplicate keys inside a single JSON object during normalization. For example, whether the string `{"Schlüssel":1,"Schluessel":2}` is normalized to `{"Schluessel":2}`.
* Sorting of keys inside a single JSON object. For example, whether the string `{"Schlüssel":1,"Schluff":2}` is normalized to `{"Schluff":2,"Schlüssel":1}`.
The default collation generally provides the desired behavior. However, you can override the default at the table or column level or by using the `json_collation` engine variable.
> **📝 Note**: SingleStore recommends that you use the `utf8mb4_bin` collation for all JSON columns.
## Table-level Override
In the following example, for the `users` table, both `userdata` and `lastname` use the table collation (which has been specified as `utf8_unicode_ci`).
```sql
CREATE TABLE users (
uid INT AUTO_INCREMENT PRIMARY KEY,
userdata JSON,
lastname AS data::name::$last PERSISTED TEXT) COLLATE=utf8_unicode_ci;
```
## Column-level Override
In the following example, for the `orders` table:
* The `data` column uses `utf8_unicode_ci`.
* The `productdetails` column uses `utf8_bin`.
* Both the `productname` column and the `comments` column use `utf8_general_ci`, which is SingleStore Helios’s default database collation
```sql
CREATE TABLE orders (
oid INT AUTO_INCREMENT PRIMARY KEY,
data JSON COLLATE utf8_unicode_ci,
productname AS data::product::$name PERSISTED TEXT,
productdetails AS data::product::$details PERSISTED TEXT COLLATE utf8_bin,
comments VARCHAR(256));
```
## Expression-level Override
The `:>` operator allows you to specify a collation for different expressions in a query.
```sql
:> text collate
```
The following example uses a binary collation (`utf8_bin`) for the first expression and a case-insensitive collation (`utf8_general_ci`) for the second expression.
```sql
SELECT *
FROM sets
WHERE sets.json_field::$x :> text collate utf8_bin = "string1"
AND sets.json_field::$y :> text collate utf8_general_ci = "string2";
```
## Maximum JSON Value Size
Under the hood, JSON data is stored in `LONGBLOB` columns. While the DDL will allow you to specify a length of up to 4GB, there is an internal limit applied when assigning a value to a string or JSON field that caps the maximum size of a single value to `max_allowed_packet`. This is 100MB by default and can be set to up to 1GB.
## Performance Impact on Parquet Encoding for JSON
When using seekable JSON/JSON Parquet encoding a major impact on performance is if a schema is dense or sparse.
A node in a tree is considered to be dense if it occurs in most JSON rows. A schema is said to be dense if most of the nodes in the entire schema are dense. Otherwise, the schema is considered to be sparse.
Consider the following JSON data table:
| JSON Data (dense) |
| ----------------------- |
| `{"a":1, "b":1}` |
| `{“a”:2, “c”:{“d”: 1}}` |
| `{“c”:{“d”:2, “e”:3}}` |
The schema will infer the JSON rows as follows:

Using the image above the leaves of the tree become internal columns in the JSON encoding. This is an example of a dense schema.
| a | b | c::d | c::e |
| ---- | ---- | ---- | ---- |
| 1 | 1 | NULL | NULL |
| 2 | NULL | 1 | NULL |
| NULL | NULL | 2 | 3 |
Using the following JSON data table:
| JSON Data (sparse) |
| ------------------ |
| `{“a”: 1}` |
| `{“b”: 1}` |
| `{“c”: 1}` |
| `{“d”: 1}` |
| `{“e”: 1}` |
The JSON rows will be encoded as follows:
| a | b | c | d | e |
| ---- | ---- | ---- | ---- | ---- |
| 1 | NULL | NULL | NULL | NULL |
| NULL | 1 | NULL | NULL | NULL |
| NULL | NULL | 1 | NULL | NULL |
| NULL | NULL | NULL | 1 | NULL |
| NULL | NULL | NULL | NULL | 1 |
The preceding table represents a sparse schema caused by the NULLs not being part of the original JSON strings. This results in poor performance since the NULLs will need to be counted which increases the execution time and memory usage.
To prevent an overly sparse schema from being inferred, SingleStore uses a method where if the average of a key’s children is too low (<1%) in relation to the key itself, the key is stored as a string without inferring its children.
## Related Topics
* See: [JSON\_AGG](https://docs.singlestore.com/cloud/reference/sql-reference/json-functions/json-agg/#section-idm4605787636892833501997993222.md)
* [JSON\_COLUMN\_SCHEMA](https://docs.singlestore.com/cloud/reference/information-schema-reference/segment-column-and-merge-status/json-column-schema.md)
* Training: [Working with JSON](https://training.singlestore.com/learn/course/internal/view/elearning/632/working-with-json-data)
***
Modified at: July 14, 2026
Source: [/cloud/create-a-database/using-json/](https://docs.singlestore.com/cloud/create-a-database/using-json/)
(An index of the documentation is available at /llms.txt)
---
# Using Persistent Computed Columns
A computed column is a column defined by an expression that uses other columns in the table. SingleStore Helios allows users to create persistent computed columns defined by an expression that combines other columns, constants, built-in functions, and operators. SingleStore Helios’s computed columns are fully materialized and can be indexed like a standard column.
There are storage and performance tradeoffs to consider when using computed columns. At a high level, computed columns are a way to optimize computationally expensive read queries that use built-in functions or require additional data processing. They allow users to precompute values that would otherwise have to be computed as part of the execution of a read query. However, computed columns also consume additional storage and require more computation on writes. Some example use cases for computed columns include:
* Parsing JSON objects for improved read performance
* Precomputing a value using an expression that includes values from other columns in the table
* Extracting values from a column, such as a year from a timestamp or a domain from a URL
* Pre-materializing common expressions in queries allowing them to be used in high-order operations, such as segment elimination or encoded `GROUP BY`s (see [Encoded Data in Columnstores](https://docs.singlestore.com/cloud/create-a-database/columnstore/encoded-data-in-columnstores.md) for more information)
* Using computed columns as sort keys, such as a timestamp type computed column (see [Optimizing Table Data Structures](https://docs.singlestore.com/cloud/create-a-database/optimizing-table-data-structures.md) for more information on sort keys)
* When filtering on a query, using computed column names isn't necessary to get faster performance. If there is an index or a shard key on the computed column, then the optimizer will match the expression in the `WHERE` clause and use the computed column to execute the query. An index on a computed column can speed up an existing query by orders of magnitude without rewriting the query. See an example below:
> **📝 Note**: It is a best practice to use large storage size data types for persistent computed columns, e.g. `BIGINT` or `LONGTEXT`. This ensures the expression result will fit into the computed column.
```sql
CREATE TABLE t (a INT, b INT, c as a + b PERSISTED BIGINT, sort key(c));
SELECT * FROM t WHERE c = ;
SELECT * FROM t WHERE a + b = ;
```
Either query is acceptable. The second query will also use column c to filter and does not have to compute a + b.
* Data type mismatch within the computed column and or parameterization of a computed column can prevent matching. Warnings will inform you if there is an issue with computed column matching:
```sql
COMPILE ;
SHOW WARNINGS;
```
```output
An example warning is:
SHOW WARNINGS;
+---------+------+---------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------------------+
| Warning | 2626 | Prospect computed column: . of type text |
| | | CHARACTER SET utf8 COLLATE utf8_general_ci NULL cannot suit expression of |
| | | type longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL. |
+---------+------+---------------------------------------------------------------------------+
1 row in set (0.00 sec)
```
In the above case, change the `column_name` type to `LONGTEXT` and the matching will work as expected.
* Using computed columns helps to maintain data independence by keeping the physical structure of data independent from application logic. For example, if your application requires data that is a combination of two or more columns within a table, a persistent computed column plus computed column matching can be used to speed up a query. This can be done without having to modify the query to refer to the computed column (a physical structure created to optimize performance) by name.
* Promoting and indexing JSON fields is the main use case of persistent computed columns. See [Using JSON](https://docs.singlestore.com/cloud/create-a-database/using-json.md) for more information.
Persistent computed columns can be created as part of a [CREATE TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-table.md) statement, or can be added later using [ALTER TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/alter-table.md).
## Computed Column Examples
The following statement creates a table `col_test` with an `INT` column `col_a` and a persistent computed column `col_b` that is defined using an expression that takes the value in `col_a` and adds `1` to it.
```sql
CREATE TABLE cal_test (col_a INT PRIMARY KEY, col_b AS col_a + 1
PERSISTED BIGINT, SORT KEY(col_b));
```
Inserting values into column `col_a` will automatically populate column `col_b` using the column definition expression.
```sql
INSERT INTO cal_test (col_a) VALUES (1), (2);
SELECT * FROM cal_test;
```
```output
+-------+-------+
| col_a | col_b |
+-------+-------+
| 2 | 3 |
| 1 | 2 |
+-------+-------+
```
It is possible to create a table with computed columns initialized using a `NOT NULL` constraint, just like a non-computed column.
```sql
CREATE TABLE cal_test (col_a int NOT NULL, col_b AS col_a+1 PERSISTED BIGINT NOT NULL);
DESC cal_test;
```
```output
+-------+---------+------+------+---------+----------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+------+---------+----------+
| col_a | int(11) | NO | | NULL | |
| col_b | int(11) | NO | | NULL | computed |
+-------+---------+------+------+---------+----------+
```
It is also possible to add a computed column to an existing table using [ALTER TABLE](https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/alter-table.md).
```sql
CREATE TABLE cal_test (col_a INT, col_b INT);
INSERT INTO cal_test (col_a, col_b) VALUES (15, 9), (45, 81);
ALTER TABLE cal_test ADD col_c AS (col_a + col_b/2) PERSISTED BIGINT;
SELECT * FROM cal_test;
```
```output
+---+-------------------+
| col_a | col_b | col_c |
+-------+-------+-------+
| 15 | 9 | 20 |
| 45 | 81 | 86 |
+-------+-------+-------+
```
```sql
DESC cal_test;
```
```output
+-------+---------+------+-----+---------+----------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------+
| col_a | int(11) | YES | | NULL | |
| col_b | int(11) | YES | | NULL | |
| col_c | int(11) | YES | | NULL | computed |
+-------+---------+------+-----+---------+----------+
```
Adding a computed column with a `NOT NULL` constraint using `ALTER TABLE` will result in an error.
```sql
ALTER TABLE cal_test ADD col_c AS (col_a + col_b/2)
PERSISTED BIGINT NOT NULL;
```
```output
ERROR 1064 ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near 'NOT NULL' at line 1
```
Attempts to insert values directly into a computed column will result in an error, even if the values are “correct” with respect to the column definition.
```sql
INSERT INTO cal_test (col_a, col_b, col_c) VALUES (3, 4, 2);
```
```output
ERROR 1822 ER_MEMSQL_COMPUTED_INSERT: Cannot insert into computed column 'col_c'
```
A computed column can be created using any expression that outputs a value that is a valid SingleStore Helios data type, composed of operators and built-in functions. For example, computed columns allow you to extract values from a JSON blob so they can be scanned and read more quickly. However, note that aggregations, user-defined functions, and non-deterministic functions such as `rand()` and `now()` cannot be used in computed columns.
```sql
SELECT * FROM j;
```
```output
+---+-------------------------------------------------+
| a | b |
+---+-------------------------------------------------+
| 1 | {"name":"Sandy Beach","occupation":"lifeguard"} |
+---+-------------------------------------------------+
```
```sql
ALTER TABLE j ADD COLUMN occupation AS b::$occupation PERSISTED LONGTEXT;
SELECT * FROM j;
```
```output
+---+-------------------------------------------------+------------+
| a | b | occupation |
+---+-------------------------------------------------+------------+
| 1 | {"name":"Sandy Beach","occupation":"lifeguard"} | lifeguard |
+---+-------------------------------------------------+------------+
```
Modifying values in a column used to define a computed column will also update the affected values in the computed column.
```sql
UPDATE j SET b::$occupation = 'circus clown';
SELECT * FROM j;
```
```output
+---+----------------------------------------------------+--------------+
| a | b | occupation |
+---+----------------------------------------------------+--------------+
| 1 | {"name":"Sandy Beach","occupation":"circus clown"} | circus clown |
+---+----------------------------------------------------+--------------+
```
## Computed Column Matching
The keyword AUTO has been added when using computed columns. This addition allows the engine to infer the type of expression used by the computed column.
Instead of using the syntax:
```sql
CREATE TABLE test_cal(col_a int, col_b AS col_a * col_a PERSISTED int);
```
Use the word `AUTO` in place of the expression type:
```sql
CREATE TABLE auto_cal(col_a int, col_b AS col_a * col_a PERSISTED AUTO);
```
This example uses the table created above and specifies the expression type.
```sql
EXPLAIN SELECT col_a, col_a*col_a FROM test_cal;
```
```output
+-------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------+
| WARNING: Computed column test_cal.col_b of type [int(11) NULL] |
| does not match similar expression's type. Consider changing the |
| computed column's type to that of the expression [bigint(21) |
| NULL] |
| Project [test_cal.col_a, test_cal.col_a * test_cal.col_a AS |
| 'col_a*col_a'] |
| |
| ColumnStoreScan ticket_test.test_cal, KEY __UNORDERED () USING |
| CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+-------------------------------------------------------------------+
```
The following uses the table created above and uses `AUTO` for the expression type.
```sql
EXPLAIN SELECT col_a, col_a*col_a FROM auto_cal;
```
```output
+-------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------+
| Project [auto_cal.col_a, auto_cal.col_b AS `col_a*col_a`] |
| ColumnStoreScan ticket_test.auto_cal, KEY __UNORDERED () USING |
| CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+-------------------------------------------------------------------+
```
Use `SHOW CREATE TABLE ` to see the persisted column expression when the expression type is specified.
```sql
SHOW CREATE TABLE test_cal;
```
```output
+-----------+------------------------------------------------------+
| Table | Create Table |
+-----------+------------------------------------------------------+
| test_cal | CREATE TABLE `test_cal` (`col_a` int(11) DEFAULT |
| | NULL,`col_b` as col_a * col_a PERSISTED int(11), |
| | KEY `__UNORDERED` () USING CLUSTERED COLUMNSTORE, |
| | SHARD KEY () )AUTOSTATS_CARDINALITY_MODE=INCREMENTAL |
| | AUTOSTATS_HISTOGRAM_MODE=CREATE AUTOSTATS_SAMPLING=ON|
| | SQL_MODE='STRICT_ALL_TABLES' |
+-----------+------------------------------------------------------+
```
Use `SHOW CREATE TABLE ` to see the persisted column and when using `AUTO`.
```sql
SHOW CREATE TABLE auto_cal;
```
```output
+-----------+------------------------------------------------------+
| Table | Create Table |
+-----------+------------------------------------------------------+
| auto_cal | CREATE TABLE `auto_cal` (`col_a` int(11) DEFAULT |
| | NULL,`col_b` as col_a * col_a PERSISTED bigint(21), |
| | KEY `__UNORDERED` () USING CLUSTERED COLUMNSTORE, |
| | SHARD KEY () )AUTOSTATS_CARDINALITY_MODE=INCREMENTAL |
| | AUTOSTATS_HISTOGRAM_MODE=CREATE AUTOSTATS_SAMPLING=ON|
| | SQL_MODE='STRICT_ALL_TABLES' |
+-----------+------------------------------------------------------+
```
> **📝 Note**: **Known Limitation**If you define a persistent computed column with `PERSISTED AUTO NOT NULL`, the `NOT NULL` constraint is not enforced. The column is created as nullable, and the `NOT NULL` constraint is silently dropped. If you need the computed column to be `NOT NULL`, specify an explicit type instead of `AUTO`. For example, using `PERSISTED DOUBLE NOT NULL` over `PERSISTED AUTO NOT NULL`.
***
Modified at: July 10, 2026
Source: [/cloud/create-a-database/using-persistent-computed-columns/](https://docs.singlestore.com/cloud/create-a-database/using-persistent-computed-columns/)
(An index of the documentation is available at /llms.txt)
---
# Developer Resources
Information developers need to know to create applications using SingleStore, from getting started, to migrating applications, to connecting with various application development languages and tools:
* Connect to application development tools such as C/C++, Java, Ruby, ODBC/JDBC, Perl, Python, and many more.
* Use SingleStore's Data API to develop custom applications and build seamless integrations with applications.
* Use `Management` API to create and manage clusters.
* View samples of concurrent multi-inserts for Bash, C, C# / .NET Core, Java, Node.js, and Python.
* Perform operations based on features like time series data analysis, full-text search, geospatial features, and window functions.
* View the [SQL command reference](https://docs.singlestore.com/cloud/reference/sql-reference/sql-command-syntax.md).
* Create custom programs such as SPs, UDFs, TVFs, and UDAFs.
## See Also
* Training: [SingleStore Helios Procedural SQL](https://training.singlestore.com/learn/course/internal/view/elearning/636/procedural-sql)
* [Procedural SQL Reference](https://docs.singlestore.com/cloud/reference/sql-reference/procedural-sql-reference.md)
* [Data API](https://docs.singlestore.com/cloud/reference/data-api.md)
## In this section
* [Try SingleStore Helios for Free](https://docs.singlestore.com/cloud/developer-resources/try-singlestore-helios-for-free.md)
* [Connect with Application Development Tools](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools.md)
* [Database Branching](https://docs.singlestore.com/cloud/developer-resources/database-branching.md)
* [Connect with Data API](https://docs.singlestore.com/cloud/developer-resources/connect-with-data-api.md)
* [Management API](https://docs.singlestore.com/cloud/developer-resources/management-api.md)
* [Porting Tables to SingleStore Helios](https://docs.singlestore.com/cloud/developer-resources/porting-tables-to-singlestore-helios.md)
* [Concurrent Multi-Insert Examples](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples.md)
* [Unsupported MySQL Features](https://docs.singlestore.com/cloud/developer-resources/unsupported-mysql-features.md)
* [Transition from MySQL to SingleStore Helios](https://docs.singlestore.com/cloud/developer-resources/transition-from-mysql-to-singlestore-helios.md)
* [Functional Extensions](https://docs.singlestore.com/cloud/developer-resources/functional-extensions.md)
* [Procedural Extensions](https://docs.singlestore.com/cloud/developer-resources/procedural-extensions.md)
* [Secrets](https://docs.singlestore.com/cloud/developer-resources/secrets.md)
* [Guides](https://docs.singlestore.com/cloud/developer-resources/guides.md)
***
Modified at: July 15, 2026
Source: [/cloud/developer-resources/](https://docs.singlestore.com/cloud/developer-resources/)
(An index of the documentation is available at /llms.txt)
---
# Concurrent Multi-Insert Examples
To perform a trickle load into SingleStore, you can run concurrent processes that each load data in batches using the `INSERT` command to insert up to several thousand rows in each statement. When loading a large volume of data, loading a row at a time is a resource-intensive and time-consuming process due to per-statement overhead, so batching is preferred.
For bulk loading into SingleStore, you can use the `LOAD DATA` command or [pipelines](https://docs.singlestore.com/cloud/load-data/about-singlestore-pipelines.md). `LOAD DATA` is preferable for a small number of files that are not extremely large, loaded in an initial step before working with the data. For very large data sets where parallel loading is important, pipelines are preferred. Moreover, pipelines can perform continuous loads as new files or messages arrive.
The following examples demonstrate how to perform concurrent multi-inserts with different tools/languages.
## In this section
* [Bash](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/bash.md)
* [C](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/c.md)
* [C# / .NET Core](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/c-net-core.md)
* [Java](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/java.md)
* [Node.js](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/node-js.md)
* [Python](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/python.md)
***
Modified at: March 14, 2023
Source: [/cloud/developer-resources/concurrent-multi-insert-examples/](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/)
(An index of the documentation is available at /llms.txt)
---
# Bash
**Dependencies**
* `singlestore` client
* Bourne-Again Shell (`bash`)
**Code**
```shell
#!/bin/bash
MHOST="127.0.0.1"
MPORT="3306"
MUSER="root"
MDB=""
NUM_WORKERS=128
BATCH_SIZE=256
memsql_exec()
{
singlestore -h $MHOST -P $MPORT -u $MUSER $MDB -e "$1"
}
memsql_exec_multi()
{
singlestore -h $MHOST -P $MPORT -u $MUSER $MDB -e \
"$(for ((b = 0; b < $BATCH_SIZE; b++)); do
echo "$1;"
done)"
}
echo "Creating database test"
memsql_exec "CREATE DATABASE IF NOT EXISTS test"
MDB="test"
echo "Creating table tbl"
memsql_exec "CREATE TABLE IF NOT EXISTS tbl (id INT AUTO_INCREMENT PRIMARY KEY)"
echo "Launching $NUM_WORKERS workers"
sleep 1
declare -a WORKERS
for ((worker = 0; worker < $NUM_WORKERS; worker++)); do
(while [ 1 ]; do
echo "Worker $worker inserting"
memsql_exec_multi "INSERT INTO tbl VALUES (NULL)"
done) &
WORKERS[$worker]=$!
done
sleep 10
for ((worker = 0; worker < $NUM_WORKERS; worker++)); do
echo "Killing worker $worker"
kill ${WORKERS[$worker]}
wait ${WORKERS[$worker]} 2>/dev/null
done
echo "Cleaning up"
sleep 1
memsql_exec "DROP DATABASE test"
```
***
Modified at: May 14, 2026
Source: [/cloud/developer-resources/concurrent-multi-insert-examples/bash/](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/bash/)
(An index of the documentation is available at /llms.txt)
---
# C# / .NET Core
**Dependencies**
* [SingleStore Connector for .NET and .NET Core](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core.md)
**Code**
```C#
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using SingleStoreConnector;
namespace SingleStoreDBTest
{
public class SingleStoreDBTest
{
/**
* Tweak the following globals to fit your environment
* ###################################################
*/
public const string HOST = "svc-3nb226d8-ee13-47f0-8ca4-2dc820773442-dml.aws-oregon-2.svc.singlestore.com";
public const int PORT = 3306;
public const string USER = "admin";
public const string PASSWORD = "passkey";
// Specify which database and table to work with.
// Note: this database will be dropped at the end of this script
public const string DATABASE = "test";
public const string TABLE = "tbl";
// The number of workers to run
public const int NUM_WORKERS = 20;
// Run the workload for this many seconds
public const int WORKLOAD_TIME = 10; // seconds
// Batch size to use
public const int BATCH_SIZE = 5000;
/**
* Internal code starts here
* #########################
*/
private IDbCommand dbCommand;
private string insertCommand;
private void GetDbCommand()
{
IDbConnection conn = new SingleStoreConnection();
conn.ConnectionString = $"Server={HOST};Port={PORT};Uid={USER};Pwd={PASSWORD};";
conn.Open();
dbCommand = conn.CreateCommand();
string[] _batch = new string[BATCH_SIZE];
Array.Fill(_batch, "(DEFAULT)");
insertCommand = $"INSERT INTO {TABLE} VALUES {string.Join(",", _batch)}";
}
private void SetupTestDb()
{
dbCommand.CommandText = $"CREATE DATABASE IF NOT EXISTS {DATABASE}";
dbCommand.ExecuteNonQuery();
dbCommand.CommandText = $"USE {DATABASE}";
dbCommand.ExecuteNonQuery();
dbCommand.CommandText = $"CREATE TABLE {TABLE} (id int primary key auto_increment)";
dbCommand.ExecuteNonQuery();
}
private void Warmup()
{
Console.WriteLine("Warming up workload");
dbCommand.CommandText = insertCommand;
dbCommand.ExecuteNonQuery(); // FRAGILE: included in count, not included in time
}
private void DoBenchmark()
{
Console.WriteLine($"Launching {NUM_WORKERS} workers for {WORKLOAD_TIME} sec");
Thread[] workers = new Thread[NUM_WORKERS];
for(int i = 0; i < NUM_WORKERS; i++)
{
workers[i] = new Thread(new ThreadStart(Worker));
workers[i].Start();
}
Console.WriteLine($"{workers.Length} workers running...");
for(int i = 0; i < NUM_WORKERS; i++)
{
workers[i].Join();
}
}
private void Worker()
{
// Create another connection per thread
using (IDbConnection conn = new SingleStoreConnection())
{
conn.ConnectionString = $"Server={HOST};Port={PORT};database={DATABASE};Uid={USER};Pwd={PASSWORD};SslMode=None;";
conn.Open();
using (IDbCommand dbCommand = conn.CreateCommand())
{
dbCommand.CommandText = insertCommand;
Stopwatch stop = new Stopwatch();
stop.Start();
while(stop.ElapsedMilliseconds < WORKLOAD_TIME*1000)
{
dbCommand.ExecuteNonQuery();
}
}
}
}
private void ShowStats()
{
dbCommand.CommandText = $"USE {DATABASE}";
dbCommand.ExecuteNonQuery();
dbCommand.CommandText = $"SELECT COUNT(*) FROM {TABLE}";
using (IDataReader reader = dbCommand.ExecuteReader())
{
long count = 0;
while(reader.Read())
{
count = (long)reader["COUNT(*)"];
}
Console.WriteLine($"{count} rows inserted using {NUM_WORKERS} workers");
Console.WriteLine($"{count / WORKLOAD_TIME} rows per second");
}
}
private void CleanupTestDb()
{
if (dbCommand != null)
{
Console.WriteLine("Cleaning up");
dbCommand.CommandText = $"USE `information_schema`";
dbCommand.ExecuteNonQuery();
dbCommand.CommandText = $"DROP DATABASE IF EXISTS {DATABASE}";
dbCommand.ExecuteNonQuery();
dbCommand = null;
}
}
public static int Main(string[] args)
{
SingleStoreDBTest tester = new SingleStoreDBTest();
try
{
tester.GetDbCommand();
tester.SetupTestDb();
tester.Warmup();
tester.DoBenchmark();
tester.ShowStats();
tester.CleanupTestDb();
return 0;
}
catch (Exception ex)
{
Console.WriteLine($"ERROR: {ex.Message}, {ex.GetType()}, {ex.StackTrace}");
try
{
tester.CleanupTestDb();
}
catch
{
// ignore error
}
return 1;
}
}
}
}
```
***
Modified at: September 7, 2023
Source: [/cloud/developer-resources/concurrent-multi-insert-examples/c-net-core/](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/c-net-core/)
(An index of the documentation is available at /llms.txt)
---
# C
**Dependencies**
* C compiler (e.g. gcc)
* `pthreads` library (present on most Linux distributions)
* `mysqlclient` library, available from the `libmysqlclient-dev` package on Debian-based distributions.
**Code**
```C
/* Compile with:
*
* cc multi_threaded_inserts.c -lmysqlclient -pthread -o mti
*/
#include
#include
#include
const static char *host = "127.0.0.1";
const static char *user = "root";
const static char *passwd = "";
const static size_t port = 3306;
#define NUM_WORKERS 20
static volatile int keep_going = 1;
void *insert_worker(void *worker_id);
int main()
{
my_init();
MYSQL conn;
mysql_init(&conn);
printf("Connecting to SingleStore Helios...\n");
if (mysql_real_connect(&conn, host, user, passwd, NULL, port, NULL, 0) != &conn)
{
printf("Could not connect to the SingleStore Helios database!\n");
goto failure;
}
printf("Creating database 'test'...\n");
if (mysql_query(&conn, "create database test") || mysql_query(&conn, "use test"))
{
printf("Could not create 'test' database!\n");
goto failure;
}
printf("Creating table 'tbl' in database 'test'...\n");
if (mysql_query(&conn, "create table tbl (id bigint auto_increment primary key)"))
{
printf("Could not create 'tbl' table in the 'test' database!\n");
goto failure;
}
printf("Launching %lu insert workers...\n", NUM_WORKERS);
pthread_t workers[NUM_WORKERS];
size_t i;
for (i = 0; i < NUM_WORKERS; ++i)
{
pthread_create(&workers[i], NULL, &insert_worker, (void *)i);
}
printf("Running inserts for %lu seconds...\n", 10);
sleep(10);
keep_going = 0;
size_t rows_inserted = 0;
for (i = 0; i < NUM_WORKERS; ++i)
{
size_t rows_i;
pthread_join(workers[i], &rows_i);
rows_inserted += rows_i;
}
printf("Inserted %lu rows. Cleaning up...\n", rows_inserted);
if (mysql_query(&conn, "drop database test"))
{
printf("Could not drop the testing database 'test'!\n");
}
mysql_close(&conn);
return 0;
failure:
mysql_close(&conn);
return 1;
}
void *insert_worker(void *worker_id)
{
size_t id = (size_t) worker_id;
MYSQL conn;
mysql_init(&conn);
if (mysql_real_connect(&conn, host, user, passwd, "test", port, NULL, 0) != &conn)
{
printf("Worker %lu could not connect to the SingleStore Helios database! Aborting...\n", id);
exit(1);
}
size_t i;
for (i = 0; keep_going; i += 8)
{
if (mysql_query(&conn, "insert into tbl values (null), (null), (null),"
"(null), (null), (null), (null), (null)"))
{
printf("Worker %lu failed to insert data, aborting...\n", id);
exit(1);
}
}
mysql_close(&conn);
return (void *)i;
}
```
***
Modified at: July 26, 2023
Source: [/cloud/developer-resources/concurrent-multi-insert-examples/c/](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/c/)
(An index of the documentation is available at /llms.txt)
---
# Java
**Dependencies**
* JDBC library (package `libmysql-java` on Debian-based distributions)
**Code**
```Java
import java.sql.*;
import java.util.Properties;
import java.util.concurrent.*;
public class Sample {
private static final String dbClassName = "com.singlestore.jdbc.Driver";
private static final String CONNECTION = "jdbc:singlestore://127.0.0.1:3306/";
private static final String USER = "root";
private static final String PASSWORD = "";
private static void executeSQL(Connection conn, String sql) throws SQLException {
try (Statement stmt = conn.createStatement()) {
stmt.execute(sql);
}
}
private static void ResetEnvironment() throws SQLException {
Properties p = new Properties();
p.put("user", USER);
p.put("password", PASSWORD);
try (Connection conn = DriverManager.getConnection(CONNECTION, p)) {
for (String query: new String[] {
"DROP DATABASE IF EXISTS test",
"CREATE DATABASE test",
"USE test",
"CREATE TABLE tbl (id INT AUTO_INCREMENT PRIMARY KEY)"
}) {
executeSQL(conn, query);
}
}
}
private static void worker() {
Properties properties = new Properties();
properties.put("user", USER);
properties.put("password", PASSWORD);
try (Connection conn = DriverManager.getConnection(CONNECTION, properties)) {
executeSQL(conn, "USE test");
while (!Thread.interrupted()) {
executeSQL(conn, "INSERT INTO tbl VALUES (NULL)");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException {
Class.forName(dbClassName);
ResetEnvironment();
ExecutorService executor = Executors.newFixedThreadPool(20);
for (int i = 0; i < 20; i++) {
executor.submit(new Runnable() {
@Override
public void run() {
worker();
}
});
}
Thread.sleep(20000);
executor.shutdownNow();
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
System.err.println("Pool did not terminate");
}
}
}
```
***
Modified at: May 18, 2026
Source: [/cloud/developer-resources/concurrent-multi-insert-examples/java/](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/java/)
(An index of the documentation is available at /llms.txt)
---
# Node.js
**Dependencies**
* [singlestore-nodejs](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js.md) dependency: run `npm install --save singlestore-nodejs`.
**Code**
```javascript
const singlestore = require("singlestore-nodejs"); // npm install --save singlestore-nodejs
const util = require('util');
/**
* Tweak the following globals to fit your environment
* ###################################################
*/
const HOST = '127.0.0.1';
const PORT = 3306;
const USER = 'root';
const PASSWORD = '';
// Specify which database and table to work with.
// Note: this database will be dropped at the end of this script
const DATABASE = 'test';
const TABLE = 'tbl';
// The number of workers to run
const NUM_WORKERS = 20;
// Run the workload for this many seconds
const WORKLOAD_TIME = 10;
// Batch size to use
const BATCH_SIZE = 5000;
/**
* Internal code starts here
* #########################
*/
let isDone = false;
// await-able setTimeout()
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Pre-generate the insert query
const _batch = new Array(BATCH_SIZE).fill().map(_ => '()').join(',');
const insertQuery = `INSERT INTO ${TABLE} VALUES ${_batch}`;;
function getConnection(dbName) {
return new Promise(function(resolve, reject) {
const conn = singlestore.createConnection({
host: HOST,
port: PORT,
user: USER,
password: PASSWORD,
database: dbName
});
conn.connect(err => {
if (err) {
reject(err);
} else {
conn.query = util.promisify(conn.query);
resolve(conn);
}
});
});
};
async function setupTestDb() {
const conn = await getConnection('information_schema');
await conn.query(`CREATE DATABASE IF NOT EXISTS ${DATABASE}`);
await conn.query(`USE ${DATABASE}`);
await conn.query(`CREATE TABLE IF NOT EXISTS ${TABLE} (id INT AUTO_INCREMENT PRIMARY KEY)`);
}
async function insertWorker() {
const conn = await getConnection(DATABASE);
while (true) {
// await will process.nextTick()
await conn.query(insertQuery);
if (isDone) {
break;
}
}
}
async function warmup() {
console.log('Warming up workload');
const conn = await getConnection(DATABASE)
await conn.query(insertQuery); // FRAGILE: included in count, not included in time
}
async function doBenchmark() {
console.log(`Launching ${NUM_WORKERS} workers for ${WORKLOAD_TIME} sec`);
const workers = [];
for (let i = 0; i < NUM_WORKERS; ++i) {
workers.push(insertWorker());
}
console.log(`${workers.length} workers running...`);
await timeout(WORKLOAD_TIME * 1000);
console.log('Stopping workload');
isDone = true;
await Promise.all(workers);
}
async function printStats() {
const conn = await getConnection(DATABASE);
const rows = await conn.query(`SELECT COUNT(*) AS count FROM ${TABLE}`);
const count = rows[0].count;
console.log(`${count} rows inserted using ${NUM_WORKERS} workers`);
console.log(`${count / WORKLOAD_TIME} rows per second`);
}
async function cleanupTestDb() {
console.log('Cleaning up');
const conn = await getConnection('information_schema');
await conn.query(`DROP DATABASE ${DATABASE}`);
}
async function main() {
try {
await setupTestDb();
await warmup();
await doBenchmark();
await printStats();
await cleanupTestDb();
} catch (err) {
console.error('ERROR', err);
try {
await cleanupTestDb();
} catch (err2) {
console.error(err2);
}
process.exit(1);
}
process.exit(0); // releases all connections
}
main();
```
***
Modified at: May 18, 2026
Source: [/cloud/developer-resources/concurrent-multi-insert-examples/node-js/](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/node-js/)
(An index of the documentation is available at /llms.txt)
---
# Python
**Dependencies**
* [SingleStore Python Client](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-using-the-singlestore-python-client.md)
**Code**
> **📝 Note**: The following script is only a proof of concept. For production purposes or loading large amounts of data, use [LOAD DATA](https://docs.singlestore.com/cloud/reference/sql-reference/data-manipulation-language-dml/load-data.md) or [pipelines](https://docs.singlestore.com/cloud/load-data/about-singlestore-pipelines.md).
```python
#!/usr/bin/env python3
import os
import sys
import time
import threading
import argparse
import singlestoredb as s2
parser = argparse.ArgumentParser()
parser.add_argument("--host", default=None, help="The hostname of the SingleStore Helios node to connect to")
parser.add_argument("--port", default=None, type=int, help="The port of the SingleStore Helios node to connect to")
parser.add_argument("--user", default="root", help="The user of the SingleStore Helios node to connect to")
parser.add_argument("--password", default="", help="The password of the SingleStore Helios node to connect to")
parser.add_argument("--database", default="simple_benchmark", help="The database to use - note: this database should not exist")
parser.add_argument("--num-workers", type=int, default=10, help="The number of insert threads")
parser.add_argument("--time", type=int, default=30, help="The number of seconds to run the benchmark for")
options = parser.parse_args()
HOST = None
PORT = None
TABLE = "tbl"
BATCH_SIZE = 5000
# Pre-generate the workload query
QUERY_TEXT = "INSERT INTO %s (val) VALUES %s" % (TABLE, ",".join(["(1)"] * BATCH_SIZE))
def get_connection(host=None, port=None, db=options.database):
""" Returns a new connection to the database. """
if host is None:
host = HOST
if port is None:
port = PORT
out = s2.connect(
host=host,
port=port,
user=options.user,
password=options.password,
database=db)
out.autocommit(True)
return out
class InsertWorker(threading.Thread):
""" A simple thread which inserts empty rows in a loop. """
def __init__(self, stopping):
super(InsertWorker, self).__init__()
self.stopping = stopping
self.daemon = True
self.exception = None
def run(self):
with get_connection() as conn:
with conn.cursor() as cur:
while not self.stopping.is_set():
cur.execute(QUERY_TEXT)
def test_connection():
try:
with get_connection(db="information_schema") as conn:
conn.is_connected()
except s2.Error:
print("Unable to connect to SingleStore Helios with provided connection details.")
print("Please verify that SingleStore Helios is running @ %s:%s" % (HOST, PORT))
sys.exit(1)
def setup_test_db():
""" Create a database and table for this benchmark to use. """
with get_connection(db="information_schema") as conn:
with conn.cursor() as cur:
print('Creating database %s' % options.database)
try:
# note: the following query will fail if there is an existing database
cur.execute('CREATE DATABASE %s' % options.database)
except s2.Error:
print("Database %s already exists - since we drop the database at" % options.database)
print("the end of this script, please specify an un-used database")
print("with the --database flag.")
sys.exit(1)
cur.execute('USE %s' % options.database)
cur.execute('CREATE TABLE IF NOT EXISTS %s (id INT AUTO_INCREMENT PRIMARY KEY, val INT)' % TABLE)
def warmup():
print('Warming up workload')
with get_connection() as conn:
with conn.cursor() as cur:
cur.execute(QUERY_TEXT)
def run_benchmark():
""" Run a set of InsertWorkers and record their performance. """
stopping = threading.Event()
workers = [ InsertWorker(stopping) for _ in range(options.num_workers) ]
print('Launching %d workers' % options.num_workers)
print('Workload will take approximately %d seconds.' % options.time)
[ worker.start() for worker in workers ]
time.sleep(options.time)
print('Stopping workload')
stopping.set()
[ worker.join() for worker in workers ]
with get_connection() as conn:
with conn.cursor() as cur:
cur.execute("SELECT COUNT(*) AS count FROM %s" % TABLE)
count = cur.fetchall()[0][0]
print("%d rows inserted using %d threads" % (count, options.num_workers))
print("%.1f rows per second" % (count / float(options.time)))
def cleanup():
""" Cleanup the database this benchmark is using. """
try:
with get_connection() as conn:
with conn.cursor() as cur:
cur.execute('DROP DATABASE IF EXISTS %s' % options.database)
except s2.Error:
pass
if __name__ == '__main__':
HOST = options.host or "127.0.0.1"
PORT = options.port or 3306
cleanup()
try:
test_connection()
setup_test_db()
warmup()
run_benchmark()
except KeyboardInterrupt:
print("Interrupted... exiting...")
```
***
Modified at: March 26, 2025
Source: [/cloud/developer-resources/concurrent-multi-insert-examples/python/](https://docs.singlestore.com/cloud/developer-resources/concurrent-multi-insert-examples/python/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Application Development Tools
SingleStore supports connecting your cluster via various application development tools and programming languages. The support level for various third-party application development tools/programming languages may differ. SingleStore provides the following levels of support:
* **GA**: SingleStore regularly tests the compatibility with this tool/language, against the latest version specified in the compatibility matrix.
* **Preview**: SingleStore may not yet support complete integration with this tool/language, and it may require independent troubleshooting.
If you face issues in connecting your SingleStore cluster with the tools/languages/frameworks specified in the following compatibility matrix, contact [SingleStore Support](https://www.singlestore.com/support/).
| Language/Framework | Connector/Driver | Status |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------- | ------- |
| [C/C++](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-c-c.md) | MariaDB Connector/C (C/C++) | Preview |
| [C#/.NET](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core.md) | SingleStoreConnector for .NET and .NET Core | GA |
| [Drizzle ORM](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js/connect-with-drizzle-orm.md) | MySQL2 | GA |
| [Django](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-with-django.md) | Django-SingleStoreConnector | Preview |
| [Go](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-go.md) | Go MySQL Driver | Preview |
| [Haystack](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-haystack.md) | SingleStoreHaystack Library | GA |
| [Hibernate](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/hibernate-singlestore-dialect.md) | SingleStoreJDBC Driver | GA |
| [Java/JDBC](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md) | SingleStoreJDBC Driver | GA |
| [LangChain](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-with-langchain.md) | LangChain-SingleStoreConnector | GA |
| [Laravel](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-laravel.md) | MySQL2 | Preview |
| [Node.js](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js.md) | MySQL | Preview |
| [ODBC](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc/the-singlestore-odbc-driver.md) | SingleStoreODBC Driver | GA |
| [Perl](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-perl.md) | MySQL DBI and DBM Drivers | Preview |
| [PHP](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-php.md) | PDO\_MySQL Driver/MySQLi | Preview |
| [Python](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-using-the-singlestore-python-client.md) | SingleStorePython Client | GA |
| [R2DBC](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-r-2-dbc.md) | SingleStoreR2DBC Connector | GA |
| [Ruby](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-ruby.md) | RubyGems MySQL2 | Preview |
| [Rust](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-rust.md) | SQLx | Preview |
| [Spring Boot](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/connect-with-spring-boot.md) | SingleStoreJDBC Driver | GA |
For information about connecting with various IDEs/environments (or any MySQL compatible client), refer to [Connect to SingleStore](https://docs.singlestore.com/cloud/connect-to-singlestore.md).
You can also connect to your cluster via the [Data API](https://docs.singlestore.com/cloud/reference/data-api.md).
## In this section
* [Connect with C/C++](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-c-c.md)
* [Connect with Go](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-go.md)
* [Connect with Haystack](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-haystack.md)
* [Connect with Java/JDBC](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc.md)
* [Connect with Laravel](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-laravel.md)
* [Connect with .NET and .NET Core](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core.md)
* [Connect with Node.js](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js.md)
* [Connect with ODBC](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc.md)
* [Connect with Perl](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-perl.md)
* [Connect with PHP](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-php.md)
* [Connect with Python](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python.md)
* [Connect with R2DBC](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-r-2-dbc.md)
* [Connect with Ruby](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-ruby.md)
* [Connect with Rust](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-rust.md)
* [Extended Protocol Packet Metadata](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/extended-protocol-packet-metadata.md)
* [Using Prepared Statements](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/using-prepared-statements.md)
***
Modified at: June 15, 2026
Source: [/cloud/developer-resources/connect-with-application-development-tools/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/)
(An index of the documentation is available at /llms.txt)
---
# Connect with C/C++
You can connect to your SingleStore database from C/C++ based applications using the MariaDB Connector (C/C++) (LGPLv2.1). [Download the MariaDB connector](https://mariadb.com/downloads/connectors/) version compatible with your operating system.
> **📝 Note**: As of MariaDB Connector/C++ version 1.1.6, connections configured with `rewriteBatchedStatements=true` may not work as expected. To perform multi-row inserts, ensure that your application generates a single SQL statement containing multiple rows.
Refer to MariaDB [Connector/C](https://mariadb.com/docs/connectors/mariadb-connector-c) and [Connector/C++](https://mariadb.com/docs/connectors/mariadb-connector-cpp) for more information.
## Examples
Update the connection configuration of your SingleStore Helios deployment before running the code.
* `endpoint`: IP address or hostname of the SingleStore deployment.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* `database`: Name of the SingleStore database to connect with.
* `username`: Username of the SingleStore database user with which to connect to SingleStore.
* `password`: Password of the SingleStore database user.
## Example: Connect using C++
This example creates a table in SingleStore, inserts data into the table, and queries the data using C++.
> **📝 Note**: The following commands may require `sudo` access (`root` privileges).
1. Install the required dependencies. This example uses a Debian-based Linux OS.
```shell
apt-get install cmake libmariadb-dev libssl-dev
```
2. Download and install the MariaDB C++ connector.
1. Clone the connector repository.
```shell
git clone https://github.com/mariadb-corporation/mariadb-connector-cpp.git
cd mariadb-connector-cpp
```
2. Build and install the connector.
```shell
cmake .
make
make install
```
The `mariadbapp` library is installed in the `/usr/local/lib` directory.
3. Add a symbolic link for `libmariadbcpp.so`.
```shell
ln -s /usr/local/lib/mariadb/libmariadbcpp.so /usr/local/lib
ldconfig
```
3. Add the following code to a **s2example.cpp** file. Update the connection configuration of your SingleStore deployment in the code.
```C++
#include
#include
int main() {
try {
// Connection details
const std::string url = "tcp://:3306/";
const std::string user = "";
const std::string password = "";
// Connect
sql::Driver* driver = sql::mariadb::get_driver_instance();
sql::SQLString connection_url(url);
sql::Properties properties({{"user", user}, {"password", password}});
std::unique_ptr conn(driver->connect(connection_url, properties));
std::unique_ptr stmt(conn->createStatement());
// Create operation
stmt->execute("CREATE TABLE IF NOT EXISTS Stock (ID INT PRIMARY KEY,Code VARCHAR(10),Quantity INT)");
// Insert operation
stmt->execute("INSERT INTO Stock (ID, Code, Quantity) VALUES (3, 'cdq3', 25)");
stmt->execute("INSERT INTO Stock (ID, Code, Quantity) VALUES (1, 'xvf1', 40)");
stmt->execute("INSERT INTO Stock (ID, Code, Quantity) VALUES (2, 'gwl2', 15)");
// Read operation
std::unique_ptr res(stmt->executeQuery("SELECT * FROM Stock ORDER BY ID"));
// Display results
while (res->next()) {
std::cout << "ID: " << res->getInt("ID")
<< ", Code: " << res->getString("Code")
<< ", Quantity: " << res->getInt("Quantity") << std::endl;
}
} catch (sql::SQLException &e) {
std::cerr << "SQL Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}
```
4. Run the following command to compile the code. Run this command in the same directory as **s2example.cpp** (or append the path to the file).
```shell
g++ s2example.cpp -o singlestore_mariadb \
-I/usr/local/include/mariadb \
-L/usr/local/lib/mariadb \
-lmariadbcpp
```
5. Run the code. Run the following command in the same directory as the **singlestore\_mariadb** file generated in the previous step.
```shell
./singlestore_mariadb
```
```output
./singlestore_mariadb
ID: 1, Code: xvf1, Quantity: 40
ID: 2, Code: gwl2, Quantity: 15
ID: 3, Code: cdq3, Quantity: 25
```
## Example: Connect with C
This example creates a table in SingleStore, inserts data into the table, and queries the data using C.
> **📝 Note**: The following commands may require `sudo` access (`root` privileges).
1. Install the MariaDB C connector. This example uses a Debian-based Linux OS.
```shell
apt-get install libmariadb-dev
```
2. Add the following code to a **s2example.c** file.
```C
#include
#include
#include
int main() {
// Connection parameters -- REPLACE these with your actual values
const char *host = "";
const char *user = "";
const char *pass = "";
const char *database = "";
unsigned int port = 3306;
MYSQL *conn = mysql_init(NULL);
// Connect to SingleStore
if (!mysql_real_connect(conn, host, user, pass, database, port, NULL, 0)) {
fprintf(stderr, "Connection error: %s\n", mysql_error(conn));
mysql_close(conn);
return 1;
}
// Create a table
const char *create_table_sql = "CREATE TABLE IF NOT EXISTS Inventory (ID INT PRIMARY KEY,Code VARCHAR(4),Quantity INT)";
if (mysql_query(conn, create_table_sql)) {
fprintf(stderr, "Create table error: %s\n", mysql_error(conn));
mysql_close(conn);
return 1;
}
// Insert data
const char *insert1 = "INSERT INTO Inventory (ID, Code, Quantity) VALUES (3, 'cdq3', 25)";
const char *insert2 = "INSERT INTO Inventory (ID, Code, Quantity) VALUES (1, 'xvf1', 40)";
const char *insert3 = "INSERT INTO Inventory (ID, Code, Quantity) VALUES (2, 'gwl2', 15)";
if (mysql_query(conn, insert1) || mysql_query(conn, insert2) || mysql_query(conn, insert3)) {
fprintf(stderr, "Insert error: %s\n", mysql_error(conn));
mysql_close(conn);
return 1;
}
// Perform SELECT query
if (mysql_query(conn, "SELECT * FROM Inventory")) {
fprintf(stderr, "SELECT error: %s\n", mysql_error(conn));
mysql_close(conn);
return 1;
}
MYSQL_RES *result = mysql_store_result(conn);
if (result == NULL) {
fprintf(stderr, "Result error: %s\n", mysql_error(conn));
mysql_close(conn);
return 1;
}
// Print results
MYSQL_ROW row;
printf("ID\tCode\tQuantity\n");
while ((row = mysql_fetch_row(result))) {
printf("%s\t%s\t%s\n", row[0], row[1], row[2]);
}
// Clean up
mysql_free_result(result);
mysql_close(conn);
return 0;
}
```
3. Compile the code. Run this command in the same directory as **s2example.c** (or append the path to the file).
```shell
gcc s2example.c -o singlestore_mariadb -lmariadb
```
4. Run the code. Run the following command in the same directory as the **singlestore\_mariadb** file generated in the previous step.
```shell
./singlestore_mariadb
```
```output
ID Code Quantity
3 cdq3 25
1 xvf1 40
2 gwl2 15
```
***
Modified at: September 26, 2025
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-c-c/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-c-c/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Go
Use the Go SingleStore driver (`go-singlestore-driver`), a Go driver for the `database/sql` driver package, to connect Go applications to SingleStore databases. This driver includes features and improvements specific to SingleStore.
Refer to the [Go-SingleStore-Driver](https://github.com/singlestore-labs/go-singlestore-driver) GitHub repository for more information on supported features and enhancements.
## Prerequisites
* [Install](https://go.dev/doc/install) the latest version of Go.
* SingleStore 8.7 or later.
* (Optional) [Install](https://git-scm.com/install/linux) `git`.
## Install the Go SingleStore Driver
Install the `go-singlestore-driver` package using the Go CLI utility:
```shell
go get -u github.com/singlestore-labs/go-singlestore-driver/v2
```
## Configure the Connection to SingleStore
Use the following connection configuration parameters in the standard MySQL DSN (Data Source Name) or other applicable methods:
* `protocol`: Network transport type used to establish the database connection, which determines how the accompanying address is interpreted. Use the `tcp` protocol for connecting with SingleStore Helios.
* `hostname`: IP address or hostname of the SingleStore cluster. Specified when the protocol is `tcp`.
Refer to [SingleStore Helios Endpoints](https://docs.singlestore.com/cloud/connect-to-singlestore/singlestore-helios-endpoints.md) to determine the endpoint (`host:port`) of your deployment.
* `port`: Port of the SingleStore cluster. The default is `3306`. Specified when the protocol is `tcp`.
* `username`: Username of the SingleStore database user.
* `password`: Password for the SingleStore database user.
* `database`: Name of the SingleStore database to connect with.
* `param=value`: (Optional) Additional connection parameters.
The driver supports the following DSN format:
```DSN
:@tcp()/[?param=value]
```
For more information on the DSN and supported parameters, refer to [DSN (Data Source Name)](https://github.com/singlestore-labs/go-singlestore-driver#dsn-data-source-name).
## Example
The following example connects to a SingleStore database and performs basic CRUD operations.
1. Create a project folder and initialize the Go module.
```shell
mkdir ssGo
cd ssGo
go mod init ssGo
```
2. Install the `go-singlestore-driver` package.
```shell
go get -u github.com/singlestore-labs/go-singlestore-driver/v2
```
3. Create a **main.go** file and add the following code to this file. Update the connection configuration of your SingleStore database in the code.
```go
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/singlestore-labs/go-singlestore-driver/v2"
)
func main() {
// Connection settings
host := "svc-xxxx"
port := "3306"
user := "s2user"
password := "p455w1kd"
database := "demo"
// SingleStore DSN
dsn := fmt.Sprintf(
"%s:%s@tcp(%s:%s)/%s?parseTime=true",
user,
password,
host,
port,
database,
)
// Open connection using the SingleStore driver
db, err := sql.Open("singlestore", dsn)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Verify connection
if err := db.Ping(); err != nil {
log.Fatal(err)
}
fmt.Println("Connected to SingleStore")
// Create table
createTableSQL := `
CREATE TABLE IF NOT EXISTS users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(255)
)
`
_, err = db.Exec(createTableSQL)
if err != nil {
log.Fatal(err)
}
fmt.Println("Table created")
// Insert rows
insertSQL := `
INSERT INTO users (name, email)
VALUES (?, ?)
`
_, err = db.Exec(insertSQL, "Alice", "alice@example.com")
if err != nil {
log.Fatal(err)
}
_, err = db.Exec(insertSQL, "Bob", "bob@example.com")
if err != nil {
log.Fatal(err)
}
fmt.Println("Rows inserted")
// Update a row
updateSQL := `
UPDATE users
SET email = ?
WHERE name = ?
`
result, err := db.Exec(updateSQL, "alice@newdomain.com", "Alice")
if err != nil {
log.Fatal(err)
}
rowsUpdated, _ := result.RowsAffected()
fmt.Printf("Rows updated: %d\n", rowsUpdated)
// Delete a row
deleteSQL := `
DELETE FROM users
WHERE name = ?
`
result, err = db.Exec(deleteSQL, "Bob")
if err != nil {
log.Fatal(err)
}
rowsDeleted, _ := result.RowsAffected()
fmt.Printf("Rows deleted: %d\n", rowsDeleted)
// Query remaining rows
rows, err := db.Query(`
SELECT id, name, email
FROM users
`)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
fmt.Println("\nRemaining users:")
for rows.Next() {
var id int
var name string
var email string
if err := rows.Scan(&id, &name, &email); err != nil {
log.Fatal(err)
}
fmt.Printf("ID=%d Name=%s Email=%s\n", id, name, email)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
}
```
4. Run the application.
```shell
go run main.go
```
```output
Connected to SingleStore
Table created
Rows inserted
Rows updated: 1
Rows deleted: 1
Remaining users:
ID=1 Name=Alice Email=alice@newdomain.com
```
## References
* [Go-SingleStore-Driver](https://github.com/singlestore-labs/go-singlestore-driver) GitHub repository
* Additional examples:
* [Getting started with SingleStore and Go](https://github.com/singlestore-labs/start-with-singlestore-go/)
* [Getting started with SingleStore stored procedures and Go](https://github.com/singlestore-labs/start-with-singlestore-go-stored-procedure)
***
Modified at: June 16, 2026
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-go/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-go/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Haystack
[Haystack](https://docs.haystack.deepset.ai/) by [Deepset](https://www.deepset.ai/) is an open-source framework for building search and retrieval-augmented generation (RAG) applications. The `singlestore-haystack` library enables you to integrate your SingleStore database as a [Document Store](https://docs.haystack.deepset.ai/docs/document-store) in Haystack to store and index documents and their metadata. Haystack retrieves these documents during queries and provides them to the Retriever for additional processing.
The `singlestore-haystack` library uses the [SingleStore Python client](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-using-the-singlestore-python-client.md) to interact with the SingleStore database. Refer to the [singlestore-haystack](https://github.com/singlestore-labs/singlestore-haystack) GitHub repository for its source code and related information.
## Install singlestore-haystack
The `singlestore-haystack` library can be installed using the standard Python package installation process:
```shell
pip install singlestore-haystack
```
## Data Storage Model
`SingleStoreDocumentStore` stores documents as rows in a SingleStore table. Vector embeddings are stored in a [VECTOR](https://docs.singlestore.com/cloud/reference/sql-reference/data-types/vector-type.md) type column in the table.
`SingleStoreDocumentStore` automatically creates the required vector and full-text indexes if they do not already exist. When using `SingleStoreEmbeddingRetriever`, documents must be embedded before they are written to the database. Use a Haystack embedder to generate these embeddings. For example, use the `SentenceTransformersDocumentEmbedder` in an indexing pipeline to generate document embeddings before storing them in SingleStore.
The following is a visual representation:

In this infographic:
* **Haystack table** is a SingleStore table used by `SingleStoreDocumentStore` to persist Haystack Document objects as rows.
* **embedding** is a property of the document, which is stored as a vector of type `VECTOR(n, F32)`.
* **content** is a property of the document.
* **vector indexes** are SingleStore vector indexes created on the embedding column to enable efficient search for dense retrieval.
* **fulltext index** is a SingleStore full-text index created on the content column to support BM25-based sparse retrieval.
* `write_documents` represents the insert operation where `SingleStoreDocumentStore` stores documents in the table.
* `retrieve_documents` represents the retrieval operations run by retrievers, such as `SingleStoreEmbeddingRetriever` (for vector search) and `SingleStoreBM25Retriever` (for full-text search).
For example, consider the following code:
```python
from haystack import Document
from haystack_integrations.document_stores.singlestore_haystack import SingleStoreDocumentStore
# Initialize the document store (uses S2_CONN_STR by default)
document_store = SingleStoreDocumentStore(
database_name="haystack_db",
table_name="haystack_documents",
embedding_dimension=384,
)
# Each Document becomes a row in the SingleStore table
documents = [
Document(
content="SingleStore is a distributed SQL database built to power intelligent applications.",
embedding=[0.1] * 384, # VECTOR(384, F32) column
meta={
"num_of_years": 3, # stored as JSON/metadata column
},
)
]
# Insert documents into SingleStore
document_store.write_documents(documents)
```
## Supported Components
This library implements the [DocumentStore protocol](https://docs.haystack.deepset.ai/docs/document-store#documentstore-protocol) methods; import the `SingleStoreDocumentStore` implementation as follows:
```python
from haystack_integrations.document_stores.singlestore_haystack import SingleStoreDocumentStore
```
In addition to `SingleStoreDocumentStore`, the `singlestore-haystack` library includes the following Haystack [Retriever](https://docs.haystack.deepset.ai/docs/retrievers) components that can be used in a pipeline:
* `SingleStoreEmbeddingRetriever`: Queries SingleStore vector index and finds semantically related documents. This component uses `SingleStoreDocumentStore` to perform vector similarity search over stored vector embeddings.
```python
from haystack_integrations.components.retrievers.singlestore_haystack import SingleStoreEmbeddingRetriever
```
* `SingleStoreBM25Retriever`: Performs sparse retrieval using the BM25 ranking algorithm. It leverages SingleStore full-text search (FTS) capabilities to retrieve documents based on keyword relevance instead of vector similarity (embeddings). This component uses `SingleStoreDocumentStore` to execute BM25 queries. SingleStore recommends using this component for keyword-based and hybrid search scenarios.
```python
from haystack_integrations.components.retrievers.singlestore_haystack import SingleStoreBM25Retriever
```
You can specify either of the following scoring functions:
* BM25
* BM25\_GLOBAL
Refer to [BM25](https://docs.singlestore.com/cloud/reference/sql-reference/full-text-search-functions/bm-25.md) for more information. For example:
```python
retriever = SingleStoreBM25Retriever(document_store=document_store)
results = retriever.run(
query="database",
top_k=2,
bm25_function="BM25",
)["documents"]
```
## Use SingleStore as a Document Store
## Prerequisites
Ensure the following are met before running examples in this section:
* An active SingleStore cluster.
* Install the `singlestore_haystack` package.
* (Optional) Install the `sentence-transformers` Python library. It provides pre-trained models used in this example to generate vector embeddings.
```python
pip install sentence-transformers
```
## Configure the Connection to SingleStore
To keep the credentials out of the source code, assign the connection string to the `S2_CONN_STR` environment variable in the following format:
```shell
export S2_CONN_STR="singlestoredb://:@:/[]"
```
where,
* `hostname`: IP address or hostname of the SingleStore cluster.
* `port`: Port of the SingleStore cluster. The default is `3306`.
* `username`: Username of the SingleStore database user.
* `password`: Password for the SingleStore database user.
* `database`: (Optional) Name of the SingleStore database to connect with.
Alternatively, specify the connection configuration while instantiating the class:
```python
document_store = SingleStoreDocumentStore(
host="",
port=,
username="",
password="",
database_name="",
table_name="" # Name of SingleStore the table used to store Documents
)
```
## Configure Indexes
`SingleStoreDocumentStore` supports creating and customizing indexes on the SingleStore table. Refer to [Working with Vector Data](https://docs.singlestore.com/cloud/developer-resources/functional-extensions/working-with-vector-data.md) for more information. Based on the retrieval strategy, enable or disable specific index types and configure the index accordingly. For example:
```python
from haystack_integrations.document_stores.singlestore_haystack import SingleStoreDocumentStore
document_store = SingleStoreDocumentStore(
database_name="haystack_db",
table_name="haystack_documents",
embedding_dimension=768,
# Enable FULLTEXT index for keyword/BM25 search
use_fulltext_index=True,
fulltext_index_options={
"analyzer": "standard",
},
# Enable vector index optimized for dot product similarity
use_dot_product_vector_index=True,
dot_product_vector_index_options={
"nlist": 128,
},
# Optionally disable Euclidean-distance index if not needed
use_euclidian_distance_vector_index=False,
)
```
Specify the following options as applicable when instantiating a `SingleStoreDocumentStore` object:
## Dot Product Optimized Vector Index
| Option | Description |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `use_dot_product_vector_index` | Creates a vector index using dot product similarity. |
| `dot_product_vector_index_options` | Specifies a dictionary that contains options for configuring the vector index that uses dot product similarity. These options are forwarded toSingleStore. Refer to[Vector Index Options](https://docs.singlestore.com/cloud/reference/sql-reference/vector-functions/vector-indexing/#section-idm457710817120003408966071884.md)for information on supported options. |
## Euclidean Distance Optimized Vector Index
| Option | Description |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `use_euclidian_distance_vector_index` | Creates a vector index using Euclidean (L2) distance similarity. |
| `euclidian_distance_vector_index_options` | Specifies a dictionary that contains additional options for configuring the vector index that uses Euclidean distance similarity. These options are forwarded toSingleStore. Refer to[Vector Index Options](https://docs.singlestore.com/cloud/reference/sql-reference/vector-functions/vector-indexing/#section-idm457710817120003408966071884.md)for information on supported options. |
## Full Text Index
> **📝 Note**: The full-text index is required for keyword-based retrieval using the `SingleStoreBM25Retriever`.
| Option | Description |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `use_fulltext_index` | Creates a full-text index (version 2). |
| `fulltext_index_options` | Specifies a dictionary that contains additional options for configuring the full-text index. These options are forwarded toSingleStore. Refer to[Working with Full-Text Search](https://docs.singlestore.com/cloud/developer-resources/functional-extensions/working-with-full-text-search.md)for information on supported options. |
## Hybrid Retrieval
To support hybrid retrieval scenarios, both vector and full-text indexes can be enabled at the same time (used together). For example, to combine dense (semantic) and sparse (keyword-based) search techniques within the same Haystack pipeline.
## Write Documents
To write documents to SingleStore, use either of the following:
* `SingleStoreDocumentStore.write_documents()` method
* [DocumentWriter](https://docs.haystack.deepset.ai/docs/documentwriter) component
## write\_documents() Example
The following example generates the embeddings using `SentenceTransformersDocumentEmbedder` and then writes the document to SingleStore.
```python
from haystack import Document
from haystack.components.embedders import SentenceTransformersDocumentEmbedder
from haystack_integrations.document_stores.singlestore_haystack import SingleStoreDocumentStore
# Initialize the document store
document_store = SingleStoreDocumentStore(
database_name="haystack_db", # SingleStore database
table_name="haystack_documents", # SingleStore table for Documents
embedding_dimension=384, # Dimension of embeddings
)
# Create documents
documents = [
Document(content="SingleStore is a distributed SQL database built to power intelligent applications.")
]
# Create the document embedder
document_embedder = SentenceTransformersDocumentEmbedder(
model="sentence-transformers/all-MiniLM-L6-v2"
)
# Download the model and prepare it (first run only)
document_embedder.warm_up()
# Generate embeddings
result = document_embedder.run(documents)
documents_with_embeddings = result["documents"]
# Write documents (with embeddings) to SingleStore
document_store.write_documents(documents_with_embeddings)
```
## DocumentWriter Example
The following example creates a Haystack pipeline to write documents to SingleStore:
```python
from haystack import Document, Pipeline
from haystack.components.embedders import SentenceTransformersDocumentEmbedder
from haystack.components.writers import DocumentWriter
from haystack_integrations.document_stores.singlestore_haystack import SingleStoreDocumentStore
# Input documents
documents = [
Document(content="SingleStore is a distributed SQL database built to power intelligent applications."),
Document(content="SingleStore is delivered as a SaaS data platform (SingleStore Helios) and is available in AWS, Azure, and GCP."),
]
# Initialize the document store
document_store = SingleStoreDocumentStore(
table_name="haystack_documents",
embedding_dimension=384,
recreate_table=True, # Recreate the table if it already exists
)
# Components
embedder = SentenceTransformersDocumentEmbedder(
model="sentence-transformers/all-MiniLM-L6-v2"
)
writer = DocumentWriter(document_store=document_store)
# Build the pipeline
pipeline = Pipeline()
pipeline.add_component(instance=embedder, name="embedder")
pipeline.add_component(instance=writer, name="writer")
pipeline.connect("embedder", "writer")
# Run the indexing pipeline
result = pipeline.run({"embedder": {"documents": documents}})
print(result) # {'writer': {'documents_written': 2}}
```
```output
`{'writer': {'documents_written': 2}}`
```
## Retrieve Documents
Use the `SingleStoreEmbeddingRetriever` component to retrieve documents from SingleStore.
For example, consider the following Haystack pipeline that finds documents using vector index and [metadata filtering](https://docs.haystack.deepset.ai/docs/metadata-filtering):
```python
from typing import List
from haystack import Document, Pipeline
from haystack.components.embedders import SentenceTransformersDocumentEmbedder, SentenceTransformersTextEmbedder
from haystack_integrations.components.retrievers.singlestore_haystack import SingleStoreEmbeddingRetriever
from haystack_integrations.document_stores.singlestore_haystack import SingleStoreDocumentStore
# Initialize the document store
document_store = SingleStoreDocumentStore(
database_name="haystack_db", # The name of the database in SingleStore
table_name="haystack_documents", # The name of the table to store Documents
embedding_dimension=384, # The dimension of the embeddings being stored
recreate_table=True,
)
# Sample documents with metadata
documents = [
Document(content="My name is Morgan and I live in Paris.", meta={"num_of_years": 3}),
Document(content="I am Susan and I live in Berlin.", meta={"num_of_years": 7}),
]
# The same model is used for both query and Document embeddings
model_name = "sentence-transformers/all-MiniLM-L6-v2"
# Embed and write documents
document_embedder = SentenceTransformersDocumentEmbedder(model=model_name)
document_embedder.warm_up()
documents_with_embeddings = document_embedder.run(documents)
document_store.write_documents(documents_with_embeddings.get("documents"))
print("Number of documents written: ", document_store.count_documents())
# Build the retrieval pipeline
pipeline = Pipeline()
pipeline.add_component("text_embedder", SentenceTransformersTextEmbedder(model=model_name))
pipeline.add_component("retriever", SingleStoreEmbeddingRetriever(document_store=document_store))
pipeline.connect("text_embedder.embedding", "retriever.query_embedding")
# Run a query with metadata filtering
result = pipeline.run(
data={
"text_embedder": {"text": "What cities do people live in?"},
"retriever": {
"top_k": 5,
"filters": {"field": "meta.num_of_years", "operator": "==", "value": 3},
},
}
)
documents: List[Document] = result["retriever"]["documents"]
print(documents)
```
```output
[Document(id=4014455c3be5d88151ba12d734a16754d7af75c691dfc3a5f364f81772471bd2, content: 'My name is Morgan and I live in Paris.', meta: {'num_of_years': 3}, score: 0.339349627494812, embedding: vector of size 384)]
```
## Examples
Refer to the [singlestore-haystack](https://github.com/singlestore-labs/singlestore-haystack?tab=readme-ov-file#more-examples) GitHub repository for more examples.
## References
* [Vector Indexing](https://docs.singlestore.com/cloud/reference/sql-reference/vector-functions/vector-indexing.md)
* [Vector Type](https://docs.singlestore.com/cloud/reference/sql-reference/data-types/vector-type.md)
* [Working with Vector Data](https://docs.singlestore.com/cloud/developer-resources/functional-extensions/working-with-vector-data.md)
* [Working with Full-Text Search](https://docs.singlestore.com/cloud/developer-resources/functional-extensions/working-with-full-text-search.md)
* [DOT\_PRODUCT](https://docs.singlestore.com/cloud/reference/sql-reference/vector-functions/dot-product.md)
* [EUCLIDEAN\_DISTANCE](https://docs.singlestore.com/cloud/reference/sql-reference/vector-functions/euclidean-distance.md)
***
Modified at: April 24, 2026
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-haystack/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-haystack/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Java/JDBC
You can connect from Java/JDBC-based applications to SingleStore using the following drivers/connectors:
* The SingleStore JDBC Driver
* MariaDB Connector/J (JDBC)
For most JDBC use cases, SingleStore recommends [The SingleStore JDBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md).
## The SingleStore JDBC Driver
The SingleStore JDBC driver is compatible with JDBC 4.2. You can use this driver to connect applications developed in Java 21, Java 17, Java 11, and Java 8 to SingleStore databases.
Refer to [The SingleStore JDBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md) for detailed information on how to install, configure, and connect using this driver.
## Hibernate SingleStore Dialect
Refer to [Hibernate SingleStore Dialect](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/hibernate-singlestore-dialect.md) for information on connecting to your SingleStore deployments from Hibernate applications using the SingleStore dialect.
## MariaDB Connector/J (JDBC) Version 2.4.0 (LGPLv2.1)
You can also use the MariaDB Connector/J v2.4.0 to connect to your SingleStore database.
> **📝 Note**: To enable/promote connector compatibility, SingleStore identifies itself as MySQL version x.x.x compatible. The compatibility version may vary depending on the SingleStore version in use.To specify a MySQL compatibility version, use the `compat_version` variable. For example,```sql
> SET GLOBAL compat_version = '5.6.4';
> ```
Refer to [Connector/J 2.4.0](https://mariadb.com/docs/release-notes/connectors/java/2.4/2.4.0) for its binary and source code.
## In this section
* [The SingleStore JDBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/the-singlestore-jdbc-driver.md)
* [Hibernate SingleStore Dialect](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/hibernate-singlestore-dialect.md)
* [Connect with Spring Boot](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/connect-with-spring-boot.md)
***
Modified at: November 7, 2025
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-java-jdbc/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Laravel
You can connect Laravel to SingleStore using the SingleStore Driver for Laravel ("the driver"). Refer to the [SingleStore Driver for Laravel](https://github.com/singlestore-labs/singlestoredb-laravel-driver) Github repository for its source code and related information.
Prerequisites
* Install [PDO\_MYSQL](https://www.php.net/manual/en/ref.pdo-mysql.php).
* Install the driver via composer:
```shell
composer require singlestoredb/singlestoredb-laravel
```
## Connect to SingleStore
To connect Laravel to SingleStore, enable the driver and configure the connection.
To enable the driver, edit your `config/database.php` file and create a new entry for SingleStore in the connection configuration. Update the `default` option to point to the new connection or set `DB_CONNECTION=singlestore` in your environment file.
Here's a sample configuration:
```php
[
'default' => env('DB_CONNECTION', 'singlestore'),
'connections' => [
'singlestore' => [
'driver' => 'singlestore',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST'),
'port' => env('DB_PORT'),
'database' => env('DB_DATABASE'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'unix_socket' => env('DB_SOCKET'),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
PDO::ATTR_EMULATE_PREPARES => true,
PDO::ATTR_PERSISTENT => true
]) : [],
],
]
]
```
The SingleStore driver is an extension of the MySQL driver, so you can also use the driver from `mysql`.
**Connect using SSL**
To configure SSL connections between SingleStore Helios and Laravel, download the `singlestore_bundle.pem` [certificate file](https://portal.singlestore.com/static/ca/singlestore_bundle.pem) and update your `MYSQL_ATTR_SSL_CA` environment variable to point to it. Set `PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT` to `"true"`, as shown below.
```php
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
PDO::ATTR_EMULATE_PREPARES => true,
PDO::ATTR_PERSISTENT => true
]) : [],
```
For more details, refer to the [SingleStore Driver for Laravel](https://github.com/singlestore-labs/singlestoredb-laravel-driver) and [Laravel docs](https://laravel.com/docs/database).
***
Modified at: June 11, 2024
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-laravel/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-laravel/)
(An index of the documentation is available at /llms.txt)
---
# Connect with .NET and .NET Core
The SingleStore Connector for .NET and .NET Core (`SingleStoreConnector`) is an ADO.NET data provider for SingleStore. It implements the following classes: `DbConnection`, `DbCommand`, `DbDataReader`, and `DbTransaction`. Refer to the [GitHub repository](https://github.com/memsql/SingleStoreNETConnector) and [SingleStoreConnector on NuGet](https://www.nuget.org/packages/SingleStoreConnector/) for more information.
This library is licensed under the MIT license.
The `SingleStoreConnector` supports .NET 10.
## Prerequisites
Download and install the latest stable version of [.NET Core](https://dotnet.microsoft.com/en-us/download).
## Install SingleStoreConnector
To install the `SingleStoreConnector` in a new project, run the following command:
```shell
dotnet add package SingleStoreConnector
```
You can also install the `SingleStoreConnector` using the NuGet Package Manager in Visual Studio. Refer to [SingleStoreConnector](https://www.nuget.org/packages/SingleStoreConnector/) on NuGet for more information.
## Configure the Connection
You need a connection string to connect your SingleStore cluster to .NET. The connection string uses the following format:
```C#
host=;port=;userid=;password=;database=;
```
Here's a sample connection string:
```C#
host=svc-xxxx-ddl.aws-oregon-2.svc.singlestore.com;port=3306;userid=s2user;password=pass23key;database=s2_dbtest;
```
Refer to [Connection String Options](https://mysqlconnector.net/connection-options/) for more options.
## Example
The following example creates a new project in Visual Studio Code and performs CRUD operations in SingleStore using C#.
Create a SingleStore cluster. For this example, we'll use the following connection string:
```C#
"Server=svc-xxxx-ddl.aws-oregon-2.svc.singlestore.com;port=3306;User ID=admin;Password=tK_,mh&Hq-EnN;Database=dbtest"
```
In Visual Studio Code, open the terminal, and create a project template:
```shell
dotnet new console -o dbTestNet
cd dbTestNet
```
Install the required dependencies, for example `SingleStoreConnector`:
```shell
dotnet add package SingleStoreConnector
```
## Create Operation Example
Add the following code to the `Program.cs` file of your project:
```C#
using SingleStoreConnector;
var connStr = "Server=svc-xxxx-ddl.aws-oregon-2.svc.singlestore.com;port=3306;User ID=admin;Password=tK_,mh&Hq-EnN;Database=dbtest";
var connection = new SingleStoreConnection(connStr);
connection.Open();
using var command = new SingleStoreCommand("CREATE TABLE testID (ID INT PRIMARY KEY, Code VARCHAR(4));INSERT INTO testID values(1, 'SamK');INSERT INTO testID values(2, 'JoeR');INSERT INTO testID values(3, 'BriA');",connection);
using var reader = command.ExecuteReader();
connection.Close();
```
In the terminal, run the following command:
```shell
dotnet run
```
On the Cloud Portal command line, execute the following command to verify that the `testID` table is created:
```sql
DESC testID;
```
```output
+-------+------------+------+------+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+------+---------+-------+
| id | int(11) | NO | UNI | NULL | |
| code | varchar(4) | YES | | NULL | |
+-------+------------+------+------+---------+-------+
```
## Read Operation Example
Add the following code to the `Program.cs` file of your project:
```C#
using SingleStoreConnector;
var connStr = "Server=svc-xxxx-ddl.aws-oregon-2.svc.singlestore.com;port=3306;User ID=admin;Password=tK_,mh&Hq-EnN;Database=dbtest";
var connection = new SingleStoreConnection(connStr);
connection.Open();
using var command = new SingleStoreCommand("SELECT * FROM testID",connection);
using var reader = command.ExecuteReader();
while (reader.Read())
{
Console.Write(reader.GetInt32(0));
Console.Write(" ");
Console.WriteLine(reader.GetString(1));
}
connection.Close();
```
In the terminal, run the following command:
```shell
dotnet run
```
```output
1 SamK
2 JoeR
3 BriA
```
## Update Operation Example
Add the following code to the `Program.cs` file of your project:
```C#
using SingleStoreConnector;
var connStr = "Server=svc-xxxx-ddl.aws-oregon-2.svc.singlestore.com;port=3306;User ID=admin;Password=tK_,mh&Hq-EnN;Database=dbtest";
var connection = new SingleStoreConnection(connStr);
connection.Open();
using var command = new SingleStoreCommand("UPDATE testID SET Code = 'BenW' WHERE ID =3;SELECT * FROM testID",connection);
using var reader = command.ExecuteReader();
while (reader.Read())
{
Console.Write(reader.GetInt32(0));
Console.Write(" ");
Console.WriteLine(reader.GetString(1));
}
connection.Close();
```
In the terminal, run the following command:
```shell
dotnet run
```
```output
1 SamK
2 JoeR
3 BenW
```
## Delete Operation Example
Add the following code to the `Program.cs` file of your project:
```C#
using SingleStoreConnector;
var connStr = "Server=svc-xxxx-ddl.aws-oregon-2.svc.singlestore.com;port=3306;User ID=admin;Password=tK_,mh&Hq-EnN;Database=dbtest";
var connection = new SingleStoreConnection(connStr);
connection.Open();
using var command = new SingleStoreCommand("DELETE FROM testID WHERE ID = 3;SELECT * FROM testID;",connection);
using var reader = command.ExecuteReader();
while (reader.Read())
{
Console.Write(reader.GetInt32(0));
Console.Write(" ");
Console.WriteLine(reader.GetString(1));
}
connection.Close();
```
In the terminal, run the following command:
```shell
dotnet run
```
```output
1 SamK
2 JoeR
```
## In this section
* [Connect using Entity Framework Core](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core/connect-using-entity-framework-core.md)
***
Modified at: July 28, 2026
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-net-and-net-core/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Node.js
Use the SingleStore Node.js driver (`singlestore-nodejs` dependency) to connect Node.js applications to SingleStore databases, whether using an ORM or straight SQL. The `singlestore-nodejs` dependency supports configuring the connection behavior, prepared statements, compression, SSL, and more.
Refer to [SingleStore-Nodejs](https://singlestore-labs.github.io/singlestore-nodejs/docs) for more information related to the driver's implementation, supported features, and usage patterns. Refer to the [SingleStore Node.js Driver](https://github.com/singlestore-labs/singlestore-nodejs) GitHub repository for its source code and related information.
To connect from Node.js to SingleStore using SSL, refer to [Connect with Node.js using SSL](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js/connect-with-node-js-using-ssl.md). SSL is required for connections to a Shared cluster.
## Install the SingleStore Node.js Driver
Install the `singlestore-nodejs` dependency to use the SingleStore Node.js driver:
```sql
npm install --save singlestore-nodejs
```
To add TypeScript type definitions, run the following command:
```sql
npm install --save-dev @types/node
```
## Configure the Connection to SingleStore
The driver supports both Promise-based and callback-based programming models for handling asynchronous operations. Use the following connection configuration parameters with the respective model to configure the connection to SingleStore:
* `hostname`: IP address or hostname of the SingleStore cluster.
* `port`: Port of the SingleStore cluster. The default is `3306`.
* `username`: Username of the SingleStore database user.
* `password`: Password for the SingleStore database user.
* `database`: (Optional) Name of the SingleStore database to connect with.
## Using Promises
```javascript
import singlestore from "singlestore-nodejs/promise";
const connection = await singlestore.createConnection({
host: "",
port: 3306,
user: "",
password: "",
database: "",
});
```
## Using Callbacks
```javascript
const singlestore = require("singlestore-nodejs");
const connection = singlestore.createConnection({
host: "",
port: 3306,
user: "",
password: "",
database: "",
});
connection.connect((err) => {
if (err) {
console.error("Connection error:", err);
return;
}
console.log("Connected to SingleStore.");
```
## Example
The following example connects to a SingleStore database and performs basic CRUD operations.
1. Create a Node.js project.
```shell
mkdir nodeJs
cd nodeJs
npm init -y
```
2. Install the `singlestore-nodejs` dependency.
```shell
npm install singlestore-nodejs
```
3. Enable ES modules. Add `"type": "module"` to `package.json`. For example:
```json
{
"name": "nodejs",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"singlestore-nodejs": "^1.0.1"
}
}
```
4. Add the following code to the `index.js` file. Update the connection configuration of your SingleStore database in the code.
```javascript
import singlestore from "singlestore-nodejs/promise";
// == Update the SingleStore database connection config) ==
const config = {
host: "svchost-xxxx",
user: "s2user",
password: "p455w1kd",
database: "dbTest",
port: 3306,
};
async function main() {
let conn;
try {
// 1. CONNECT
conn = await singlestore.createConnection(config);
console.log("Connected to SingleStore.");
// 2. CREATE TABLE
await conn.execute(`
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
)`);
console.log("Table ready.");
// 3. INSERT
const [insertResult] = await conn.execute(
"INSERT INTO users (name) VALUES (?)",
["Green"]);
console.log("Inserted ID:", insertResult.insertId);
const userId = insertResult.insertId;
// 4. READ
const [rows] = await conn.execute(
"SELECT * FROM users WHERE id = ?",
[userId]);
console.log("Read:", rows);
// 5. UPDATE
await conn.execute(
"UPDATE users SET name = ? WHERE id = ?",
["Mink", userId]);
console.log("Updated user.");
// 6. VERIFY UPDATE
const [updatedRows] = await conn.execute(
"SELECT * FROM users WHERE id = ?",
[userId]);
console.log("After update:", updatedRows);
// 7. DELETE
await conn.execute("DELETE FROM users WHERE id = ?", [userId]);
console.log("Deleted user.");
} catch (err) {
console.error("Error:", err);
} finally {
if (conn) {
await conn.end();
console.log("Connection closed."); }
}
}
main();
```
5. Run the application.
```shell
node index.js
```
```output
Connected to SingleStore.
Table ready.
Inserted ID: 1
Read: [ { id: 1, name: 'Green' } ]
Updated user.
After update: [ { id: 1, name: 'Mink' } ]
Deleted user.
Connection closed.
```
## Additional Examples
* Training: [Building a SingleStore Application Using Javascript and Node.js](https://training.singlestore.com/learn/course/internal/view/elearning/689/building-a-singlestore-application-using-javascript-and-nodejs).
* [Getting started with SingleStore stored procedures and Node.js](https://github.com/singlestore-labs/start-with-singlestore-node-stored-procedure).
* [Getting started with SingleStore and Node.js Sequelize ORM](https://github.com/singlestore-labs/start-with-singlestore-node-orm).
## References
* [SingleStore Node.js Reference ](https://singlestore-labs.github.io/singlestore-nodejs/docs)
* [singlestore-nodejs](https://github.com/singlestore-labs/singlestore-nodejs) GitHub repository
## In this section
* [Connect with Node.js using SSL](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js/connect-with-node-js-using-ssl.md)
* [Connect with Drizzle ORM](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js/connect-with-drizzle-orm.md)
***
Modified at: May 15, 2026
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-node-js/)
(An index of the documentation is available at /llms.txt)
---
# Connect with ODBC
You can connect to SingleStore from ODBC-based applications using the following drivers/connectors:
* The SingleStore ODBC Driver
* MariaDB Connector/ODBC
* MySQL Connector/ODBC
For most ODBC use cases, SingleStore recommends [The SingleStore ODBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc/the-singlestore-odbc-driver.md).
## The SingleStore ODBC Driver
You can connect to your SingleStore Helios clusters from ODBC-based applications using the SingleStore ODBC driver. It supports both Unicode and ANSI modes. You can download the SingleStore ODBC binaries from its [GitHub](https://github.com/memsql/singlestore-odbc-connector/releases/tag/v1.1.1) repository.
See [The SingleStore ODBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc/the-singlestore-odbc-driver.md) for detailed Information on how to install, configure, and connect using the driver.
## MariaDB Connector/ODBC Version 3.0.8 (LGPLv2.1)
You can use the MariaDB Connector/ODBC v3.0.8 to connect to your SingleStore Helios database.
Refer to [Connector/ODBC 3.0.8](https://mariadb.com/docs/release-notes/connectors/odbc/3.0/3.0.8) for its binary and source code.
## MySQL Connector/ODBC Version 8.0.26 (GPLv2)
You can also use the MySQL Connector/ODBC v8.0.26 to connect to your SingleStore Helios database. You can download the connector binaries for the supported operating systems from [MySQL Community Downloads](https://dev.mysql.com/downloads/connector/odbc/).
## In this section
* [The SingleStore ODBC Driver](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc/the-singlestore-odbc-driver.md)
***
Modified at: November 7, 2025
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-odbc/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Perl
SingleStore supports the basic Perl drivers for MySQL using the standard DBI and DBM drivers. You may install and configure Perl using any of the supported methods, but you must have the MySQL driver to get Perl to work with SingleStore. You can also use the [MariaDB Perl library](https://docs.singlestore.com/#section-idm4547852021628833399531792337.md).
## Install Drivers for Perl
The following example installs the Perl drivers with the [basic CPAN method](https://dev.mysql.com/doc/refman/8.0/en/perl-installation.html):
```shell
$ perl -MCPAN -e shell
cpan> install DBI
cpan> install DBD::mysql
```
This command installed the following version of DBI and DBD:
```shell
perl -MDBI -e 'print $DBI::VERSION."\n"' # 1.642
perl -MDBD::mysql -e 'print $DBD::mysql::VERSION."\n"' # 4.050
```
Here's a sample script to test connectivity using the installed drivers. The following script connects to a cluster and retrieves some basic information about the cluster.
```perl
#!/usr/bin/perl
use strict;
use DBI;
my $host = "connect("DBI:mysql:database=$database;host=$host",$user, $pw) or die "Cannot connect to MySQL server\n";
my $sql = 'select @@memsql_version';
my $sth = $dbh->prepare($sql);
$sth->execute();
while (my @row = $sth->fetchrow_array) {
print "MemSQL_Version: $row[0] \n";
}
my $sql = 'select count(*) from aggregators';
my $sth = $dbh->prepare($sql);
$sth->execute();
while (my @row = $sth->fetchrow_array) {
print "Aggregators: $row[0] \n";
}
my $sql = 'select count(*) from leaves';
my $sth = $dbh->prepare($sql);
$sth->execute();
while (my @row = $sth->fetchrow_array) {
print "Leaves $row[0] \n";
}
my $sql = 'select variable_name, variable_value from information_schema.global_status where variable_name = "uptime"';
my $sth = $dbh->prepare($sql);
$sth->execute();
while (my @row = $sth->fetchrow_array) {
#print "variable_name $row[0] variable_value $row[1]\n";
print "Cluster has been up for $row[1] seconds! \n";
}
```
Replace `ip_address_or_hostname` in the code above with the IP address or the hostname of your cluster. Here's a sample output:
```shell
$ ./show_cluster.pm
MemSQL_Version: 6.7.14 Aggregators: 1
Leaves 2
Cluster has been up for 16025 seconds!
```
## DBD-MariaDB Perl Library
SingleStore also supports the MariaDB Perl Library v1.11 (GPLv2).
| Binary | URL |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| Platform independent, includes source code | [DBD-MariaDB-1.11.tar.gz](https://cpan.metacpan.org/authors/id/P/PA/PALI/DBD-MariaDB-1.11.tar.gz) |
***
Modified at: April 7, 2023
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-perl/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-perl/)
(An index of the documentation is available at /llms.txt)
---
# Connect with PHP
You can connect to SingleStore via PHP using [PHP Data Objects (PDO)](https://www.php.net/manual/en/book.pdo.php) or [MySQLi](https://www.php.net/manual/en/book.mysqli.php).
To connect using PDO, you need to create a DSN from the host, port, and database name, and then pass the DSN to the PDO constructor along with the database username and password. For example,
> **📝 Note**: To read the connection information from the environment, use the `$_SERVER['VAR_NAME']` notation.
```php
```
To connect using MySQLi, pass the host, username, password, database name, and port to the `mysqli` constructor. For example,
```php
$link = new mysqli($_SERVER['HOSTNAME'], $_SERVER['USERNAME'], $_SERVER['PASSWORD'], $_SERVER['DB_NAME'], $_SERVER['PORT']);
```
***
Modified at: March 3, 2025
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-php/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-php/)
(An index of the documentation is available at /llms.txt)
---
# Connect with Python
For most Python use cases, SingleStore recommends using the [SingleStore Python client](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-using-the-singlestore-python-client.md). The SingleStore Python client is a Python Database API compliant database connector that supports Python version 3.9+.
This client supports the [Data API](https://docs.singlestore.com/cloud/reference/data-api.md). It also includes objects for interfacing with the [Management API](https://docs.singlestore.com/cloud/reference/management-api.md).
The [SingleStore Python Client API Reference](https://singlestoredb-python.labs.singlestore.com/api.html) lists the Python Database API objects, functions, and properties that the SingleStore Python client supports.
You can also connect to your SingleStore clusters using the following Python client/libraries:
* [SQLAlchemy](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-with-sqlalchemy.md)
* [mysqlclient](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/supported-python-libraries.md)
* [PyMySQL](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/supported-python-libraries.md)
* [MySQL Connector/Python](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/supported-python-libraries.md)
## In this section
* [Connect using the SingleStore Python Client](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-using-the-singlestore-python-client.md)
* [Connect with Django](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-with-django.md)
* [Connect with LangChain](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-with-langchain.md)
* [Connect with SQLAlchemy](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/connect-with-sqlalchemy.md)
* [Supported Python Libraries](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/supported-python-libraries.md)
***
Modified at: April 22, 2026
Source: [/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/](https://docs.singlestore.com/cloud/developer-resources/connect-with-application-development-tools/connect-with-python/)
(An index of the documentation is available at /llms.txt)
---
# Connect with R2DBC
R2DBC (Reactive Relational Database Connectivity) is a specification and set of APIs for connecting to relational databases from Java and other JVM languages. The SingleStore R2DBC connector ("the connector") is a non-blocking, asynchronous Java client that enables reactive Java applications to connect to SingleStore using the R2DBC specification. Instead of the traditional JDBC "one thread per blocking query" model, R2DBC uses asynchronous I/O and reactive streams (for example, Publisher, Flux, and Mono) to integrate seamlessly with reactive frameworks, such as [Spring WebFlux](https://docs.spring.io/spring-framework/reference/web/webflux.html) and [Project Reactor](https://projectreactor.io/docs).
## Driver Compatibility
* Java 8+ JDK
* SingleStore version 9.0+
## Install the SingleStore R2DBC Connector
To install the connector using Maven, include the following dependency in the `pom.xml` file of your project. Replace `x.x.x` with the connector version you want to use.
```xml