技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
sap-hana-tools【数据与研究】SAP HANA developer tooling and CLI skill. Use when working with hdbsql CLI, managing HDI containers, using HANA Database Explorer, or automating HANA operations. If the user mentions hdbsql, HDI container management, HANA Cloud Central, or HANA client tools, use this skill. Extends sap-hana-cloud with operational tooling focus.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
sap-hana-cloud — HANA Cloud database development (SQL, HDI, multi-model)sap-devops-cicd — HANA artifact deployment in CI/CD pipelinessap-cap-advanced — CAP projects with HANA Cloud persistenceKey tools:
| Tool | Purpose | Install |
|---|---|---|
hdbsql | Interactive SQL client | SAP HANA Client package |
hdbuserstore | Secure credential store | SAP HANA Client package |
@sap/hdi-deploy | HDI container deployer | npm install @sap/hdi-deploy |
| HANA Database Explorer | Web-based SQL editor | BTP cockpit → HANA Cloud |
| HANA Cloud Central | Instance management | BTP cockpit |
@sap/hana-client | Node.js HANA driver | npm install @sap/hana-client |
Connect with hdbsql:
# Store credentials securely
hdbuserstore SET HANACLOUD <host>:443 <user> <password>
# Connect and run query
hdbsql -U HANACLOUD "SELECT * FROM M_DATABASE"
# Connect directly
hdbsql -n <host>:443 -u <user> -p <password> -encrypt
# HDI deploy from command line (CI/CD)
npx @sap/hdi-deploy \
--service-replacements '{"hdi-container":"my-hdi-service-key"}' \
--deploy '["src/**"]' \
--undeploy '["src/old_table.hdbtable"]'
# Environment variables for HDI deploy
export HDI_DEPLOY_OPTIONS='{"auto_undeploy":false,"treat_warnings_as_errors":true}'
| Method | Use Case | Security |
|---|---|---|
hdbuserstore | Persistent, scripted access | Encrypted local store |
| Direct params | One-off queries | Password on command line (avoid in prod) |
| JWT token | BTP app auth | Short-lived, OAuth 2.0 |
| X.509 certificate | Service-to-service | Mutual TLS |
| Service key (JSON) | BTP service binding | From BTP cockpit |
# CSV output (for data export)
hdbsql -U HANACLOUD -o output.csv -c "," -a "SELECT * FROM MY_TABLE"
# JSON output (pipe to jq)
hdbsql -U HANACLOUD -j "SELECT TOP 10 * FROM M_SQL_PLAN_CACHE ORDER BY total_execution_time DESC"
# Aligned column output (human-readable)
hdbsql -U HANACLOUD -A "SELECT * FROM M_SERVICE_MEMORY"
#!/bin/bash
# hana_health_check.sh — Daily HANA Cloud health report
STORE_KEY="HANACLOUD"
echo "=== HANA Cloud Health Check $(date) ==="
echo -e "\n--- Database Info ---"
hdbsql -U $STORE_KEY -j "SELECT DATABASE_NAME, VERSION, USAGE FROM M_DATABASE"
echo -e "\n--- Memory Usage ---"
hdbsql -U $STORE_KEY -A "
SELECT HOST,
ROUND(USED_PHYSICAL_MEMORY/1024/1024/1024, 2) AS USED_GB,
ROUND(FREE_PHYSICAL_MEMORY/1024/1024/1024, 2) AS FREE_GB,
ROUND(USED_PHYSICAL_MEMORY * 100.0 / (USED_PHYSICAL_MEMORY + FREE_PHYSICAL_MEMORY), 1) AS USED_PCT
FROM M_HOST_RESOURCE_UTILIZATION"
echo -e "\n--- Top 5 Expensive Queries (Last 24h) ---"
hdbsql -U $STORE_KEY -A "
SELECT TOP 5
SUBSTRING(STATEMENT_STRING, 1, 80) AS QUERY,
ROUND(DURATION_MICROSEC/1000000, 2) AS DURATION_SEC,
RECORDS AS ROWS_AFFECTED
FROM M_EXPENSIVE_STATEMENTS
WHERE START_TIME > ADD_SECONDS(CURRENT_TIMESTAMP, -86400)
ORDER BY DURATION_MICROSEC DESC"
echo -e "\n--- Active Connections ---"
hdbsql -U $STORE_KEY -A "
SELECT CONNECTION_STATUS, COUNT(*) AS CNT
FROM M_CONNECTIONS
GROUP BY CONNECTION_STATUS"
echo -e "\n--- Table Growth (Top 10 by size) ---"
hdbsql -U $STORE_KEY -A "
SELECT TOP 10
SCHEMA_NAME, TABLE_NAME,
ROUND(TABLE_SIZE/1024/1024, 2) AS SIZE_MB,
RECORD_COUNT
FROM M_CS_TABLES
ORDER BY TABLE_SIZE DESC"
const hana = require('@sap/hana-client');
class HANAConnection {
constructor(serviceKey) {
this.connParams = {
host: serviceKey.host,
port: serviceKey.port,
uid: serviceKey.user,
pwd: serviceKey.password,
encrypt: true,
sslValidateCertificate: true
};
}
async query(sql, params = []) {
const conn = hana.createConnection();
try {
await new Promise((resolve, reject) =>
conn.connect(this.connParams, (err) => err ? reject(err) : resolve())
);
return await new Promise((resolve, reject) =>
conn.exec(sql, params, (err, result) => err ? reject(err) : resolve(result))
);
} finally {
conn.disconnect();
}
}
async streamLargeResult(sql, params, onRow) {
const conn = hana.createConnection();
await new Promise((resolve, reject) =>
conn.connect(this.connParams, (err) => err ? reject(err) : resolve())
);
const stmt = conn.prepare(sql);
const rs = stmt.execQuery(params);
while (rs.next()) {
await onRow(rs.getValues());
}
rs.close();
stmt.drop();
conn.disconnect();
}
}
// Usage
const db = new HANAConnection(JSON.parse(process.env.HANA_SERVICE_KEY));
const results = await db.query(
'SELECT * FROM ORDERS WHERE CUSTOMER_ID = ? AND ORDER_DATE > ?',
['CUST001', '2026-01-01']
);
#!/bin/bash
# Manage HDI containers for multi-tenant scenario
SERVICE_INSTANCE="my-hdi-shared"
# List all HDI containers
cf service-keys $SERVICE_INSTANCE | grep -E "^name"
# Create tenant-specific container
create_tenant_container() {
local TENANT_ID=$1
local CONTAINER_NAME="hdi-${TENANT_ID}"
cf create-service-key $SERVICE_INSTANCE $CONTAINER_NAME \
-c "{\"permissions\":\"development\"}"
# Get connection details
cf service-key $SERVICE_INSTANCE $CONTAINER_NAME | tail -n +2 > /tmp/${CONTAINER_NAME}.json
# Deploy schema to new container
HDI_SERVICE_KEY=$(cat /tmp/${CONTAINER_NAME}.json)
npx @sap/hdi-deploy --service-replacements "[{\"key\":\"hdi-container\",\"service\":\"$HDI_SERVICE_KEY\"}]"
}
# Delete tenant container
delete_tenant_container() {
local TENANT_ID=$1
cf delete-service-key $SERVICE_INSTANCE "hdi-${TENANT_ID}" -f
}
-- Find slow queries in plan cache
SELECT TOP 20
STATEMENT_HASH,
EXECUTION_COUNT,
ROUND(TOTAL_EXECUTION_TIME/1000000, 2) AS TOTAL_SEC,
ROUND(AVG_EXECUTION_TIME/1000000, 2) AS AVG_SEC,
ROUND(MAX_EXECUTION_TIME/1000000, 2) AS MAX_SEC,
TOTAL_LOCK_WAIT_COUNT,
SUBSTR(STATEMENT_STRING, 1, 100) AS QUERY_PREVIEW
FROM M_SQL_PLAN_CACHE
WHERE EXECUTION_COUNT > 10
ORDER BY AVG_EXECUTION_TIME DESC;
-- Table column memory consumption
SELECT SCHEMA_NAME, TABLE_NAME, COLUMN_NAME,
ROUND(MEMORY_SIZE_IN_TOTAL/1024/1024, 2) AS TOTAL_MB,
ROUND(PERSISTENT_MEMORY_SIZE_IN_TOTAL/1024/1024, 2) AS DISK_MB,
LOADED AS IS_LOADED
FROM M_CS_COLUMNS
WHERE SCHEMA_NAME = 'MY_SCHEMA'
ORDER BY MEMORY_SIZE_IN_TOTAL DESC;
-- Index advisor suggestions
SELECT * FROM M_CS_INDEXES_ADVISOR
WHERE SCHEMA_NAME = 'MY_SCHEMA'
ORDER BY ESTIMATED_BENEFIT DESC;
-- Check delta merge status
SELECT SCHEMA_NAME, TABLE_NAME, PART_ID,
RAW_RECORD_COUNT_IN_DELTA AS DELTA_ROWS,
RAW_RECORD_COUNT_IN_MAIN AS MAIN_ROWS,
ROUND(RAW_RECORD_COUNT_IN_DELTA * 100.0 /
NULLIF(RAW_RECORD_COUNT_IN_MAIN + RAW_RECORD_COUNT_IN_DELTA, 0), 1) AS DELTA_PCT
FROM M_CS_TABLES
WHERE RAW_RECORD_COUNT_IN_DELTA > 100000
ORDER BY RAW_RECORD_COUNT_IN_DELTA DESC;
from hdbcli import dbapi
import json
def connect_from_service_key(key_path):
"""Connect using BTP service key JSON."""
with open(key_path) as f:
key = json.load(f)
return dbapi.connect(
address=key["host"],
port=key["port"],
user=key["user"],
password=key["password"],
encrypt=True
)
def export_to_csv(conn, sql, output_path):
"""Export query results to CSV."""
import csv
cursor = conn.cursor()
cursor.execute(sql)
columns = [desc[0] for desc in cursor.description]
with open(output_path, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(columns)
while True:
rows = cursor.fetchmany(10000)
if not rows:
break
writer.writerows(rows)
cursor.close()
def bulk_insert(conn, table_name, data, batch_size=5000):
"""Efficient bulk insert with parameterized batches."""
if not data:
return
columns = list(data[0].keys())
placeholders = ','.join(['?' for _ in columns])
sql = f"INSERT INTO {table_name} ({','.join(columns)}) VALUES ({placeholders})"
cursor = conn.cursor()
for i in range(0, len(data), batch_size):
batch = data[i:i+batch_size]
params = [tuple(row[c] for c in columns) for row in batch]
cursor.executemany(sql, params)
conn.commit()
cursor.close()
| Error | Message | Root Cause | Fix |
|---|---|---|---|
hdbsql: -10709 | Connection failed | Wrong host/port or network issue | Check host:443 (HANA Cloud always uses 443) |
hdbsql: -10104 | Invalid credentials | Wrong user/password | Reset password; check hdbuserstore entry |
hdbsql: -10 | Encryption required | Missing -encrypt flag | Add -encrypt or encrypt=true |
hdi-deploy: 403 | Insufficient privilege | Missing HDI admin role | Grant HDI container admin to technical user |
hdi-deploy: Build failed | Artifact compilation error | Invalid HDB artifact syntax | Check .hdbcds/.hdbprocedure syntax |
npm: @sap/hana-client | Install failed (native module) | Missing C++ build tools | Install node-gyp prereqs; use prebuild binary |
SQLCODE -131 | Transaction rolled back | Lock timeout during bulk insert | Reduce batch size; check for concurrent access |
SQLCODE -10001 | SQL syntax error | HANA SQL ≠ ANSI SQL | Check HANA-specific syntax (e.g., TOP N not LIMIT N) |
hdbuserstore is encrypted and reusable-B (batch mode) for non-interactive execution in CI/CD? placeholders; prevents SQL injection and enables plan reuse--deploy with specific file pathshdbsql -o with CSV format for data export instead of SELECT in app codeSELECT TOP N not LIMIT N (though recent versions support both)@sap/hana-client (native, faster) vs hdb (pure JS, slower but no native deps)UTCTOLOCAL()