YOLO813

Django项目中ORM使用指定的sql语句提速30倍(强制索引)

    在django项目中一般都是使用ORM来操作sql语句,但是这带来了一个问题,例如:我在站点地图的代码中有这样一句:

def items(self):
  return NBA.objects.values("id").filter(display=1).order_by("id")

    这个转化成sql语句大概是这样子:

SELECT `nba`.`id` FROM `nba` WHERE `nba`.`display` = 1 ORDER BY `nba`.`id` ASC LIMIT 3441 OFFSET 535000

    本地测试一直都没问题,但是上传到服务器上结果发现了问题,输出的语句不知道为什么一直没用到联合索引idx_id_display,而使用联合索引的语句速度比未使用的情况下快30倍,实测USE INDEX (idx_id_display)

SELECT `nba`.`id` FROM `nba` USE INDEX (idx_id_display) WHERE `nba`.`display` = 1 ORDER BY `nba`.`id` ASC LIMIT 3441 OFFSET 535000

    这就带来了一个问题,如何在django的ORM中使用原生的sql语句,

    原本的代码:

class DetailSitemap(LimitSitemap):
    changefreq = "weekly"
    priority = 0.6
    def items(self):
        return NBA.objects.values("id").filter(display=1).order_by("id")

    def location(self, obj):
        return reverse("detail",args=[obj.get('id')])
    def lastmod(self, obj):
        return datetime.now()

    修改的代码如下:

from django.db import connection

class DetailSitemap(LimitSitemap):
    changefreq = "weekly"
    priority = 0.6
    def items(self):
        query = "SELECT `nba`.`id` FROM `nba` USE INDEX (idx_id_display) WHERE `nba`.`display` = 1 ORDER BY `nba`.`id`"
        with connection.cursor() as cursor:
            cursor.execute(query)
            result = cursor.fetchall()
        return result

    def location(self, obj):
        return reverse("detail", args=[obj[0]])  

    def lastmod(self, obj):
        return datetime.now()

这里面其实还有一个问题,就是修改后的代码在数据库文件中其实少了ASC LIMIT 5000 OFFSET 1540000这种偏移量,但是我在实际测试站点地图页面的时候发现确实二者的返回页面结果都是一样的。