当前位置:首页>python>第4.5章:Python AI开发常用标准库

第4.5章:Python AI开发常用标准库

  • 2026-08-20 13:21:52
第4.5章:Python AI开发常用标准库

《Python AI 应用开发入门》第 4.5 节。

运用 datetime、uuid、collections、logging、os 和 python-dotenv,完善对话核心的时间记录、唯一标识、统计、日志和环境配置。

本节目标

学完本节后,你应当能够:

  1. 1. 区分标准库模块与需要额外安装的第三方包。
  2. 2. 使用带时区的 datetime 记录消息时间。
  3. 3. 使用 ISO 8601 字符串保存时间,并将其恢复为时间对象。
  4. 4. 使用 uuid4() 为会话和消息生成唯一标识。
  5. 5. 使用 Counter 统计消息角色。
  6. 6. 使用 deque 保存有限长度的最近记录。
  7. 7. 使用 defaultdict 按键分组数据。
  8. 8. 在程序入口统一配置日志,并在业务代码中记录关键事件。
  9. 9. 将日志同时输出到终端和文件,并能确定日志文件的实际路径。
  10. 10. 选择合适日志级别并避免泄露敏感信息。
  11. 11. 使用 python-dotenv 加载 .env,再通过 os.getenv() 读取和验证配置。
  12. 12. 将本章的数据模型与对象协作方式整合为一个完整的对话核心。

1. 什么是标准库

安装 Python 时,一批常用模块也会随之安装,它们合称 Python 标准库。标准库不需要再用 pip 安装,但使用前仍然需要先 import

import loggingimport osfrom pathlib import Pathimport uuidfrom collections import Counterfrom datetime import datetime

第三方包不属于 Python 自带内容,通常由社区或厂商维护。使用前,需要先把它们安装到当前虚拟环境,例如后续课程会用到的 HTTP 客户端和 Web 框架。

“属于标准库”只说明模块随 Python 一同提供,并不意味着它适合所有场景,也不意味着调用时一定不会出错。使用前,仍要弄清它能解决什么问题、有哪些使用限制。

本节将结合对话核心,学习以下几个常用模块:

  • • datetime:记录和转换时间。
  • • uuid:生成唯一标识。
  • • collections:完成计数、分组和有界队列等操作。
  • • logging:记录程序运行情况。
  • • os:从环境变量中读取配置。

后文还会使用 python-dotenv 加载 .env。它不是标准库,而是项目开发中常用的第三方包,需要单独安装;将它放在本节,是为了把环境配置的实际使用流程讲完整。

2. 正确处理时间与时区

先来看如何获取当前的 UTC 时间:

from datetime import datetime, timezonecreated_at = datetime.now(timezone.utc)print(created_at)

datetime.now() 用来获取当前时间。传入 timezone.utc 后,得到的是 UTC 时间,并且结果中会明确保留时区信息。

如果不传时区,会得到一个不带时区信息的时间,Python 文档称它为“朴素时间”:

naive_time = datetime.now()

这类对象虽然包含年月日和时分秒,却没有说明它表示的是北京时间、UTC,还是其他地区的时间。程序只在本机运行时,问题可能并不明显;一旦需要跨地区部署或与 API 交换数据,同一个时间点就可能被错误理解。

因此,后端程序通常统一保存带时区的 UTC 时间,展示给用户时再转换为当地时间。

3. 使用 ISO 8601 保存时间

JSON 只能保存字符串、数字、列表和字典等基础类型,不能直接保存 datetime 对象。写入 JSON 前,通常先把时间转换为 ISO 8601 格式的字符串:

from datetime import datetime, timezonecreated_at = datetime.now(timezone.utc)created_at_text = created_at.isoformat()print(created_at_text)

输出类似:

2026-08-06T08:30:00.123456+00:00

读取数据后,可以把字符串恢复为 datetime 对象:

restored_time = datetime.fromisoformat(created_at_text)print(restored_time)print(restored_time.tzinfo)

isoformat() 把时间对象转换为字符串,fromisoformat() 则把字符串恢复为时间对象。使用这组方法,比手动拼接和拆分年月日更清楚,也不容易遗漏时区信息。

不过,来自外部的字符串仍可能格式错误或缺少时区。读取不可信数据时,要捕获 ValueError,并检查 tzinfo 是否符合要求。

4. 用 UUID 生成稳定标识

每条消息都应该拥有稳定、独立的标识。列表索引不适合作为长期消息 ID:一旦删除或调整消息顺序,后续消息的索引也会随之改变。

