composer vendor目录扫描慢是因为每次composer show等命令需遍历vendor逐个解析composer.json,200+包耗时300–800ms;根本解法是启用并优化installed.sqlite:建复合索引、启用json1扩展,用sqlite json函数查询替代全量文件读取。

为什么 Composer 的 vendor 目录扫描慢得像在读磁盘日志
因为默认情况下,Composer 不索引本地包元数据——每次 composer show、composer depends 或插件调用 RepositoryManager::getLocalRepository() 时,它都要遍历整个 vendor/ 目录,逐个读取 composer.json 文件并解析 JSON。一个含 200+ 包的项目,光文件 I/O 就可能耗掉 300–800ms,且无法缓存中间结构。
直接改 vendor/composer/installed.php 不行,得动底层 SQLite
Composer 自 2.2 起已内置 SQLite 支持(通过 composer install --classmap-authoritative 后生成的 vendor/composer/installed.sqlite),但该文件仅用于类映射,不包含包名、版本、依赖关系等完整元数据。你要的是「可查询的包知识图谱」,不是「类路径查找表」。
- 别试图 patch
installed.php:它是 PHP 数组 dump,无索引、不可 JOIN、无法WHERE - 必须启用并扩展
installed.sqlite:它由Composer\Repository\InstalledRepository在安装/更新时写入,结构可控 - 关键字段要显式建索引:至少覆盖
name、version、type、require(JSON 字段)
给 installed.sqlite 加复合索引和 JSON1 支持
SQLite 默认不启用 json1 扩展,而包依赖关系存在 require 字段里(如 {"monolog/monolog": "^2.0"}),不用 JSON 函数就只能全表字符串匹配。同时,单列索引对 composer depends monolog/monolog 这类反向依赖查询无效。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 先确认 SQLite 编译支持:
php -r "var_dump(SQLite3::hasExtension('json1'));"→ 必须返回true - 执行以下语句(在
vendor/composer/installed.sqlite上运行):CREATE INDEX idx_pkg_name_ver ON packages(name, version); CREATE INDEX idx_pkg_type ON packages(type); CREATE INDEX idx_pkg_require ON packages(require) WHERE require IS NOT NULL;
- 对
require字段做前缀索引没用——JSON 值无固定前缀;真正有效的是后续用json_each(require)+json_tree配合虚拟表查询
查询时手写 SQLite JSON 查询,别依赖 Composer 原生方法
Composer 的 Package 类和 DependencyFilter 不知道你加了索引,也不会自动用 json_each()。所有提速逻辑必须落在你自己写的 CLI 命令或插件里。
- 查谁依赖
psr/log:SELECT name, version FROM packages p, json_each(p.require) j WHERE j.value = 'psr/log' OR j.key LIKE '%psr/log%';
- 查所有 type=library 的包:
SELECT name FROM packages WHERE type = 'library'(走idx_pkg_type) - 避免
LIKE '%monolog%'—— 它让idx_pkg_name_ver失效;改用name GLOB 'monolog/*'或全文检索 FTS5(需额外建表)
最易被忽略的是:SQLite 的 installed.sqlite 文件默认权限为 644,而 Composer 更新时会重写它;若你在外部进程并发读取,可能遇到「database is locked」或读到半写状态。要么加 PRAGMA journal_mode = WAL,要么确保所有查询在 post-install-cmd 后触发,而非实时监听文件变更。










