suggest-indexes proposes composite indexes that include the primary key or a unique field
评估
调研方向
从 cli/orm_lens/query_analyzer.py 中的 suggest_indexes() 开始,那里可以用到 pk_name 和 target_model,然后阅读 _propose_indexes() 顶部的复合索引循环。构建一个唯一单列的集合(主键 PK、pk、带 primary_key=True 或 unique=True 的字段,以及 OneToOneFields),跳过包含其中任一列的复合索引,单字段逻辑保持不变。完成标准是:Story 复现只输出 ['status'] 和 ['title'],pk= 的行为与 id= 一致,并且 cli/tests/test_query_analyzer.py 以及 pytest、ruff、mypy 全部通过。
由索引模型根据 Issue 内容生成。
描述
Source: weblate — trans.Unit: models.Index(fields=['id', 'translation'])
What happens
filter(id=pk, title=title) seen twice gives models.Index(fields=['id', 'title']). The primary key is unique: an equality lookup on it returns at most one row, so the PK index already answers the query and a composite led by id only costs writes and disk. The same is true for any unique=True field.
_propose_indexes() uses already_indexed for single-field proposals only. The composite loop checks the M2M/reverse filter from #252/#263 and existing Meta groups, nothing else. pk= is folded into id before that, so both spellings hit it.
On weblate trans.Unit gets models.Index(fields=['id', 'translation']).
Repro
board/models.py
from django.db import models
class Story(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
status = models.CharField(max_length=20)
board/stats.py
from .models import Story
def by_id_and_title(pk, title):
return Story.objects.filter(id=pk, title=title).first()
def by_id_and_title_again(pk, title):
return Story.objects.get(id=pk, title=title)
def by_pk_and_status(pk, status):
return Story.objects.filter(pk=pk, status=status).exists()
def by_pk_and_status_again(pk, status):
return Story.objects.filter(pk=pk, status=status).first()
def by_slug_and_status(slug, status):
return Story.objects.filter(slug=slug, status=status).first()
def by_slug_and_status_again(slug, status):
return Story.objects.filter(slug=slug, status=status).exists()
$ orm-lens suggest-indexes board.Story
target: board.Story
proposed Meta.indexes (5):
models.Index(fields=['id', 'status']), # 2 composite filter sites
models.Index(fields=['id', 'title']), # 2 composite filter sites
models.Index(fields=['slug', 'status']), # 2 composite filter sites
models.Index(fields=['status']), # 4 filter sites
models.Index(fields=['title']), # 2 filter sites
Expected: only ['status'] and ['title']. The usage table can keep listing id + title etc.
Where
cli/orm_lens/query_analyzer.py
- line 497,
_propose_indexes(); the composite loop is right at the top of the function body; - line 309,
_indexed_single_fields(): buildsalready_indexed, but it also containsdb_index=Truefields and FKs, which are not unique, so it can't be reused as is; - line 598,
suggest_indexes():pk_name(line 675) andtarget_modelare both there.
Suggested fix
In suggest_indexes(), build the set of unique single columns: pk_name, "pk", every field with primary_key=True or unique=True (the _PK_TRUE_RE / _UNIQUE_TRUE_RE regexes are already in the module), and OneToOneFields (unique by definition). Pass it to _propose_indexes() as a new keyword argument and skip a composite combo that contains any of these names.
Don't touch the single-field and order_by logic.
How to test
cli/tests/test_query_analyzer.py: the repro gives exactly['status']and['title'].filter(pk=..., ...)is dropped the same asfilter(id=..., ...).- A model with
code = models.CharField(primary_key=True)drops a['code', 'title']composite. - A composite of two non-unique fields (
filter(title=..., status=...)) is still proposed. cd cli && python -m pytest -q,ruffandmypypass.
Difficulty: good first issue, one set and one if.
- 主要语言
- Python
- 星标
- 84
- 派生
- 13
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
- 提供 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
FROWNINGdev/django-orm-lens 的其他 Issue
-
`migration-risk` text output prints `app.None` for graph-level findings可能已有人在做 @phoenixbycaselka 今天认领。 未关闭bug good first issue python
难度 1/5 1-3 小时 新手友好度 88/100
FROWNINGdev/django-orm-lens#268 ·
-
Finish the Chinese rule reference — DOL001–DOL007可能重新可做 @harbinresearcher 于 64 天前认领,目前没有进行中的 PR。 未关闭documentation good first issue help wanted
难度 2/5 1-3 小时 新手友好度 68/100
FROWNINGdev/django-orm-lens#81 · 2 条评论 ·
-
Fields inherited from Django's `AbstractBaseUser` / `PermissionsMixin` / `AbstractUser` are missing未关闭bug good first issue python
难度 3/5 1-2 天 新手友好度 62/100
FROWNINGdev/django-orm-lens#267 ·
-
bug good first issue python
难度 3/5 半天 新手友好度 78/100
FROWNINGdev/django-orm-lens#266 ·
-
enhancement help wanted python
难度 4/5 3-5 天 新手友好度 35/100
FROWNINGdev/django-orm-lens#254 ·
查看 FROWNINGdev/django-orm-lens 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 62/100
roman-corgi/corgisim#327 ·
维护者通常 2 天内回复
-
[Bug]: opencode_go chat route drops reasoning_effort (even 'none'), while the same endpoint honors it via custom_llm_provider=openai可能已有人在做 @arvindkumar-ship-it 今天认领。 未关闭llm translation
难度 2/5 1-3 小时 新手友好度 70/100
BerriAI/litellm#51871 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
PolicyEngine backdates South Carolina’s EITC into 2015–2017可能已有人在做 @MaxGhenis 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 72/100
PolicyEngine/policyengine-us#10944 ·
维护者通常 2 天内回复
-
fix(frontend): resolve SSE parser crash on unhandled Ref methods and undefined actions identifier未关闭bug
难度 2/5 1-3 小时 新手友好度 75/100
kodokbakar/MiroFish-Local#94 ·
维护者通常 1 天内回复