Skip to content

Return Objects ve Meta Data

Bu dersi tamamladıktan sonra:

  • D1Result ve D1ExecResult objelerini detaylı şekilde anlayacaksınız
  • Meta bilgilerini nasıl kullanacağınızı öğreneceksiniz
  • Monitoring ve debugging için meta data’yı nasıl kullanacağınızı kavrayacaksınız
  • Performance optimizasyonu için meta bilgilerinden nasıl faydalanacağınızı bileceksiniz
  1. D1Result Objesi
  2. D1ExecResult Objesi
  3. Meta Bilgileri Detaylı
  4. Monitoring ve Analytics
  5. Performance Optimization

interface D1Result {
success: boolean;
meta: D1ResultMeta;
results: any[] | null;
}

İşlemin başarılı olup olmadığını belirtir:

const result = await db.prepare("SELECT * FROM users").run();
if (result.success) {
console.log("Query successful!");
} else {
console.log("Query failed!");
}

Sorgu sonuçlarını içerir. SELECT işlemlerinde doludur, INSERT/UPDATE/DELETE’de boştur:

// SELECT - results doludur
const { results } = await db
.prepare("SELECT * FROM users")
.run();
console.log(results); // [{...}, {...}, ...]
// INSERT - results boştur
const { results } = await db
.prepare("INSERT INTO users (username) VALUES (?)")
.bind("newuser")
.run();
console.log(results); // null

interface D1ExecResult {
count: number;
duration: number;
}

exec() metodu D1ExecResult döner:

const result = await db.exec(`
CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT);
INSERT INTO users VALUES (1, 'ahmet');
SELECT * FROM users;
`);
console.log(result);
// {
// count: 3, // 3 işlem çalıştırıldı
// duration: 15 // Toplam 15ms
// }

const { meta } = await db.prepare("SELECT * FROM users LIMIT 1").run();
console.log(meta.served_by); // "D1" veya "miniflare.db"
console.log(meta.served_by_region); // "WEUR", "ENAM" vb.
console.log(meta.served_by_primary); // true/false
const { meta } = await db.prepare("SELECT * FROM users").run();
console.log(meta.duration); // Toplam süre (ms)
console.log(meta.sql_duration_ms); // Sadece SQL süresi (ms)
// Performans uyarısı
if (meta.duration > 1000) {
console.warn(`Slow query detected: ${meta.duration}ms`);
}
const { meta } = await db
.prepare("UPDATE users SET first_name = ? WHERE id = ?")
.bind("Updated", 1)
.run();
console.log(meta.changes); // Etkilenen row sayısı
console.log(meta.last_row_id); // Son eklenen row ID
console.log(meta.changed_db); // DB değişti mi?
if (meta.changes === 0) {
console.log("No rows were updated");
}
const { meta } = await db
.prepare("INSERT INTO posts (title) VALUES (?)")
.bind("New Post")
.run();
console.log(meta.size_after); // DB boyutu (byte)
// Storage kullanımı takibi
const sizeInMB = meta.size_after / (1024 * 1024);
console.log(`Database size: ${sizeInMB.toFixed(2)} MB`);
const { meta } = await db
.prepare("SELECT * FROM posts WHERE user_id = ?")
.bind(1)
.run();
console.log(meta.rows_read); // Okunan row sayısı
console.log(meta.rows_written); // Yazılan row sayısı
// Maliyet tahmini
const estimatedCost =
(meta.rows_read * 0.000001) +
(meta.rows_written * 0.00001);
console.log(`Estimated cost: $${estimatedCost.toFixed(6)}`);
const { meta } = await db
.prepare("SELECT * FROM users")
.run();
console.log(meta.total_attempts); // Toplam deneme
// Retry analizi
if (meta.total_attempts > 1) {
console.log(`Query was retried ${meta.total_attempts - 1} times`);
}

