guidewire-performance-tuning

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Guidewire Performance Tuning

Guidewire性能调优

Overview

概述

Optimize Guidewire InsuranceSuite performance through query optimization, efficient batch processing, caching strategies, and JVM configuration.
通过查询优化、高效批处理、缓存策略和JVM配置来优化Guidewire InsuranceSuite性能。

Prerequisites

前提条件

  • Access to Guidewire logs and metrics
  • Understanding of database query execution
  • Access to performance monitoring tools
  • 可访问Guidewire日志和指标
  • 了解数据库查询执行原理
  • 可访问性能监控工具

Performance Metrics Baseline

性能指标基准

MetricTargetCritical
Page load time< 2s> 5s
API response time (95th)< 1s> 3s
Batch job completionWithin windowExceeds window
Database query time< 100ms> 1s
Memory utilization< 80%> 95%
指标目标值临界值
页面加载时间< 2s> 5s
API响应时间(95分位)< 1s> 3s
批处理作业完成时间在窗口内超出窗口
数据库查询时间< 100ms> 1s
内存使用率< 80%> 95%

Instructions

操作步骤

Step 1: Query Optimization

步骤1:查询优化

gosu
// Query optimization patterns
package gw.performance

uses gw.api.database.Query
uses gw.api.database.Relop
uses gw.api.util.Logger

class QueryOptimization {
  private static final var LOG = Logger.forCategory("QueryOptimization")

  // BAD: Loads all data into memory
  static function getAllActivePoliciesBad() : List<Policy> {
    return Query.make(Policy).select().toList()
      .where(\p -> p.Status == PolicyStatus.TC_INFORCE)
  }