标准库中的 uuid 模块可以生成这样的标识:

from uuid import uuid4message_id = str(uuid4())print(message_id)

输出类似:

6a850f09-65fe-4a9d-9484-99e6c22f3fd8

uuid4() 基于随机数据生成 UUID。多次调用得到相同结果的概率极低,因此很适合为本课程中的会话、消息和请求生成彼此独立的标识。

使用 UUID 时需要注意:

  • • UUID 适合标识对象,不负责身份认证。
  • • UUID 不保证按创建时间排序。
  • • 即使 UUID 很难猜,也不能用它代替访问权限检查。
  • • 写入 JSON 前通常使用 str() 转为字符串。

5. 用 Counter 统计消息角色

先看使用普通字典计数的写法:

counts = {}for message in messages:    role = message.role    counts[role] = counts.get(role, 0) + 1

如果只是想统计每个值出现了多少次,可以直接使用 collections.Counter

from collections import Counterrole_counts = Counter(    message.role    for message in messages)print(role_counts["user"])print(role_counts["assistant"])

Counter 的用法与字典相近,但访问尚未出现的键时会得到 0,因此不必事先判断键是否存在。

查看最常见项目:

print(role_counts.most_common(2))

Counter 适合处理单纯的计数问题。如果还要为每个角色保存权限、显示名称等复杂信息,就应该改用结构更明确的数据模型。

6. 用 deque 保留最近记录

如果程序只关心“最近三条命令”,普通列表也能实现,但需要手动检查长度并删除旧数据。deque 是双端队列,既能限制最大长度,也能高效地从两端添加或删除元素:

from collections import dequerecent_commands = deque(maxlen=3)recent_commands.append("list")recent_commands.append("add user 你好")recent_commands.append("recent 5")recent_commands.append("exit")print(list(recent_commands))

输出只保留最近三项:

['add user 你好', 'recent 5', 'exit']

maxlen=3 表示最多保留三项。队列达到上限后,如果继续从右侧 append(),左侧最旧的元素会被自动移除。

适合 deque 的场景:

  • • 最近 N 条操作。
  • • 有上限的内存缓存。
  • • 需要从队列两端处理的数据。

deque 只负责内存中的队列操作,不会自动将数据写入文件。需要长期保存的完整聊天记录,仍然可以使用列表并将其写入 JSON。

7. 用 defaultdict 按角色分组

如果要按角色把消息放进不同列表,使用普通字典时,需要先为第一次出现的角色创建空列表:

grouped_messages = {}for message in messages:    if message.role not in grouped_messages:        grouped_messages[message.role] = []    grouped_messages[message.role].append(message)

defaultdict 可以预先指定“键不存在时要创建什么”:

from collections import defaultdictgrouped_messages = defaultdict(list)for message in messages:    grouped_messages[message.role].append(message)

这里将 list 函数传给 defaultdict。第一次访问某个新角色时,它会调用 list() 创建空列表,然后再执行 append()

defaultdict 主要用于简化程序内部的处理逻辑。写入 JSON,或传给只接收普通字典的代码之前,可以先进行转换:

serializable_groups = dict(grouped_messages)

8. print() 和日志各自适合什么场景

print() 通常用于直接向用户显示程序结果,也适合在学习和调试时临时观察变量:

  • • 面向用户显示结果。
  • • 临时学习和快速观察。

日志主要供开发者和运维人员查看,用于了解程序内部的运行情况:

  • • 记录程序内部发生的事件。
  • • 区分重要程度。
  • • 附带时间、模块和异常信息。
  • • 可以统一控制日志输出到终端或文件。

业务模块通常会先创建当前模块专用的日志记录器:

import logginglogger = logging.getLogger(__name__)

这里传入的 __name__ 就是当前模块名。即使多个文件都在记录日志,也能通过日志中的名称判断事件来自哪个模块。

9. 配置并使用日志

9.1 在程序入口配置日志

创建 logger 只是取得一个日志记录器,还需要设置最低记录级别和输出格式。基础配置通常只在程序入口执行一次:

import logginglogging.basicConfig(    level=logging.INFO,    format="%(asctime)s %(levelname)s %(name)s %(message)s",)

level=logging.INFO 表示只处理 INFO 及以上级别的日志,DEBUG 日志会被忽略。format 决定每条日志显示哪些信息;上面的配置会依次显示时间、级别、模块名和消息正文。

