乐于分享
好东西不私藏

RAGFlow源码解析-11、数据库与服务层深度解析(第九周)

RAGFlow源码解析-11、数据库与服务层深度解析(第九周)

概述

本周深入分析 RAGFlow 的数据库架构和服务层设计。RAGFlow 采用 Peewee ORM 作为数据库抽象层,支持 MySQL、PostgreSQL、OceanBase、SeekDB 等多种数据库。服务层遵循 Active Record 模式,通过 CommonService 基类提供统一的 CRUD 操作接口。

核心文件

  • api/db/db_models.py
     - 数据模型定义与数据库连接池
  • api/db/services/common_service.py
     - 服务层基类
  • api/db/services/knowledgebase_service.py
     - 知识库服务
  • api/db/services/document_service.py
     - 文档服务
  • 其他 20+ 服务类

一、数据库连接池架构

1.1 多数据库支持设计

1.2 连接池核心实现

源码位置api/db/db_models.py:244-315

class RetryingPooledMySQLDatabase(PooledMySQLDatabase):    def __init__(self, *args, **kwargs):        self.max_retries = kwargs.pop("max_retries"5)        self.retry_delay = kwargs.pop("retry_delay"1)        super().__init__(*args, **kwargs)    def execute_sql(self, sql, params=None):        for attempt in range(self.max_retries + 1):            try:                return super().execute_sql(sql, params)            except (OperationalError, InterfaceError) as e:                error_codes = [20132006]  # 连接丢失错误码                error_messages = ['''Lost connection']                should_retry = (                    (hasattr(e, 'args'and e.args and e.args[0in error_codes) or                    (str(e) in error_messages) or                    (hasattr(e, '__class__'and e.__class__.__name__ == 'InterfaceError')                )                if should_retry and attempt < self.max_retries:                    logging.warning(                        f"Database connection issue (attempt {attempt+1}/{self.max_retries}): {e}"                    )                    self._handle_connection_loss()                    time.sleep(self.retry_delay * (2 ** attempt))  # 指数退避                else:                    logging.error(f"DB execution failure: {e}")                    raise        return None

设计决策分析:

特性
实现方式
优势
连接池
PooledMySQLDatabase
复用连接,减少开销
重试机制
指数退避策略
避免雪崩效应
错误识别
错误码+消息匹配
精确识别可重试错误
连接恢复
_handle_connection_loss()
自动重建连接

1.3 数据库类型适配

源码位置api/db/db_models.py:49-57

classTextFieldType(Enum):    MYSQL = "LONGTEXT"    OCEANBASE = "LONGTEXT"    SEEKDB = "LONGTEXT"    POSTGRES = "TEXT"class LongTextField(TextField):    field_type = TextFieldType[settings.DATABASE_TYPE.upper()].value

二、自定义字段类型

2.1 字段类型继承层次

2.2 JSONField 实现

源码位置api/db/db_models.py:60-76

class JSONField(LongTextField):    default_value = {}    def __init__(self, object_hook=None, object_pairs_hook=None, **kwargs):        self._object_hook = object_hook        self._object_pairs_hook = object_pairs_hook        super().__init__(**kwargs)    def db_value(self, value):        if value is None:            value = self.default_value        return json_dumps(value)    def python_value(self, value):        if not value:            return self.default_value        return json_loads(value, object_hook=self._object_hook,                          object_pairs_hook=self._object_pairs_hook)

使用示例:

class Knowledgebase(DataBaseModel):    parser_config = JSONField(null=False                             default={"pages": [[11000000]],                                      "table_context_size"0                                     "image_context_size"0})    kb_ids = JSONField(null=Falsedefault=[])

2.3 SerializedField 序列化策略


三、BaseModel 基类设计

3.1 模型基类功能矩阵

3.2 时间戳自动填充机制

源码位置api/db/db_models.py:214-236

