我注意到以前在舊版 Django 中快速的查詢現在在 4.0.8 中要慢得多。
有一個相當大的表,帶有一個 FK“標記”和一個附有索引的布爾“標志”。以下查詢可以合理地回傳數萬行。
在我的代碼庫中,有一個類似的查詢
MyModel.objects.filter(marker_id=123, flag=False).count()
在 Django Debug Toolbar 中(當我檢查時也在 shell 中str(qs.query))它現在決議為以下 SQL 語法:
SELECT ??? FROM `myapp_mymodel` WHERE (`myapp_mymodel`.`marker_id` = 123 AND NOT `myapp_mymodel`.`flag`)
在極端情況下,此查詢會運行 20 秒左右。同時,在舊版 Django 版本(1.11 )中,相同的查詢變為以下 SQL:
SELECT ??? FROM `myapp_mymodel` WHERE (`myapp_mymodel`.`marker_id` = 123 AND `myapp_mymodel`.`flag` = 0)
這是可行的,因為表模式包含作為 TINYINT(1) 的“標志”,但最重要的是,它的運行速度要快得多 - 在一秒鐘內回傳。
編輯:我要求 sql server 解釋兩個查詢,并且在后一個(更快)查詢中作為潛在鍵出現的“標志”存在差異,但在較慢的查詢中沒有。這與這個答案一致,即mysql需要查看與值的比較才能知道使用索引。因此,主要問題變成了,如何強制使用已經存在的索引的語法?
結束編輯
原問題:為什么ORM-to-SQL的翻譯會有差異,在哪里可以找到負責的代碼(我檢查了db.backends.mysql無濟于事,或者未能識別罪魁禍首)? 有沒有辦法向 Django 暗示我更喜歡等于零的行為?
到目前為止,我看到的唯一解決方法是使用原始 SQL 查詢。如果可能的話,我寧愿避免這種情況。
uj5u.com熱心網友回復:
這是已經在 Django 的問題跟蹤器中報告并解決的回歸問題 #32691。
這在 Django 4.1 中已修復,因此如果您更新它將自動解決。對于 3.2 到 4.0 版本,您可以使用Todor Velichkov 在使用運算式的問題上指出的解決方法:Value()
from django.db.models import Value
MyModel.objects.filter(marker_id=123, flag=Value(0)).count()
uj5u.com熱心網友回復:
(MySQL/MariaDB,使用 ENGINE InnoDB)
這取決于索引是什么。
INDEX(flag)
僅當少于 20% 的行匹配時才可能使用。(20% 是近似值。)
INDEX(flag, ...)
其中額外的列可用于過濾,很可能用于 TRUE 或 FALSE。
請注意,在 InnoDB 中,PRIMARY KEY's列被隱式附加到索引的末尾。這變成INDEX(flag)可能INDEX(flag, id)允許上面的第二種形式是相關的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/526082.html