如果只使用这段配置,日志默认输出到终端的标准错误流 sys.stderr,不会自动生成日志文件。在普通终端中,它会和程序输出一起显示;在 VS Code 或 PyCharm 中,通常会出现在运行控制台。

9.2 在业务代码中记录日志

入口完成配置后,业务模块只需要根据事件的严重程度调用对应方法:

logger = logging.getLogger(__name__)def save_session(session_id, message_count):    logger.info(        "正在保存会话 session_id=%s message_count=%s",        session_id,        message_count,    )logger.debug("准备读取会话缓存")logger.warning("会话历史即将达到上限")logger.error("会话保存失败")

日志消息中的 %s 是占位符,后面的参数会依次填入。相比提前使用 f-string 拼接,日志更推荐这种写法:如果当前级别不需要输出这条消息,日志系统可以省去不必要的字符串格式化。

常用级别:

级别
用途示例
DEBUG
开发时观察详细状态
INFO
正常的重要流程,例如启动、保存成功
WARNING
可以继续运行,但出现异常情况
ERROR
当前操作失败,需要关注
CRITICAL
程序无法继续的严重故障

级别表达的是事件的严重程度。用户把命令输错通常不是系统故障,而保存文件失败也不应只藏在 DEBUG 中。

9.3 同时输出到终端和文件

需要长期保留日志时,可以显式添加 FileHandler。下面的配置会把同一条日志同时输出到终端和 logs/chat.log

import loggingfrom pathlib import Pathproject_dir = Path(__file__).resolve().parentlog_dir = project_dir / "logs"log_dir.mkdir(parents=True, exist_ok=True)log_file = log_dir / "chat.log"logging.basicConfig(    level=logging.INFO,    format="%(asctime)s %(levelname)s %(name)s %(message)s",    handlers=[        logging.StreamHandler(),        logging.FileHandler(log_file, encoding="utf-8"),    ],)logger = logging.getLogger(__name__)logger.info("日志系统已启动 log_file=%s", log_file.resolve())

这里使用 Path(__file__).resolve().parent 找到入口脚本所在目录。因此,如果 main.py 位于项目根目录,日志就会保存在项目根目录下的 logs/chat.log,不会因为从不同终端目录启动程序而改变位置。

FileHandler 不会自动创建父目录,所以必须先调用 log_dir.mkdir()。它默认以追加模式写入,程序重新启动后,新日志会接在旧日志后面。如果只想写入文件,可以删掉 logging.StreamHandler();如果不配置 FileHandler,就不会产生日志文件。

这个示例适合课程练习。长期运行的服务还要考虑日志轮转,否则单个文件会不断增大;后续可以使用 logging.handlers.RotatingFileHandler 按文件大小保留有限数量的历史日志。

10. 记录异常

只记录“读取失败”通常还不够,我们还需要知道错误出现在哪一行。在 except 代码块中调用 logger.exception(),日志会自动附带 Traceback:

def load_session(path):    try:        return path.read_text(encoding="utf-8")    except OSError:        logger.exception("读取会话失败 path=%s", path)        raise

logger.exception() 应该在处理异常的 except 代码块中使用。

这里记录后仍然执行 raise,让上层代码决定如何提示用户或恢复操作。把错误写进日志,并不等于错误已经处理完毕。

不要在日志中记录以下内容:

  • • API Key、密码和访问令牌。
  • • 完整认证请求头。
  • • 不必要的私密对话内容。
  • • 包含密钥的完整配置字典。

可以记录消息数量、会话 ID、模型名称和错误类型等诊断信息,但应遵循最小必要原则。

11. 从环境变量读取配置

模型名称、历史记录上限和 API Key 等配置,不应该散落在源码中。环境变量是操作系统在程序运行时提供的键值对,可以让同一份代码在不同电脑或部署环境中使用不同配置。

11.1 直接读取系统环境变量

读取可选值:

import osmodel_name = os.getenv("CHAT_MODEL", "demo-model")

os.getenv("CHAT_MODEL", "demo-model") 会读取 CHAT_MODEL;如果没有设置,就返回第二个参数提供的默认值。

在 macOS 或 Linux 的终端中,可以先临时设置变量,再启动当前程序:

export CHAT_MODEL="echo-model"python3 main.py

在 Windows PowerShell 中可以写:

$env:CHAT_MODEL = "echo-model"py main.py

这些设置只影响当前终端会话,以及由这个终端启动的程序。关闭终端后配置是否保留,取决于是否将它写入系统或终端的配置文件。