class BaseModel(Model):    create_time = BigIntegerField(null=True, index=True)    create_date = DateTimeField(null=True, index=True)    update_time = BigIntegerField(null=True, index=True)    update_date = DateTimeField(null=True, index=True)    @classmethod    def _normalize_data(cls, data, kwargs):        normalized = super()._normalize_data(data, kwargs)        if not normalized:            return {}        normalized[cls._meta.combined["update_time"]] = current_timestamp()        for f_n in AUTO_DATE_TIMESTAMP_FIELD_PREFIX:            if {f"{f_n}_time"f"{f_n}_date"}.issubset(cls._meta.combined.keys()):                if cls._meta.combined[f"{f_n}_time"in normalized:                    timestamp = normalized[cls._meta.combined[f"{f_n}_time"]]                    if timestamp is not None:                        normalized[cls._meta.combined[f"{f_n}_date"]] = \                            timestamp_to_date(timestamp)        return normalized

自动时间戳字段前缀:

AUTO_DATE_TIMESTAMP_FIELD_PREFIX = {"create""start""end""update"                                    "read_access""write_access"}

3.3 查询构造器

源码位置api/db/db_models.py:174-212

@classmethoddef query(cls, reverse=None, order_by=None, **kwargs):    filters = []    for f_n, f_v in kwargs.items():        attr_name = "%s" % f_n        if not hasattr(cls, attr_name) or f_v is None:            continue        if type(f_v) in {listset}:            f_v = list(f_v)            if is_continuous_field(type(getattr(cls, attr_name))):                # 范围查询                if len(f_v) == 2:                    lt_value, gt_value = f_v[0], f_v[1]                    if lt_value is not None and gt_value is not None:                        filters.append(cls.getter_by(attr_name).between(lt_value, gt_value))                    elif lt_value is not None:                        filters.append(operator.attrgetter(attr_name)(cls) >= lt_value)                    elif gt_value is not None:                        filters.append(operator.attrgetter(attr_name)(cls) <= gt_value)            else:                # IN 查询                filters.append(operator.attrgetter(attr_name)(cls) << f_v)        else:            # 等值查询            filters.append(operator.attrgetter(attr_name)(cls) == f_v)    if filters:        query_records = cls.select().where(*filters)        if reverse is not None:            if not order_by:                order_by = "create_time"            if reverse is True:                query_records = query_records.order_by(                    cls.getter_by(f"{order_by}").desc())            elif reverse is False:                query_records = query_records.order_by(                    cls.getter_by(f"{order_by}").asc())        return [query_record for query_record in query_records]    else:        return []

查询示例:

# 等值查询users = User.query(email="test@example.com")# 范围查询docs = Document.query(create_time=["2024-01-01""2024-12-31"])# IN 查询kbs = Knowledgebase.query(tenant_id=["tenant1""tenant2"])# 排序docs = Document.query(kb_id="kb123", reverse=True, order_by="update_time")

四、数据库锁机制

4.1 分布式锁设计

4.2 锁实现对比

MySQL 锁实现 (api/db/db_models.py:594-638):

class MysqlDatabaseLock:    def __init__(self, lock_name, timeout=10, db=None):        self.lock_name = lock_name        self.timeout = int(timeout)        self.db = db if db else DB    @with_retry(max_retries=3, retry_delay=1.0)    def lock(self):        cursor = self.db.execute_sql("SELECT GET_LOCK(%s, %s)"                                     (self.lock_name, self.timeout))        ret = cursor.fetchone()        if ret[0] == 0:            raise Exception(f"acquire mysql lock {self.lock_name} timeout")        elif ret[0] == 1:            return True        else:            raise Exception(f"failed to acquire lock {self.lock_name}")    @with_retry(max_retries=3, retry_delay=1.0)    def unlock(self):        cursor = self.db.execute_sql("SELECT RELEASE_LOCK(%s)"                                     (self.lock_name,))        ret = cursor.fetchone()        if ret[0] == 0:            raise Exception(f"mysql lock {self.lock_name} was not established")        elif ret[0] == 1:            return True        else:            raise Exception(f"mysql lock {self.lock_name} does not exist")

PostgreSQL 锁实现 (api/db/db_models.py:547-591):

class PostgresDatabaseLock:    def __init__(self, lock_name, timeout=10, db=None):        self.lock_name = lock_name        # 使用 MD5 哈希生成锁 ID        self.lock_id = int(hashlib.md5(lock_name.encode()).hexdigest(), 16) % (2**31 - 1)        self.timeout = int(timeout)        self.db = db if db else DB    @with_retry(max_retries=3, retry_delay=1.0)    def lock(self):        cursor = self.db.execute_sql("SELECT pg_try_advisory_lock(%s)"                                     (self.lock_id,))        ret = cursor.fetchone()        if ret[0] == 0:            raise Exception(f"acquire postgres lock {self.lock_name} timeout")        elif ret[0] == 1:            return True

4.3 锁装饰器模式

# 上下文管理器用法with DB.lock("init_database_tables"30):    init_database_tables()# 装饰器用法@DB.lock("init_database_tables"30)def init_database_tables(alter_fields=[]):    # 表初始化逻辑    pass

五、核心数据模型

5.1 数据模型关系图

5.2 用户与租户模型

User 模型 (api/db/db_models.py:707-733):

class User(DataBaseModel, AuthUser):    id = CharField(max_length=32, primary_key=True)    access_token = CharField(max_length=255null=True, index=True)    nickname = CharField(max_length=100null=False, index=True)    password = CharField(max_length=255null=True, index=True)    email = CharField(max_length=255null=False, index=True)    avatar = TextField(null=True)    language = CharField(max_length=32null=Truedefault="Chinese", index=True)    color_schema = CharField(max_length=32null=Truedefault="Bright", index=True)    timezone = CharField(max_length=64null=Truedefault="UTC+8\tAsia/Shanghai", index=True)    last_login_time = DateTimeField(null=True, index=True)    is_authenticated = CharField(max_length=1null=Falsedefault="1", index=True)    is_active = CharField(max_length=1null=Falsedefault="1", index=True)    is_anonymous = CharField(max_length=1null=Falsedefault="0", index=True)    login_channel = CharField(null=True, index=True)    status = CharField(max_length=1null=Truedefault="1", index=True)    is_superuser = BooleanField(null=Truedefault=False, index=True)    def get_id(self):        jwt = Serializer(secret_key=settings.SECRET_KEY)        return jwt.dumps(str(self.access_token))

Tenant 模型 (api/db/db_models.py:736-751):

class Tenant(DataBaseModel):    id = CharField(max_length=32, primary_key=True)    name = CharField(max_length=100null=True, index=True)    public_key = CharField(max_length=255null=True, index=True)    # 默认模型配置    llm_id = CharField(max_length=128null=False, index=True)    embd_id = CharField(max_length=128null=False, index=True)    asr_id = CharField(max_length=128null=False, index=True)    img2txt_id = CharField(max_length=128null=False, index=True)    rerank_id = CharField(max_length=128null=False, index=True)    tts_id = CharField(max_length=256null=True, index=True)    parser_ids = CharField(max_length=256null=False, index=True)    credit = IntegerField(default=512, index=True)    status = CharField(max_length=1null=Truedefault="1", index=True)

5.3 知识库与文档模型

Knowledgebase 模型 (api/db/db_models.py:843-877):

class Knowledgebase(DataBaseModel):    id = CharField(max_length=32, primary_key=True)    avatar = TextField(null=True)    tenant_id = CharField(max_length=32, null=False, index=True)    name = CharField(max_length=128, null=False, index=True)    language = CharField(max_length=32, null=True, default="Chinese", index=True)    description = TextField(null=True)    # Embedding 模型    embd_id = CharField(max_length=128, null=False, index=True)    # 权限控制    permission = CharField(max_length=16, null=False, default="me", index=True)    created_by = CharField(max_length=32, null=False, index=True)    # 统计信息    doc_num = IntegerField(default=0, index=True)    token_num = IntegerField(default=0, index=True)    chunk_num = IntegerField(default=0, index=True)    # 检索参数    similarity_threshold = FloatField(default=0.2, index=True)    vector_similarity_weight = FloatField(default=0.3, index=True)    # 解析器配置    parser_id = CharField(max_length=32, null=False, default=ParserType.NAIVE.value, index=True)    pipeline_id = CharField(max_length=32, null=True, index=True)    parser_config = JSONField(null=False, default={"pages": [[11000000]],                                                    "table_context_size"0                                                   "image_context_size"0})    pagerank = IntegerField(default=0, index=False)    # 后台任务    graphrag_task_id = CharField(max_length=32, null=True, index=True)    graphrag_task_finish_at = DateTimeField(null=True)    raptor_task_id = CharField(max_length=32, null=True, index=True)    raptor_task_finish_at = DateTimeField(null=True)    mindmap_task_id = CharField(max_length=32, null=True, index=True)    mindmap_task_finish_at = DateTimeField(null=True)    status = CharField(max_length=1, null=True, default="1", index=True)

Document 模型 (api/db/db_models.py:880-905):

class Document(DataBaseModel):    id = CharField(max_length=32, primary_key=True)    thumbnail = TextField(null=True)    kb_id = CharField(max_length=256, null=False, index=True)    # 解析配置    parser_id = CharField(max_length=32, null=False, index=True)    pipeline_id = CharField(max_length=32, null=True, index=True)    parser_config = JSONField(null=False, default={"pages": [[11000000]]})    # 文件信息    source_type = CharField(max_length=128, null=False, default="local", index=True)    type = CharField(max_length=32, null=False, index=True)    name = CharField(max_length=255, null=True, index=True)    location = CharField(max_length=255, null=True, index=True)    size = IntegerField(default=0, index=True)    suffix = CharField(max_length=32, null=False, index=True)    # 处理状态    token_num = IntegerField(default=0, index=True)    chunk_num = IntegerField(default=0, index=True)    progress = FloatField(default=0, index=True)    progress_msg = TextField(null=True, default="")    process_begin_at = DateTimeField(null=True, index=True)    process_duration = FloatField(default=0)    # 运行状态    run = CharField(max_length=1, null=True, default="0", index=True)    status = CharField(max_length=1, null=True, default="1", index=True)    created_by = CharField(max_length=32, null=False, index=True)

六、服务层架构

6.1 服务类继承体系

6.2 CommonService 基类详解

源码位置api/db/services/common_service.py:37-357

核心方法分析

查询方法 (common_service.py:51-99):

class CommonService:    model = None    @classmethod    @DB.connection_context()    def query(cls, cols=None, reverse=None, order_by=None, **kwargs):        """执行数据库查询,支持列选择和排序"""        return cls.model.query(cols=cols, reverse=reverse, order_by=order_by, **kwargs)    @classmethod    @DB.connection_context()    def get_all(cls, cols=None, reverse=None, order_by=None):        """获取所有记录"""        if cols:            query_records = cls.model.select(*cols)        else:            query_records = cls.model.select()        if reverse is not None:            if not order_by or not hasattr(cls.model, order_by):                order_by = "create_time"            if reverse is True:                query_records = query_records.order_by(                    cls.model.getter_by(order_by).desc())            elif reverse is False:                query_records = query_records.order_by(                    cls.model.getter_by(order_by).asc())        return query_records

插入方法 (common_service.py:156-203):

@classmethod@DB.connection_context()def insert(cls, **kwargs):    """插入新记录,自动生成 ID 和时间戳"""    if "id" not in kwargs:        kwargs["id"] = get_uuid()    timestamp = current_timestamp()    cur_datetime = datetime_format(datetime.now())    kwargs["create_time"] = timestamp    kwargs["create_date"] = cur_datetime    kwargs["update_time"] = timestamp    kwargs["update_date"] = cur_datetime    sample_obj = cls.model(**kwargs).save(force_insert=True)    return sample_obj@classmethod@DB.connection_context()def insert_many(cls, data_list, batch_size=100):    """批量插入记录"""    current_ts = current_timestamp()    current_datetime = datetime_format(datetime.now())    with DB.atomic():        for d in data_list:            d["create_time"] = current_ts            d["create_date"] = current_datetime            d["update_time"] = current_ts            d["update_date"] = current_datetime        for i in range(0len(data_list), batch_size):            cls.model.insert_many(data_list[i : i + batch_size]).execute()

更新方法 (common_service.py:227-240):

@classmethod@DB.connection_context()@retry_db_operationdef update_by_id(cls, pid, data):    """通过 ID 更新记录"""    data["update_time"] = current_timestamp()    data["update_date"] = datetime_format(datetime.now())    num = cls.model.update(data).where(cls.model.id == pid).execute()    return num@classmethod@DB.connection_context()def update_many_by_id(cls, data_list):    """批量更新记录"""    timestamp = current_timestamp()    cur_datetime = datetime_format(datetime.now())    for data in data_list:        data["update_time"] = timestamp        data["update_date"] = cur_datetime    with DB.atomic():        for data in data_list:            cls.model.update(data).where(cls.model.id == data["id"]).execute()

6.3 重试装饰器设计

源码位置common_service.py:25-35

def retry_db_operation(func):    @retry(        stop=stop_after_attempt(3),        wait=wait_exponential(multiplier=1min=1max=5),        retry=retry_if_exception_type((InterfaceError, OperationalError)),        before_sleep=lambda retry_state: print(f"RETRY {retry_state.attempt_number} TIMES"),        reraise=True,    )    def wrapper(*args, **kwargs):        return func(*args, **kwargs)    return wrapper

七、KnowledgebaseService 深度解析

7.1 知识库服务核心功能

7.2 文档解析状态检查

源码位置knowledgebase_service.py:85-117

@classmethod@DB.connection_context()def is_parsed_done(cls, kb_id):    """检查知识库中所有文档是否解析完成"""    from common.constants import TaskStatus    from api.db.services.document_service import DocumentService    # 获取知识库信息    kbs = cls.query(id=kb_id)    if not kbs:        return False"Knowledge base not found"    kb = kbs[0]    # 获取所有文档    docs, _ = DocumentService.get_by_kb_id(kb_id, 11000"create_time"True"", [], [])    # 检查每个文档的解析状态    for doc in docs:        # 正在解析中        if doc['run'] == TaskStatus.RUNNING.value or \           doc['run'] == TaskStatus.CANCEL.value or \           doc['run'] == TaskStatus.FAIL.value:            return Falsef"Document '{doc['name']}' in dataset '{kb.name}' is still being parsed."        # 未解析且无分块        if doc['run'] == TaskStatus.UNSTART.value and doc['chunk_num'] == 0:            return Falsef"Document '{doc['name']}' in dataset '{kb.name}' has not been parsed yet."    return TrueNone

7.3 解析器配置深度更新

源码位置knowledgebase_service.py:294-321

@classmethod@DB.connection_context()def update_parser_config(cls, id, config):    """更新知识库解析器配置(深度合并)"""    e, m = cls.get_by_id(id)    if not e:        raise LookupError(f"dataset({id}) not found.")    def dfs_update(old, new):        """深度更新嵌套配置"""        for k, v in new.items():            if k not in old:                old[k] = v                continue            if isinstance(v, dict):                assert isinstance(old[k], dict)                dfs_update(old[k], v)            elif isinstance(v, list):                assert isinstance(old[k], list)                old[k] = list(set(old[k] + v))  # 列表去重合并            else:                old[k] = v    dfs_update(m.parser_config, config)    cls.update_by_id(id, {"parser_config": m.parser_config})

配置合并示例:

# 原配置old_config = {    "pages": [[1, 100]],    "table_context_size": 0,    "raptor": {"enabled": True, "max_depth": 3}}# 新配置new_config = {    "pages": [[1, 200]],    "image_context_size": 512,    "raptor": {"max_depth": 5}}# 合并结果merged_config = {    "pages": [[1, 200]],  # 覆盖    "table_context_size": 0,  # 保留    "image_context_size": 512,  # 新增    "raptor": {"enabled": True, "max_depth": 5}  # 深度合并}

7.4 知识库创建流程

源码位置knowledgebase_service.py:374-430

@classmethod@DB.connection_context()def create_with_name(cls, *, name: str, tenant_id: str, parser_id: str | None = None, **kwargs):    """创建知识库(包含验证和默认配置)"""    # 验证名称    if not isinstance(name, str):        return False, get_data_error_result(message="Dataset name must be string.")    dataset_name = name.strip()    if dataset_name == "":        return False, get_data_error_result(message="Dataset name can't be empty.")    if len(dataset_name.encode("utf-8")) > DATASET_NAME_LIMIT:        return False, get_data_error_result(message=f"Dataset name too long")    # 名称去重    dataset_name = duplicate_name(        cls.query,        name=dataset_name,        tenant_id=tenant_id,        status=StatusEnum.VALID.value,    )    # 验证租户    ok, _t = TenantService.get_by_id(tenant_id)    if not ok:        return False, get_data_error_result(message="Tenant not found.")    # 构建 payload    kb_id = get_uuid()    payload = {        "id": kb_id,        "name": dataset_name,        "tenant_id": tenant_id,        "created_by": tenant_id,        "parser_id": (parser_id or "naive"),        **kwargs    }    # 设置解析器配置    payload["parser_config"] = get_parser_config(parser_id, kwargs.get("parser_config"))    payload["parser_config"]["llm_id"] = _t.llm_id    return True, payload

八、DocumentService 深度解析

8.1 文档服务功能矩阵

8.2 文档删除复杂流程

源码位置document_service.py:360-422

@classmethod@DB.connection_context()def remove_document(cls, doc, tenant_id):    """删除文档及其所有关联数据"""    from api.db.services.task_service import TaskService, cancel_all_task_of    # 清空分块计数    cls.clear_chunk_num(doc.id)    # 取消所有运行中的任务    try:        cancel_all_task_of(doc.id)        logging.info(f"Cancelled all tasks for document {doc.id}")    except Exception as e:        logging.warning(f"Failed to cancel tasks for document {doc.id}{e}")    # 删除数据库任务    try:        TaskService.filter_delete([Task.doc_id == doc.id])    except Exception as e:        logging.warning(f"Failed to delete tasks for document {doc.id}{e}")    # 删除分块图片    try:        cls.delete_chunk_images(doc, tenant_id)    except Exception as e:        logging.warning(f"Failed to delete chunk images for document {doc.id}{e}")    # 删除缩略图    try:        if doc.thumbnail and not doc.thumbnail.startswith(IMG_BASE64_PREFIX):            if settings.STORAGE_IMPL.obj_exist(doc.kb_id, doc.thumbnail):                settings.STORAGE_IMPL.rm(doc.kb_id, doc.thumbnail)    except Exception as e:        logging.warning(f"Failed to delete thumbnail for document {doc.id}{e}")    # 删除向量存储中的chunks(关键操作)    try:        settings.docStoreConn.delete({"doc_id": doc.id},                                      search.index_name(tenant_id), doc.kb_id)    except Exception as e:        logging.error(f"Failed to delete chunks from doc store for document {doc.id}{e}")    # 删除文档元数据    try:        DocMetadataService.delete_document_metadata(doc.id)    except Exception as e:        logging.warning(f"Failed to delete metadata for document {doc.id}{e}")    # 清理知识图谱引用    try:        graph_source = settings.docStoreConn.get_fields(...)        if len(graph_source) > 0 and doc.id in list(graph_source.values())[0]["source_id"]:            settings.docStoreConn.update(...)            settings.docStoreConn.delete(...)    except Exception as e:        logging.warning(f"Failed to cleanup knowledge graph for document {doc.id}{e}")    return cls.delete_by_id(doc.id)

8.3 进度同步机制

源码位置document_service.py:755-828

@classmethod@DB.connection_context()def _sync_progress(cls, docs: list[dict]):    """同步文档进度"""    from api.db.services.task_service import TaskService    for d in docs:        try:            tsks = TaskService.query(doc_id=d["id"], order_by=Task.create_time)            if not tsks:                continue            msg = []            prg = 0            finished = True            bad = 0            e, doc = DocumentService.get_by_id(d["id"])            status = doc.run            if status == TaskStatus.CANCEL.value:                continue            doc_progress = doc.progress if doc and doc.progress else 0.0            special_task_running = False            priority = 0            for t in tsks:                task_type = (t.task_type or "").lower()                if task_type in PIPELINE_SPECIAL_PROGRESS_FREEZE_TASK_TYPES:                    special_task_running = True                if 0 <= t.progress < 1:                    finished = False                if t.progress == -1:                    bad += 1                prg += t.progress if t.progress >= 0 else 0                if t.progress_msg.strip():                    msg.append(t.progress_msg)                priority = max(priority, t.priority)            prg /= len(tsks)            if finished and bad:                prg = -1                status = TaskStatus.FAIL.value            elif finished:                prg = 1                status = TaskStatus.DONE.value            # 特殊任务进度冻结逻辑            freeze_progress = special_task_running and doc_progress >= 1 and not finished            msg = "\n".join(sorted(msg))            begin_at = d.get("process_begin_at")            if not begin_at:                begin_at = datetime.now()                cls.update_by_id(d["id"], {"process_begin_at": begin_at})            info = {                "process_duration"max(datetime.timestamp(datetime.now()) - begin_at.timestamp(), 0),                "run": status            }            if prg != 0 and not freeze_progress:                info["progress"] = prg            if msg:                info["progress_msg"] = msg                if msg.endswith("created task graphrag"or \                   msg.endswith("created task raptor"or \                   msg.endswith("created task mindmap"):                    info["progress_msg"] += "\n%d tasks are ahead in the queue..." % get_queue_length(priority)            else:                info["progress_msg"] = "%d tasks are ahead in the queue..." % get_queue_length(priority)            info["update_time"] = current_timestamp()            info["update_date"] = get_format_time()            (cls.model.update(info)             .where(                 (cls.model.id == d["id"])                 & ((cls.model.run.is_null(True)) | (cls.model.run != TaskStatus.CANCEL.value))             )             .execute())        except Exception as e:            if str(e).find("'0'") < 0:                logging.exception("fetch task exception")

8.4 文档统计信息

源码位置document_service.py:856-909

@classmethod@DB.connection_context()def knowledgebase_basic_info(cls, kb_id: str) -> dict[strint]:    """获取知识库文档统计信息"""    # 取消的文档数    cancelled = (        cls.model.select(fn.COUNT(1))        .where((cls.model.kb_id == kb_id) & (cls.model.run == TaskStatus.CANCEL))        .scalar()    )    # 下载的文档数    downloaded = (        cls.model.select(fn.COUNT(1))        .where(            cls.model.kb_id == kb_id,            cls.model.source_type != "local"        )        .scalar()    )    # 完成数、失败数、处理中数    row = (        cls.model.select(            # finished: progress == 1            fn.COALESCE(fn.SUM(Case(None, [(cls.model.progress == 11)], 0)), 0).alias("finished"),            # failed: progress == -1            fn.COALESCE(fn.SUM(Case(None, [(cls.model.progress == -11)], 0)), 0).alias("failed"),            # processing: 0 <= progress < 1            fn.COALESCE(                fn.SUM(                    Case(                        None,                        [                            (((cls.model.progress == 0) | ((cls.model.progress > 0) & (cls.model.progress < 1))), 1),                        ],                        0,                    )                ),                0,            ).alias("processing"),        )        .where(            (cls.model.kb_id == kb_id)            & ((cls.model.run.is_null(True)) | (cls.model.run != TaskStatus.CANCEL))        )        .dicts()        .get()    )    return {        "processing"int(row["processing"]),        "finished"int(row["finished"]),        "failed"int(row["failed"]),        "cancelled"int(cancelled),        "downloaded"int(downloaded)    }

九、设计模式总结

9.1 Active Record 模式

RAGFlow 服务层采用 Active Record 模式,每个服务类对应一个数据模型:

class KnowledgebaseService(CommonService):    model = Knowledgebase  # 绑定模型    # 服务方法直接操作模型    @classmethod    def get_detail(cls, kb_id):        return cls.model.select(*fields).where(...)

优势:

  • 简单直观,易于理解
  • 减少代码重复
  • 便于测试和维护

9.2 装饰器模式

数据库操作通过装饰器增强功能:

@DB.connection_context()  # 连接上下文管理@DB.lock("init_database_tables"30)  # 分布式锁@retry_db_operation  # 重试机制def init_database_tables(alter_fields=[]):    pass

9.3 模板方法模式

CommonService 定义了 CRUD 操作的骨架,子类通过重写特定方法定制行为:

class CommonService:    @classmethod    def insert(cls, **kwargs):        # 模板方法:固定流程        if "id" not in kwargs:            kwargs["id"] = get_uuid()        timestamp = current_timestamp()        kwargs["create_time"] = timestamp        # ... 子类可重写特定步骤        return cls.model(**kwargs).save(force_insert=True)

十、性能优化策略

10.1 批量操作优化

# 批量插入(分批次)@classmethoddef insert_many(cls, data_list, batch_size=100):    with DB.atomic():  # 事务包装        for i in range(0len(data_list), batch_size):            cls.model.insert_many(data_list[i : i + batch_size]).execute()# 批量查询(分块)@classmethoddef filter_scope_list(cls, in_key, in_filters_list, filters=None, cols=None):    in_filters_tuple_list = cls.cut_list(in_filters_list, 20)  # 每次查询20条    res_list = []    for i in in_filters_tuple_list:        query_records = cls.model.select().where(getattr(cls.model, in_key).in_(i), *filters)        res_list.extend([query_record for query_record in query_records])    return res_list

10.2 索引策略

所有关键字段都添加了索引:

class Knowledgebase(DataBaseModel):    tenant_id = CharField(max_length=32, null=False, index=True)  # 索引    name = CharField(max_length=128, null=False, index=True)  # 索引    embd_id = CharField(max_length=128, null=False, index=True)  # 索引    create_time = BigIntegerField(null=True, index=True)  # 索引

10.3 连接池配置

pool_config = {    'max_retries': 5,  # 最大重试次数    'retry_delay': 1,  # 初始重试延迟}database_config.update(pool_config)
基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-06-05 01:59:30 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/711812.html
  2. 运行时间 : 0.184053s [ 吞吐率:5.43req/s ] 内存消耗:4,796.76kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=0bbd133525bec34b1f30f877dbbf7ec7
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000886s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001245s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000607s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000584s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001121s ]
  6. SELECT * FROM `set` [ RunTime:0.000454s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001214s ]
  8. SELECT * FROM `article` WHERE `id` = 711812 LIMIT 1 [ RunTime:0.001371s ]
  9. UPDATE `article` SET `lasttime` = 1780595970 WHERE `id` = 711812 [ RunTime:0.024391s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000311s ]
  11. SELECT * FROM `article` WHERE `id` < 711812 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000602s ]
  12. SELECT * FROM `article` WHERE `id` > 711812 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.008719s ]
  13. SELECT * FROM `article` WHERE `id` < 711812 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000811s ]
  14. SELECT * FROM `article` WHERE `id` < 711812 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002598s ]
  15. SELECT * FROM `article` WHERE `id` < 711812 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.021069s ]
0.185749s