2

MySQL を使用する Django でこのクエリが遅いのはなぜですか? OneToOne と ForeignKey で相互に関連する 3 つのモデルをフィルタリングしています。約 60k 行の DB に対する次のクエリは、完了するまでに約 300 秒かかります。

resutls = A.objects.filter(b__c__candy__icontains="gummybears")
results  # <-- 300 seconds

アプリ内のモデル:

class A(models.Model):
    b = models.OneToOneField(B, default=None)
    a_charfield = models.CharField(max_length=40, default='')

class B(models.Model):
    b_charfield = models.CharField(max_length=40, default='')
    primary_id = models.CharField(max_length=40, unique=True, primary_key=True, default='', null=False)

class C(models.Model):
    b = models.ForeignKey('B')
    candy = models.CharField(db_index=True, max_length=40, default='')

result.query を印刷すると、MySQL クエリが次のように表示されます (列名を * に結合しました)。

SELECT *
FROM `app_a` 
INNER JOIN `app_b` ON (`app_a`.`b_id` = `app_b`.`primary_id`) 
INNER JOIN `app_c` ON (`app_b`.`primary_id` = `app_c`.`b_id`) 
WHERE `app_c`.`candy` LIKE %gummybears%  
ORDER BY `app_a`.`id` DESC

私は2つの実用的なソリューションを持っています。

  1. B からの結果を values_list として取得し、A へのフィルター引数として使用します。 https://docs.djangoproject.com/en/dev/ref/models/querysets/#in パフォーマンスに関する考慮事項

    resutls = A.objects.filter(b__in=list(B.objects.filter(c__c_charfield__icontains="candy").values_list('pk', flat=True))
    
  2. postgresql に切り替えます。二重内部結合は 1 秒未満で機能しました
4

1 に答える 1

0

次のコードの先頭の % は、インデックスを使用する代わりに、クエリでテーブル全体のスキャンを実行するように強制します。キャンディー テーブルがメモリに収まらない場合は、しばらく時間がかかります。

WHERE `app_c`.`candy` LIKE %gummybears%  

B ツリー インデックスの特性のドキュメントを参照してください。

于 2013-10-13T22:07:34.053 に答える