读取必填配置时,还要检查它是否有效:

api_key = os.getenv("AI_API_KEY")if api_key is None or not api_key.strip():    raise ValueError("缺少环境变量 AI_API_KEY")

环境变量没有“整数类型”:只要变量存在,os.getenv() 读到的就是字符串。因此,整数配置既要转换类型,也要检查取值范围:

max_history_text = os.getenv("MAX_HISTORY", "50")try:    max_history = int(max_history_text)except ValueError as error:    raise ValueError("MAX_HISTORY 必须是整数") from errorif max_history <= 0:    raise ValueError("MAX_HISTORY 必须大于 0")

11.2 使用 python-dotenv 读取 .env

每次都在终端中手动设置环境变量并不方便。在本地开发中,项目通常会把模型名称、模型 Token 和其他配置写入项目根目录的 .env 文件,再在程序启动时加载。

.env 不是 Python 标准库能够自动识别的文件。这里使用第三方包 python-dotenv 读取它,先安装依赖:

python -m pip install python-dotenv

一个简单的项目结构如下:

chat_project/├── .env├── .env.example├── .gitignore└── main.py

在 .env 中写入本机使用的配置:

AI_API_KEY=your-model-token-hereCHAT_MODEL=demo-modelMAX_HISTORY=50

等号两侧通常不需要空格,值也不必全部加引号。Token 中如果包含特殊字符,或值的首尾需要保留空格,可以使用引号包裹。

在 main.py 启动时先调用 load_dotenv(),再使用 os.getenv()

import osfrom pathlib import Pathfrom dotenv import load_dotenvproject_dir = Path(__file__).resolve().parentenv_file = project_dir / ".env"load_dotenv(dotenv_path=env_file)api_key = os.getenv("AI_API_KEY")model_name = os.getenv("CHAT_MODEL", "demo-model")max_history_text = os.getenv("MAX_HISTORY", "50")if api_key is None or not api_key.strip():    raise ValueError("缺少环境变量 AI_API_KEY")

不传路径时,load_dotenv() 会自动查找 .env。课程示例显式传入 project_dir / ".env",可以让文件位置更加清楚,也避免程序从不同目录启动时产生疑问。

默认情况下,.env 不会覆盖操作系统中已经存在的同名环境变量。这样,部署平台设置的真实环境变量可以优先于本地文件。除非确实需要改变优先级,否则不要随意使用 override=True

load_dotenv() 只负责把文件内容加载到进程环境中,读取后的值仍然都是字符串。整数转换、必填检查和取值范围验证仍然要由程序完成。

11.3 提供不含密钥的 .env.example

真实 .env 只属于本地环境,不应该提交到 Git。将它加入 .gitignore

.env.env.local

为了让其他开发者知道项目需要哪些配置,可以提交一份 .env.example

AI_API_KEY=CHAT_MODEL=demo-modelMAX_HISTORY=50

.env.example 只保留变量名和安全的示例值,不能包含任何真实 Token。其他开发者可以复制它并创建自己的 .env

12. 环境变量与密钥安全

把密钥放进环境变量,可以避免它直接出现在源码中,但并不意味着密钥从此绝对安全。仍然要遵守以下原则:

  • • 不把真实密钥写进课程示例。
  • • 将 .env 加入 .gitignore,不把密钥提交到 Git。
  • • .env.example 只保留变量名和安全的示例值。
  • • 不在日志和异常消息中输出密钥。
  • • 不把完整环境变量字典打印出来。
  • • 配置缺失时只提示变量名,不回显秘密值。

.env 是明文文件,主要适合本地开发。部署到服务器或云平台时,优先使用平台提供的环境变量或密钥管理服务,不要把本地 .env 直接复制到公共镜像或代码仓库。

13. 带标识和时间的消息模型

上一节使用 default_factory=list 为每个会话创建独立的列表。同样的机制也能确保每条消息在创建时获得新的 ID 和时间:

from dataclasses import dataclass, fieldfrom datetime import datetime, timezonefrom uuid import uuid4def create_id() -> str:    return str(uuid4())def utc_now() -> datetime:    return datetime.now(timezone.utc)@dataclassclass Message:    role: str    content: str    message_id: str = field(default_factory=create_id)    created_at: datetime = field(default_factory=utc_now)    def __post_init__(self) -> None:        self.role = self.role.strip().lower()        self.content = self.content.strip()        if self.role not in ("system", "user", "assistant"):            raise ValueError("消息角色无效")        if not self.content:            raise ValueError("消息内容不能为空")    def to_dict(self) -> dict[str, str]:        return {            "message_id": self.message_id,            "role": self.role,            "content": self.content,            "created_at": self.created_at.isoformat(),        }