interface QueryMetrics {
query: string;
duration: number;
rowsRead: number;
rowsWritten: number;
timestamp: number;
}
class QueryMonitor {
private metrics: QueryMetrics[] = [];
async executeQuery(
db: D1Database,
query: string,
params: any[] = []
) {
const startTime = Date.now();
let stmt = db.prepare(query);
for (const param of params) {
stmt = stmt.bind(param);
}
const { results, meta } = await stmt.run();
const duration = Date.now() - startTime;
// Metric kaydı
this.metrics.push({
query,
duration,
rowsRead: meta.rows_read,
rowsWritten: meta.rows_written,
timestamp: Date.now(),
});
return results;
}
getSlowQueries(threshold = 1000) {
return this.metrics.filter(m => m.duration > threshold);
}
getExpensiveQueries(readThreshold = 10000, writeThreshold = 1000) {
return this.metrics.filter(m =>
m.rowsRead > readThreshold || m.rowsWritten > writeThreshold
);
}
}
// Kullanım
const monitor = new QueryMonitor();
const users = await monitor.executeQuery(
db,
"SELECT * FROM users WHERE id = ?",
[1]
);
const slowQueries = monitor.getSlowQueries();
console.log("Slow queries:", slowQueries);
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
const startTime = Date.now();
// Query çalıştır
const { results, meta } = await env.DB
.prepare("SELECT * FROM posts")
.run();
const duration = Date.now() - startTime;
// Response header'larına timing ekle
return Response.json(results, {
headers: {
'X-Query-Duration': duration.toString(),
'X-Rows-Read': meta.rows_read.toString(),
'X-Rows-Written': meta.rows_written.toString(),
'X-Served-By': meta.served_by_region,
},
});
},
};
interface DashboardMetrics {
totalQueries: number;
avgQueryDuration: number;
totalRowsRead: number;
totalRowsWritten: number;
slowQueries: number;
expensiveQueries: number;
}
class AnalyticsDashboard {
private queryHistory: Array<{
duration: number;
rowsRead: number;
rowsWritten: number;
timestamp: number;
}> = [];
recordQuery(meta: D1ResultMeta) {
this.queryHistory.push({
duration: meta.duration,
rowsRead: meta.rows_read,
rowsWritten: meta.rows_written,
timestamp: Date.now(),
});
// Son 1000 query'i tut
if (this.queryHistory.length > 1000) {
this.queryHistory.shift();
}
}
getMetrics(): DashboardMetrics {
const totalQueries = this.queryHistory.length;
const avgQueryDuration = this.queryHistory.reduce((sum, q) =>
sum + q.duration, 0) / totalQueries;
const totalRowsRead = this.queryHistory.reduce((sum, q) =>
sum + q.rowsRead, 0);
const totalRowsWritten = this.queryHistory.reduce((sum, q) =>
sum + q.rowsWritten, 0);
const slowQueries = this.queryHistory.filter(q => q.duration > 1000).length;
const expensiveQueries = this.queryHistory.filter(q =>
q.rowsRead > 10000 || q.rowsWritten > 1000).length;
return {
totalQueries,
avgQueryDuration,
totalRowsRead,
totalRowsWritten,
slowQueries,
expensiveQueries,
};
}
}

// ❌ Yavaş: Çok row okuyor
const { meta } = await db
.prepare("SELECT * FROM posts") // Tüm post'lar
.run();
console.log("Rows read:", meta.rows_read); // 100,000+
// ✅ Hızlı: Sadece gerekli row'ları okuyor
const { meta } = await db
.prepare("SELECT * FROM posts WHERE user_id = ? LIMIT 100")
.bind(userId)
.run();
console.log("Rows read:", meta.rows_read); // 100
// Slow query detection
async function executeWithMonitoring(
db: D1Database,
query: string,
params: any[] = []
) {
const { results, meta } = await db
.prepare(query)
.bind(...params)
.run();
// Slow query loglama
if (meta.duration > 500) {
console.warn(`Slow query detected:`);
console.warn(`Query: ${query}`);
console.warn(`Duration: ${meta.duration}ms`);
console.warn(`Rows read: ${meta.rows_read}`);
}
return results;
}
interface CostEstimate {
rowsRead: number;
rowsWritten: number;
estimatedCost: number;
}
function estimateCost(meta: D1ResultMeta): CostEstimate {
// D1 pricing (örnek)
const readCostPerRow = 0.000001; // $1 per million rows
const writeCostPerRow = 0.00001; // $10 per million rows
const readCost = meta.rows_read * readCostPerRow;
const writeCost = meta.rows_written * writeCostPerRow;
const totalCost = readCost + writeCost;
return {
rowsRead: meta.rows_read,
rowsWritten: meta.rows_written,
estimatedCost: totalCost,
};
}
// Kullanım
const { meta } = await db
.prepare("SELECT * FROM posts")
.run();
const cost = estimateCost(meta);
console.log(`Estimated cost: $${cost.estimatedCost.toFixed(6)}`);