  // GOOD: Filter at database level
  static function getAllActivePoliciesGood() : List<Policy> {
    return Query.make(Policy)
      .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)
      .select()
      .toList()
  }

  // BAD: N+1 query problem
  static function getAccountsWithPoliciesBad() : Map<Account, List<Policy>> {
    var accounts = Query.make(Account).select().toList()
    return accounts.mapToValue(\account -> account.Policies.toList())  // N additional queries!
  }

  // GOOD: Eager loading with join
  static function getAccountsWithPoliciesGood() : Map<Account, List<Policy>> {
    var policies = Query.make(Policy)
      .compare(Policy#Account, IsNotNull, null)
      .select()
      .toList()

    return policies.partition(\p -> p.Account)
  }

  // Pagination for large result sets
  static function getPoliciesPaginated(pageSize : int, pageNumber : int) : List<Policy> {
    var offset = pageNumber * pageSize
    return Query.make(Policy)
      .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)
      .select()
      .orderBy(\p -> p.IssueDate)
      .skip(offset)
      .take(pageSize)
      .toList()
  }

  // Use indexes effectively
  static function findPolicyByNumber(policyNumber : String) : Policy {
    // PolicyNumber is indexed - this will be fast
    return Query.make(Policy)
      .compare(Policy#PolicyNumber, Equals, policyNumber)
      .select()
      .AtMostOneRow
  }

  // Avoid wildcard searches when possible
  // BAD: Leading wildcard prevents index use
  static function searchPoliciesBad(searchTerm : String) : List<Policy> {
    return Query.make(Policy)
      .contains(Policy#PolicyNumber, searchTerm, true)  // Contains = %term%
      .select()
      .toList()
  }

  // GOOD: Use startsWith for index-friendly search
  static function searchPoliciesGood(searchTerm : String) : List<Policy> {
    return Query.make(Policy)
      .startsWith(Policy#PolicyNumber, searchTerm, true)  // StartsWith = term%
      .select()
      .toList()
  }
}
gosu
// Query optimization patterns
package gw.performance

uses gw.api.database.Query
uses gw.api.database.Relop
uses gw.api.util.Logger

class QueryOptimization {
  private static final var LOG = Logger.forCategory("QueryOptimization")

  // BAD: Loads all data into memory
  static function getAllActivePoliciesBad() : List<Policy> {
    return Query.make(Policy).select().toList()
      .where(\p -> p.Status == PolicyStatus.TC_INFORCE)
  }

  // GOOD: Filter at database level
  static function getAllActivePoliciesGood() : List<Policy> {
    return Query.make(Policy)
      .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)
      .select()
      .toList()
  }

  // BAD: N+1 query problem
  static function getAccountsWithPoliciesBad() : Map<Account, List<Policy>> {
    var accounts = Query.make(Account).select().toList()
    return accounts.mapToValue(\account -> account.Policies.toList())  // N additional queries!
  }

  // GOOD: Eager loading with join
  static function getAccountsWithPoliciesGood() : Map<Account, List<Policy>> {
    var policies = Query.make(Policy)
      .compare(Policy#Account, IsNotNull, null)
      .select()
      .toList()

    return policies.partition(\p -> p.Account)
  }

  // Pagination for large result sets
  static function getPoliciesPaginated(pageSize : int, pageNumber : int) : List<Policy> {
    var offset = pageNumber * pageSize
    return Query.make(Policy)
      .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)
      .select()
      .orderBy(\p -> p.IssueDate)
      .skip(offset)
      .take(pageSize)
      .toList()
  }

  // Use indexes effectively
  static function findPolicyByNumber(policyNumber : String) : Policy {
    // PolicyNumber is indexed - this will be fast
    return Query.make(Policy)
      .compare(Policy#PolicyNumber, Equals, policyNumber)
      .select()
      .AtMostOneRow
  }

  // Avoid wildcard searches when possible
  // BAD: Leading wildcard prevents index use
  static function searchPoliciesBad(searchTerm : String) : List<Policy> {
    return Query.make(Policy)
      .contains(Policy#PolicyNumber, searchTerm, true)  // Contains = %term%
      .select()
      .toList()
  }

  // GOOD: Use startsWith for index-friendly search
  static function searchPoliciesGood(searchTerm : String) : List<Policy> {
    return Query.make(Policy)
      .startsWith(Policy#PolicyNumber, searchTerm, true)  // StartsWith = term%
      .select()
      .toList()
  }
}

Step 2: Batch Processing Optimization

步骤2:批处理优化

gosu
// Efficient batch processing
package gw.performance.batch

uses gw.api.util.Logger
uses gw.api.database.Query
uses gw.transaction.Transaction

class BatchProcessor {
  private static final var LOG = Logger.forCategory("BatchProcessor")
  private static final var BATCH_SIZE = 100

  // Process large datasets in batches
  static function processAllPolicies(processor(policy : Policy)) {
    var processed = 0
    var query = Query.make(Policy)
      .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)

    var iterator = query.select().iterator()
    var batch = new ArrayList<Policy>()

    while (iterator.hasNext()) {
      batch.add(iterator.next())

      if (batch.size() >= BATCH_SIZE) {
        processBatch(batch, processor)
        processed += batch.size()
        batch.clear()
        LOG.info("Processed ${processed} policies")
      }
    }

    // Process remaining items
    if (!batch.Empty) {
      processBatch(batch, processor)
      processed += batch.size()
    }

    LOG.info("Batch processing complete: ${processed} total policies")
  }

  private static function processBatch(batch : List<Policy>, processor(policy : Policy)) {
    Transaction.runWithNewBundle(\bundle -> {
      batch.each(\policy -> {
        var p = bundle.add(policy)
        processor(p)
      })
    })
  }

  // Parallel processing for independent operations
  static function processParallel<T>(
    items : List<T>,
    processor(item : T),
    threadCount : int = 4
  ) {
    var executor = java.util.concurrent.Executors.newFixedThreadPool(threadCount)

    try {
      var futures = items.map(\item -> {
        executor.submit(\-> {
          try {
            processor(item)
          } catch (e : Exception) {
            LOG.error("Processing failed for item", e)
          }
        })
      })

      // Wait for all to complete
      futures.each(\f -> f.get())
    } finally {
      executor.shutdown()
    }
  }
}
gosu
// Efficient batch processing
package gw.performance.batch

uses gw.api.util.Logger
uses gw.api.database.Query
uses gw.transaction.Transaction

class BatchProcessor {
  private static final var LOG = Logger.forCategory("BatchProcessor")
  private static final var BATCH_SIZE = 100

  // Process large datasets in batches
  static function processAllPolicies(processor(policy : Policy)) {
    var processed = 0
    var query = Query.make(Policy)
      .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)

    var iterator = query.select().iterator()
    var batch = new ArrayList<Policy>()

    while (iterator.hasNext()) {
      batch.add(iterator.next())

      if (batch.size() >= BATCH_SIZE) {
        processBatch(batch, processor)
        processed += batch.size()
        batch.clear()
        LOG.info("Processed ${processed} policies")
      }
    }

    // Process remaining items
    if (!batch.Empty) {
      processBatch(batch, processor)
      processed += batch.size()
    }

    LOG.info("Batch processing complete: ${processed} total policies")
  }

  private static function processBatch(batch : List<Policy>, processor(policy : Policy)) {
    Transaction.runWithNewBundle(\bundle -> {
      batch.each(\policy -> {
        var p = bundle.add(policy)
        processor(p)
      })
    })
  }

  // Parallel processing for independent operations
  static function processParallel<T>(
    items : List<T>,
    processor(item : T),
    threadCount : int = 4
  ) {
    var executor = java.util.concurrent.Executors.newFixedThreadPool(threadCount)

    try {
      var futures = items.map(\item -> {
        executor.submit(\-> {
          try {
            processor(item)
          } catch (e : Exception) {
            LOG.error("Processing failed for item", e)
          }
        })
      })

      // Wait for all to complete
      futures.each(\f -> f.get())
    } finally {
      executor.shutdown()
    }
  }
}

Step 3: Caching Strategies

步骤3:缓存策略

gosu
// Caching implementation
package gw.performance.cache

uses gw.api.util.Logger
uses java.util.concurrent.ConcurrentHashMap
uses java.util.concurrent.TimeUnit

class CacheManager {
  private static final var LOG = Logger.forCategory("CacheManager")
  private static var _caches = new ConcurrentHashMap<String, Cache<Object, Object>>()

  static function getCache<K, V>(name : String, ttlSeconds : int = 300) : Cache<K, V> {
    return _caches.computeIfAbsent(name, \n -> new Cache<K, V>(ttlSeconds)) as Cache<K, V>
  }

  static function clearAll() {
    _caches.values().each(\c -> c.clear())
  }
}

class Cache<K, V> {
  private var _data = new ConcurrentHashMap<K, CacheEntry<V>>()
  private var _ttlMs : long

  construct(ttlSeconds : int) {
    _ttlMs = TimeUnit.SECONDS.toMillis(ttlSeconds)
  }

  function get(key : K, loader() : V) : V {
    var entry = _data.get(key)

    if (entry != null && !entry.isExpired()) {
      return entry.Value
    }

    var value = loader()
    _data.put(key, new CacheEntry<V>(value, _ttlMs))
    return value
  }

  function invalidate(key : K) {
    _data.remove(key)
  }

  function clear() {
    _data.clear()
  }

  property get Size() : int {
    return _data.size()
  }
}

class CacheEntry<V> {
  private var _value : V
  private var _expiresAt : long

  construct(value : V, ttlMs : long) {
    _value = value
    _expiresAt = System.currentTimeMillis() + ttlMs
  }

  property get Value() : V {
    return _value
  }

  function isExpired() : boolean {
    return System.currentTimeMillis() > _expiresAt
  }
}

// Usage example: Caching product lookup
class ProductService {
  private static var _productCache = CacheManager.getCache<String, Product>("products", 3600)

  static function getProduct(code : String) : Product {
    return _productCache.get(code, \-> loadProductFromDatabase(code))
  }

  private static function loadProductFromDatabase(code : String) : Product {
    return gw.api.productmodel.ProductLookup.getByCode(code)
  }
}
gosu
// Caching implementation
package gw.performance.cache

uses gw.api.util.Logger
uses java.util.concurrent.ConcurrentHashMap
uses java.util.concurrent.TimeUnit

class CacheManager {
  private static final var LOG = Logger.forCategory("CacheManager")
  private static var _caches = new ConcurrentHashMap<String, Cache<Object, Object>>()

  static function getCache<K, V>(name : String, ttlSeconds : int = 300) : Cache<K, V> {
    return _caches.computeIfAbsent(name, \n -> new Cache<K, V>(ttlSeconds)) as Cache<K, V>
  }

  static function clearAll() {
    _caches.values().each(\c -> c.clear())
  }
}

class Cache<K, V> {
  private var _data = new ConcurrentHashMap<K, CacheEntry<V>>()
  private var _ttlMs : long

  construct(ttlSeconds : int) {
    _ttlMs = TimeUnit.SECONDS.toMillis(ttlSeconds)
  }

  function get(key : K, loader() : V) : V {
    var entry = _data.get(key)

    if (entry != null && !entry.isExpired()) {
      return entry.Value
    }

    var value = loader()
    _data.put(key, new CacheEntry<V>(value, _ttlMs))
    return value
  }

  function invalidate(key : K) {
    _data.remove(key)
  }

  function clear() {
    _data.clear()
  }

  property get Size() : int {
    return _data.size()
  }
}

class CacheEntry<V> {
  private var _value : V
  private var _expiresAt : long

  construct(value : V, ttlMs : long) {
    _value = value
    _expiresAt = System.currentTimeMillis() + ttlMs
  }

  property get Value() : V {
    return _value
  }

  function isExpired() : boolean {
    return System.currentTimeMillis() > _expiresAt
  }
}

// Usage example: Caching product lookup
class ProductService {
  private static var _productCache = CacheManager.getCache<String, Product>("products", 3600)

  static function getProduct(code : String) : Product {
    return _productCache.get(code, \-> loadProductFromDatabase(code))
  }

  private static function loadProductFromDatabase(code : String) : Product {
    return gw.api.productmodel.ProductLookup.getByCode(code)
  }
}

Step 4: Database Connection Pool Tuning

步骤4:数据库连接池调优

properties
undefined
properties
undefined

database.properties - Connection pool optimization

database.properties - Connection pool optimization

Pool size - based on concurrent users

Pool size - based on concurrent users

Formula: connections = (core_count * 2) + effective_spindle_count

Formula: connections = (core_count * 2) + effective_spindle_count

database.connection.pool.minSize=10 database.connection.pool.maxSize=50 database.connection.pool.initialSize=10
database.connection.pool.minSize=10 database.connection.pool.maxSize=50 database.connection.pool.initialSize=10

Connection validation

Connection validation

database.connection.validationQuery=SELECT 1 database.connection.testOnBorrow=true database.connection.testWhileIdle=true database.connection.timeBetweenEvictionRunsMillis=30000
database.connection.validationQuery=SELECT 1 database.connection.testOnBorrow=true database.connection.testWhileIdle=true database.connection.timeBetweenEvictionRunsMillis=30000

Statement caching

Statement caching

database.preparedStatement.cacheSize=250
database.preparedStatement.cacheSize=250

Timeout settings

Timeout settings

database.connection.timeoutMs=30000 database.query.timeoutSeconds=60
undefined
database.connection.timeoutMs=30000 database.query.timeoutSeconds=60
undefined

Step 5: JVM Tuning

步骤5:JVM调优

bash
undefined
bash
undefined

JVM options for Guidewire Cloud applications

JVM options for Guidewire Cloud applications

Production-optimized settings

Production-optimized settings

JAVA_OPTS="

Memory settings

-Xms4g -Xmx8g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g

G1 Garbage Collector (recommended for heap > 4GB)

-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m -XX:+ParallelRefProcEnabled

GC logging

-Xlog:gc*:file=/var/log/gc.log:time,uptime:filecount=5,filesize=100m

Performance flags

-XX:+UseStringDeduplication -XX:+OptimizeStringConcat -XX:+UseCompressedOops

Debugging (remove in production)

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=/var/dumps/

"
undefined
JAVA_OPTS="

Memory settings

-Xms4g -Xmx8g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g

G1 Garbage Collector (recommended for heap > 4GB)

-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m -XX:+ParallelRefProcEnabled

GC logging

-Xlog:gc*:file=/var/log/gc.log:time,uptime:filecount=5,filesize=100m

Performance flags

-XX:+UseStringDeduplication -XX:+OptimizeStringConcat -XX:+UseCompressedOops

Debugging (remove in production)

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=/var/dumps/

"
undefined

Step 6: API Response Optimization

步骤6:API响应优化

typescript
// Optimize API responses
import { LRUCache } from 'lru-cache';

interface CacheConfig {
  maxSize: number;
  ttlMs: number;
}

class OptimizedApiClient {
  private cache: LRUCache<string, any>;

  constructor(cacheConfig: CacheConfig = { maxSize: 500, ttlMs: 60000 }) {
    this.cache = new LRUCache({
      max: cacheConfig.maxSize,
      ttl: cacheConfig.ttlMs
    });
  }

  // Use field selection to reduce payload size
  async getPolicy(policyId: string, fields?: string[]): Promise<Policy> {
    const cacheKey = `policy:${policyId}:${fields?.join(',') || 'all'}`;

    const cached = this.cache.get(cacheKey);
    if (cached) return cached;

    // Only request needed fields
    const fieldParam = fields?.length
      ? `?fields=${fields.join(',')}`
      : '?fields=policyNumber,effectiveDate,totalPremium,status';

    const response = await this.client.get(`/policy/v1/policies/${policyId}${fieldParam}`);

    this.cache.set(cacheKey, response.data);
    return response.data;
  }

  // Use includes to reduce round trips
  async getAccountWithRelated(accountId: string): Promise<Account> {
    return this.client.get(
      `/account/v1/accounts/${accountId}?include=policies,contacts,locations`
    );
  }

  // Parallel requests for independent data
  async getDashboardData(accountId: string): Promise<DashboardData> {
    const [account, policies, claims, invoices] = await Promise.all([
      this.getAccount(accountId),
      this.getPolicies(accountId),
      this.getClaims(accountId),
      this.getInvoices(accountId)
    ]);

    return { account, policies, claims, invoices };
  }
}
typescript
// Optimize API responses
import { LRUCache } from 'lru-cache';

interface CacheConfig {
  maxSize: number;
  ttlMs: number;
}

class OptimizedApiClient {
  private cache: LRUCache<string, any>;

  constructor(cacheConfig: CacheConfig = { maxSize: 500, ttlMs: 60000 }) {
    this.cache = new LRUCache({
      max: cacheConfig.maxSize,
      ttl: cacheConfig.ttlMs
    });
  }

  // Use field selection to reduce payload size
  async getPolicy(policyId: string, fields?: string[]): Promise<Policy> {
    const cacheKey = `policy:${policyId}:${fields?.join(',') || 'all'}`;

    const cached = this.cache.get(cacheKey);
    if (cached) return cached;

    // Only request needed fields
    const fieldParam = fields?.length
      ? `?fields=${fields.join(',')}`
      : '?fields=policyNumber,effectiveDate,totalPremium,status';

    const response = await this.client.get(`/policy/v1/policies/${policyId}${fieldParam}`);

    this.cache.set(cacheKey, response.data);
    return response.data;
  }

  // Use includes to reduce round trips
  async getAccountWithRelated(accountId: string): Promise<Account> {
    return this.client.get(
      `/account/v1/accounts/${accountId}?include=policies,contacts,locations`
    );
  }

  // Parallel requests for independent data
  async getDashboardData(accountId: string): Promise<DashboardData> {
    const [account, policies, claims, invoices] = await Promise.all([
      this.getAccount(accountId),
      this.getPolicies(accountId),
      this.getClaims(accountId),
      this.getInvoices(accountId)
    ]);

    return { account, policies, claims, invoices };
  }
}

Step 7: Performance Monitoring

步骤7:性能监控

gosu
// Performance monitoring utilities
package gw.performance.monitor

uses gw.api.util.Logger
uses java.util.concurrent.ConcurrentHashMap
uses java.util.concurrent.atomic.AtomicLong

class PerformanceMonitor {
  private static final var LOG = Logger.forCategory("PerformanceMonitor")
  private static var _metrics = new ConcurrentHashMap<String, OperationMetrics>()

  static function time<T>(operationName : String, operation() : T) : T {
    var startTime = System.nanoTime()
    var success = true

    try {
      return operation()
    } catch (e : Exception) {
      success = false
      throw e
    } finally {
      var duration = (System.nanoTime() - startTime) / 1_000_000.0  // ms
      recordMetric(operationName, duration, success)

      if (duration > 1000) {  // Log slow operations
        LOG.warn("Slow operation: ${operationName} took ${duration}ms")
      }
    }
  }

  private static function recordMetric(name : String, durationMs : double, success : boolean) {
    var metrics = _metrics.computeIfAbsent(name, \n -> new OperationMetrics(n))
    metrics.record(durationMs, success)
  }

  static function getMetrics() : Map<String, OperationMetrics> {
    return new HashMap<String, OperationMetrics>(_metrics)
  }

  static function reset() {
    _metrics.clear()
  }
}

class OperationMetrics {
  private var _name : String
  private var _count = new AtomicLong(0)
  private var _totalMs = new AtomicLong(0)
  private var _maxMs = new AtomicLong(0)
  private var _failures = new AtomicLong(0)

  construct(name : String) {
    _name = name
  }

  function record(durationMs : double, success : boolean) {
    _count.incrementAndGet()
    _totalMs.addAndGet(durationMs as long)

    // Update max (thread-safe)
    var currentMax = _maxMs.get()
    while (durationMs > currentMax) {
      if (_maxMs.compareAndSet(currentMax, durationMs as long)) {
        break
      }
      currentMax = _maxMs.get()
    }

    if (!success) {
      _failures.incrementAndGet()
    }
  }

  property get Name() : String { return _name }
  property get Count() : long { return _count.get() }
  property get AverageMs() : double { return _totalMs.get() / Math.max(_count.get(), 1) as double }
  property get MaxMs() : long { return _maxMs.get() }
  property get FailureRate() : double { return _failures.get() / Math.max(_count.get(), 1) as double }
}
gosu
// Performance monitoring utilities
package gw.performance.monitor

uses gw.api.util.Logger
uses java.util.concurrent.ConcurrentHashMap
uses java.util.concurrent.atomic.AtomicLong

class PerformanceMonitor {
  private static final var LOG = Logger.forCategory("PerformanceMonitor")
  private static var _metrics = new ConcurrentHashMap<String, OperationMetrics>()

  static function time<T>(operationName : String, operation() : T) : T {
    var startTime = System.nanoTime()
    var success = true

    try {
      return operation()
    } catch (e : Exception) {
      success = false
      throw e
    } finally {
      var duration = (System.nanoTime() - startTime) / 1_000_000.0  // ms
      recordMetric(operationName, duration, success)

      if (duration > 1000) {  // Log slow operations
        LOG.warn("Slow operation: ${operationName} took ${duration}ms")
      }
    }
  }

  private static function recordMetric(name : String, durationMs : double, success : boolean) {
    var metrics = _metrics.computeIfAbsent(name, \n -> new OperationMetrics(n))
    metrics.record(durationMs, success)
  }

  static function getMetrics() : Map<String, OperationMetrics> {
    return new HashMap<String, OperationMetrics>(_metrics)
  }

  static function reset() {
    _metrics.clear()
  }
}

class OperationMetrics {
  private var _name : String
  private var _count = new AtomicLong(0)
  private var _totalMs = new AtomicLong(0)
  private var _maxMs = new AtomicLong(0)
  private var _failures = new AtomicLong(0)

  construct(name : String) {
    _name = name
  }

  function record(durationMs : double, success : boolean) {
    _count.incrementAndGet()
    _totalMs.addAndGet(durationMs as long)

    // Update max (thread-safe)
    var currentMax = _maxMs.get()
    while (durationMs > currentMax) {
      if (_maxMs.compareAndSet(currentMax, durationMs as long)) {
        break
      }
      currentMax = _maxMs.get()
    }

    if (!success) {
      _failures.incrementAndGet()
    }
  }

  property get Name() : String { return _name }
  property get Count() : long { return _count.get() }
  property get AverageMs() : double { return _totalMs.get() / Math.max(_count.get(), 1) as double }
  property get MaxMs() : long { return _maxMs.get() }
  property get FailureRate() : double { return _failures.get() / Math.max(_count.get(), 1) as double }
}

Performance Checklist

性能检查清单

AreaCheckStatus
QueriesAll queries use indexes[ ]
QueriesNo N+1 query patterns[ ]
QueriesLarge results paginated[ ]
BatchAppropriate batch sizes[ ]
BatchWithin maintenance windows[ ]
CachingFrequently accessed data cached[ ]
CachingCache invalidation implemented[ ]
JVMMemory settings optimized[ ]
JVMGC logs analyzed[ ]
领域检查项状态
查询所有查询均使用索引[ ]
查询无N+1查询问题[ ]
查询大结果集已分页[ ]
批处理批处理大小设置合理[ ]
批处理在维护窗口内完成[ ]
缓存频繁访问数据已缓存[ ]
缓存已实现缓存失效机制[ ]
JVM内存设置已优化[ ]
JVM已分析GC日志[ ]

Output

输出成果

  • Optimized query patterns
  • Batch processing implementation
  • Caching layer configuration
  • JVM tuning parameters
  • Performance monitoring
  • 优化后的查询模式
  • 批处理实现方案
  • 缓存层配置
  • JVM调优参数
  • 性能监控工具

Resources

参考资源

Next Steps

后续步骤

For cost optimization, see
guidewire-cost-tuning
.
如需成本优化,请查看
guidewire-cost-tuning