这里不能在字段默认值中直接写 str(uuid4()) 或提前取得当前时间,原因是类体只执行一次,那样得到的值会被后续实例重复使用。使用 default_factory 后:

  • • 每次创建 Message,都会重新调用 create_id()
  • • 每次创建 Message,也会重新调用 utc_now()

这样,不同消息会拥有不同标识,时间也能反映各自的创建时刻。

14. 把标准库工具整合进对话核心

import loggingfrom collections import Counterfrom dataclasses import dataclass, fieldfrom uuid import uuid4logger = logging.getLogger(__name__)def create_id() -> str:    return str(uuid4())@dataclassclass ChatSession:    title: str    session_id: str = field(default_factory=create_id)    messages: list[Message] = field(default_factory=list)    def add_message(self, message: Message) -> None:        self.messages.append(message)        logger.info(            "消息已加入 session_id=%s role=%s message_count=%s",            self.session_id,            message.role,            len(self.messages),        )    def role_counts(self) -> dict[str, int]:        counts = Counter(            message.role            for message in self.messages        )        return dict(counts)    def recent_messages(self, limit: int = 5) -> list[Message]:        if limit <= 0:            raise ValueError("limit 必须大于 0")        return self.messages[-limit:].copy()

ChatSession 负责维护会话数据并统计消息。模型客户端与聊天服务继续沿用上一节建立的职责划分:

class ModelClient:    def generate(self, prompt: str) -> str:        raise NotImplementedError("子类必须实现 generate()")class EchoModelClient(ModelClient):    def __init__(self, model_name: str):        self.model_name = model_name    def generate(self, prompt: str) -> str:        logger.info(            "生成模拟回答 model=%s prompt_length=%s",            self.model_name,            len(prompt),        )        return f"模拟回复:{prompt}"class ChatService:    def __init__(        self,        session: ChatSession,        model_client: ModelClient,) -> None:        self.session = session        self.model_client = model_client    def ask(self, question: str) -> str:        user_message = Message("user", question)        self.session.add_message(user_message)        answer = self.model_client.generate(user_message.content)        self.session.add_message(Message("assistant", answer))        return answer

最后,在入口函数中读取配置、创建对象,再将它们组装起来:

import loggingimport osfrom pathlib import Pathfrom dotenv import load_dotenvdef main() -> None:    project_dir = Path(__file__).resolve().parent    load_dotenv(dotenv_path=project_dir / ".env")    log_dir = project_dir / "logs"    log_dir.mkdir(parents=True, exist_ok=True)    log_file = log_dir / "chat.log"    logging.basicConfig(        level=logging.INFO,        format="%(asctime)s %(levelname)s %(name)s %(message)s",        handlers=[            logging.StreamHandler(),            logging.FileHandler(log_file, encoding="utf-8"),        ],    )    model_name = os.getenv("CHAT_MODEL", "echo-model")    session = ChatSession("标准库练习")    client = EchoModelClient(model_name)    service = ChatService(session, client)    logger.info("应用已启动 log_file=%s", log_file.resolve())    answer = service.ask("标准库有什么作用?")    print(answer)    print(session.role_counts())if __name__ == "__main__":    main()

到这里,对话核心已经具备:

  • • 独立消息和会话 ID。
  • • 带时区的消息时间。
  • • 数据类模型。
  • • 可以替换的模型客户端。
  • • 角色统计。
  • • 同时写入终端和文件的结构化日志。
  • • 通过 .env 或系统环境变量提供的外部配置。

这些标准库工具没有打乱对象原有的职责,而是各自解决时间、标识、统计、日志和配置问题。下一步,可以继续使用上一章学过的 JSON 模块,保存 Message.to_dict() 的结果。

常见错误

跨系统交换数据时使用朴素时间

缺少时区信息会产生歧义。后端数据优先使用带时区的 UTC 时间。

把 UUID 当作安全令牌

标识与授权是不同问题。即使 ID 难以猜测,也必须单独检查访问权限。

在每个模块重复调用 basicConfig()

日志配置通常在程序入口完成一次,业务模块只获取 logger

以为日志会自动保存到文件

basicConfig() 在没有配置文件处理器时,默认只把日志输出到终端的标准错误流。需要持久保存时,必须显式配置 FileHandler,并提前创建日志目录。