class QueryLogger {
private logs: Array<{
query: string;
params: any[];
duration: number;
rowsRead: number;
rowsWritten: number;
timestamp: number;
}> = [];
async log(
db: D1Database,
query: string,
params: any[] = []
) {
const startTime = Date.now();
let stmt = db.prepare(query);
for (const param of params) {
stmt = stmt.bind(param);
}
const { results, meta } = await stmt.run();
const duration = Date.now() - startTime;
// Log kaydı
this.logs.push({
query,
params,
duration,
rowsRead: meta.rows_read,
rowsWritten: meta.rows_written,
timestamp: Date.now(),
});
// Uyarı logları
if (duration > 1000) {
console.warn(`[SLOW QUERY] ${query} took ${duration}ms`);
}
if (meta.rows_read > 10000) {
console.warn(`[HIGH ROW READ] ${query} read ${meta.rows_read} rows`);
}
return results;
}
getLogs() {
return this.logs;
}
exportLogs() {
return JSON.stringify(this.logs, null, 2);
}
}
interface PerformanceConfig {
slowQueryThreshold?: number;
highReadThreshold?: number;
logSlowQueries?: boolean;
}
export function withPerformanceMonitoring(
db: D1Database,
config: PerformanceConfig = {}
) {
const {
slowQueryThreshold = 1000,
highReadThreshold = 10000,
logSlowQueries = true,
} = config;
return {
async prepare(query: string) {
const startTime = Date.now();
// Original prepare çağrısı
const originalPrepare = db.prepare.bind(db);
const stmt = originalPrepare(query);
// Run metodunu wrap et
const originalRun = stmt.run.bind(stmt);
stmt.run = async function() {
const { results, meta } = await originalRun();
const duration = Date.now() - startTime;
// Loglama
if (logSlowQueries && duration > slowQueryThreshold) {
console.warn({
type: "SLOW_QUERY",
query,
duration,
rowsRead: meta.rows_read,
});
}
if (meta.rows_read > highReadThreshold) {
console.warn({
type: "HIGH_ROW_READ",
query,
rowsRead: meta.rows_read,
});
}
return { results, meta };
};
return stmt;
},
};
}

Bu derste aşağıdaki konuları öğrendiniz:

✅ D1Result ve D1ExecResult objeleri ✅ Meta bilgileri ve kullanım alanları ✅ Monitoring ve analytics implementasyonu ✅ Performance optimizasyonu ✅ Cost estimation ✅ Practical monitoring solutions

Bir sonraki dersimizde “SQL Statements” başlığı altında:

  • SQLite PRAGMA komutları
  • sqlite_master sorguları
  • Pattern matching
  • İleri seviye SQL özellikleri konularını inceleyeceğiz.
  1. D1Result ve D1ExecResult arasındaki fark nedir?
  2. Meta bilgileri monitoring için nasıl kullanılır?
  3. Slow query nasıl tespit edilir?
  4. Cost estimation nasıl yapılır?
  5. Performance monitoring middleware nasıl implement edilir?

Ders Süresi: 45 dakika Zorluk Seviyesi: Orta Ön Koşullar: Ders 7: Prepared Statements