← 中文资源

简体中文版本

连接池饱和

连接池饱和指池内连接全部被占用、新请求排队等待获取;排队等待时间上升才是症状,查询本身可能并不慢。

阅读英文原文

概念定义

连接池把建连成本转化为可复用容量。饱和就是容量被全部持有:新请求阻塞在获取上。用户可见延迟等于排队等待加执行,而早在任何人察觉查询变慢之前,排队就已主导延迟。

工作机制

池指标区分活跃、空闲与等待线程。数据库 CPU 低却饱和,说明持有者慢或卡死;CPU 高才说明数据库是真瓶颈。Little 定律式的推理用核数与等待比例限定有效池大小——过大的池只增加争用不增加吞吐。

使用场景

干预手段:给队列设上限、设置快速失败的获取超时、给查询本身强制超时;收紧事务范围,让连接只为数据库工作而持有;在池之前而非之后做负载丢弃。

常见误区

饱和不代表数据库过载——它可能完全空闲,只是连接被慢持有者钉住。加大池子只是把问题掩盖到数据库自身限制成为瓶颈。对饱和池发起的重试风暴会指数级放大队列压力;健康检查若也抢连接,饱和会杀死存活探针并级联重启。获取时间应作为独立指标监控,均值会掩盖“瞬间成功”与“排队”的双峰分布。

代码示例

const DIVISIONS = [
  { unit: "year", seconds: 365 * 24 * 60 * 60 },
  { unit: "month", seconds: 30 * 24 * 60 * 60 },
  { unit: "day", seconds: 24 * 60 * 60 },
  { unit: "hour", seconds: 60 * 60 },
  { unit: "minute", seconds: 60 },
  { unit: "second", seconds: 1 },
];

const formatters = new Map();

function getFormatter(locale) {
  let formatter = formatters.get(locale);
  if (formatter === undefined) {
    formatter = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
    formatters.set(locale, formatter);
  }
  return formatter;
}

export function formatRelativeTime(target, options = {}) {
  const { now = Date.now(), locale = "en" } = options;
  const targetTime =
    target instanceof Date ? target.getTime() : typeof target === "string" ? Date.parse(target) : target;
  if (!Number.isFinite(targetTime)) throw new TypeError("target must be a valid Date, ISO string or timestamp");
  if (!Number.isFinite(now)) throw new TypeError("now must be a finite timestamp");
  const deltaSeconds = Math.round((targetTime - now) / 1000);
  const magnitude = Math.abs(deltaSeconds);
  const division =
    DIVISIONS.find((item) => magnitude >= item.seconds) ?? DIVISIONS[DIVISIONS.length - 1];
  const value = Math.round(deltaSeconds / division.seconds);
  return getFormatter(locale).format(value, division.unit);
}

const now = Date.parse("2026-10-21T12:00:00Z");
console.log(formatRelativeTime("2026-10-21T10:00:00Z", { now, locale: "en" }));
console.log(formatRelativeTime(now + 90_000, { now, locale: "de" }));
console.log(formatRelativeTime(now - 45 * 24 * 60 * 60 * 1000, { now, locale: "zh-CN" }));
-- B-tree index for equality and range queries
CREATE INDEX idx_products_category_price
    ON products (category_id, unit_price);

-- Partial index: only index active products
CREATE INDEX idx_products_active
    ON products (product_name)
    WHERE discontinued_date IS NULL;

-- Expression index for case-insensitive searches
CREATE INDEX idx_customers_email_lower
    ON customers (LOWER(email));

-- Unique index for constraint enforcement
CREATE UNIQUE INDEX idx_orders_customer_date
    ON orders (customer_id, order_date)
    WHERE status != 'cancelled';

-- Covering index (INCLUDE) for index-only scans
CREATE INDEX idx_order_items_covering
    ON order_items (order_id)
    INCLUDE (product_id, quantity, unit_price);

-- Concurrent index creation (no table locks)
CREATE INDEX CONCURRENTLY idx_products_name
    ON products (product_name);