使用不明确的相对日志路径

logging.FileHandler("chat.log") 会把文件写到当前工作目录,而当前工作目录取决于程序从哪里启动。可以基于 __file__ 构造稳定路径,并通过 resolve() 确认最终位置。

在日志中输出密钥或完整对话

只记录诊断所需的最小上下文,并对敏感字段做删除或遮盖。

创建 .env 后没有调用 load_dotenv()

os.getenv() 只读取进程中已有的环境变量。使用 .env 时,要先安装 python-dotenv,并在读取配置前调用 load_dotenv()

把真实 .env 提交到 Git

.env 中通常包含模型 Token 等敏感信息,应该加入 .gitignore。团队只共享不含真实密钥的 .env.example

动手练习

练习 1:消息标识与时间

为 Message 增加 UUID 字符串和 UTC 时间,创建三条消息,确认 ID 不同且时间包含时区。实现 to_dict() 并导出 JSON。

练习 2:统计与最近记录

使用:

  • • Counter 统计各角色数量。
  • • deque(maxlen=5) 保存最近五条命令。
  • • defaultdict(list) 按角色分组消息。

分别说明这些容器为什么比手动维护普通数据结构更合适。

练习 3:日志与环境配置

使用 python-dotenv 从 .env 加载 AI_API_KEYCHAT_MODEL 和 MAX_HISTORY

  • • 安装 python-dotenv,并在读取变量前调用 load_dotenv()
  • • 创建 .env.env.example 和 .gitignore,确保真实 .env 不会被提交。
  • • 缺少模型名称时使用安全的模拟默认值,缺少 Token 时给出明确错误。
  • • MAX_HISTORY 必须转换为正整数。
  • • 创建 logs/ 目录,把日志同时输出到终端和 logs/chat.log
  • • 启动、生成、保存和异常操作使用合适的日志级别。
  • • 启动时记录日志文件的绝对路径,确认文件实际保存位置。
  • • 日志中不出现消息全文或任何密钥。

随堂小测

  1. 1. 标准库与第三方包有什么区别?
  2. 2. 为什么后端时间通常使用带时区的 UTC?
  3. 3. isoformat() 和 fromisoformat() 分别做什么?
  4. 4. UUID 为什么比列表索引更适合作为持久标识?
  5. 5. Counter 访问不存在的键会得到什么?
  6. 6. deque(maxlen=3) 加入第四项时发生什么?
  7. 7. 日志与面向用户的 print() 有什么区别?
  8. 8. 只调用 basicConfig() 且不配置文件处理器时,日志默认输出到哪里?会自动生成日志文件吗?
  9. 9. 为什么创建 FileHandler 前通常要先创建日志目录?
  10. 10. logger.exception() 应在什么位置使用?
  11. 11. os.getenv() 返回的环境变量是什么类型?
  12. 12. 为什么 .env 文件不会自动被 os.getenv() 读取?应该怎样加载?
  13. 13. 默认情况下,系统环境变量和 .env 中出现同名变量时,哪个值优先?
  14. 14. .env 和 .env.example 分别应该保存什么?

参考答案

  1. 1. 标准库随 Python 提供;第三方包通常需要单独安装到环境中。
  2. 2. UTC 避免不同地区的本地时间歧义,带时区信息才能可靠转换。
  3. 3. 前者把时间转成标准字符串,后者从兼容字符串恢复时间对象。
  4. 4. 索引会随删除和排序改变,UUID 可以作为独立、低碰撞的长期标识。
  5. 5. 0
  6. 6. 最旧的一项自动移除,只保留最近三项。
  7. 7. print() 面向用户或临时观察;日志记录带级别和上下文的程序事件。
  8. 8. 默认输出到终端的标准错误流,不会自动生成日志文件。
  9. 9. FileHandler 可以创建日志文件,但不会创建缺失的父目录;目录不存在时会引发错误。
  10. 10. 正在处理异常的 except 代码块中。
  11. 11. 字符串;未设置且无默认值时得到 None
  12. 12. 标准库只读取进程环境,不会主动解析项目文件;可以先使用 python-dotenv 的 load_dotenv() 加载 .env
  13. 13. 已存在的系统环境变量优先;load_dotenv() 默认不会用 .env 覆盖它。
  14. 14. .env 保存本机实际配置且不能提交;.env.example 只保存变量名和安全示例,可以提交给团队参考。

最新文章

随机文章

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