Skip to main content

N1QueryDetector

Struct N1QueryDetector 

Source
pub struct N1QueryDetector { /* private fields */ }
Expand description

N+1 查询检测器

通过统计相同表/关系在循环加载场景下的查询次数,识别潜在的 N+1 查询问题。

§检测策略

  1. 次数阈值:同一 relation 在一次“检测窗口“内被查询次数超过 threshold(默认 5),即判定为 N+1 嫌疑;
  2. 检测窗口:以 start_window() / end_window() 显式划定窗口, 便于在循环外包裹;
  3. 批量命中识别:如果一次 record_batch_load 调用就加载了多个 key, 视为已通过批量加载规避 N+1,仅记 1 次批量查询;
  4. 回调告警:触发 N+1 时调用可选的 on_alert 回调(用于日志/指标上报)。

§设计动机

SeaORM 的 find_with_related 仅在显式调用时才会批量加载,缺乏运行时 检测机制。本检测器提供运行时 introspection,可在开发/测试环境启用, 在生产环境关闭(zero-cost 抽象)。

§线程安全

内部使用 RwLock<HashMap> 维护计数,可在线程间共享(Send + Sync)。

§示例

use sz_orm_query::entity_graph::{N1QueryDetector, N1DetectionConfig};

let detector = N1QueryDetector::new(N1DetectionConfig::default());
detector.start_window();
for _ in 0..10 {
    detector.record_single_load("posts");
}
detector.end_window();
let alerts = detector.alerts();
assert_eq!(alerts.len(), 1);
assert_eq!(alerts[0].relation, "posts");
assert_eq!(alerts[0].query_count, 10);

Implementations§

Source§

impl N1QueryDetector

Source

pub fn new(config: N1DetectionConfig) -> Self

创建检测器

Source

pub fn with_defaults() -> Self

创建默认配置的检测器

Source

pub fn is_enabled(&self) -> bool

是否启用检测

Source

pub fn threshold(&self) -> u64

当前阈值

Source

pub fn start_window(&self)

开启检测窗口(清空旧计数与旧告警)

重复调用 start_window 会重置窗口。

Source

pub fn end_window(&self) -> Vec<N1Alert>

结束检测窗口,分析并生成告警

结束后 record_* 调用会被忽略,直到下一次 start_window。 返回本次窗口产生的告警列表。

Source

pub fn record_single_load(&self, relation: &str)

记录一次单条加载(典型的 N+1 来源:循环内 find_by_id

Source

pub fn record_batch_load(&self, relation: &str, _keys_count: usize)

记录一次批量加载(已规避 N+1 的良好实践)

  • keys_count:本次批量加载的 key 数量
  • 一个 batch 仅记 1 次批量查询,不论 keys_count 多少
Source

pub fn alerts(&self) -> Vec<N1Alert>

获取最近一次 end_window 产生的告警(只读副本)

Source

pub fn current_count(&self, relation: &str) -> u64

当前窗口内某 relation 的单条查询次数

Source

pub fn current_batch_count(&self, relation: &str) -> u64

当前窗口内某 relation 的批量查询次数

Source

pub fn is_window_active(&self) -> bool

窗口是否处于开启状态

Source

pub fn has_n_plus_one(&self) -> bool

是否已检测到 N+1(基于最近一次窗口的告警)

Trait Implementations§

Source§

impl Default for N1QueryDetector

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more