使用django从数据库中随机取N条记录的不同方法及其性能实测

Django + GraphQL 构建高并发短链服务实战 短链服务是一种典型的多维数据聚合型 Web 应用,其核心在于高效关联 URL、用户、访问日志、地域分布与设备类型等异构数据。传统 REST API 因接口粒度固定、N+1 查询频发、前端请求冗余等问题,在高并发读场景下易引发数据库连接池耗尽与响应延迟飙升。GraphQL 通过前端声明式字段获取,实现一次请求精准拉取所需数据;Django ORM 则凭借可组合的查询抽象与内置优化(如 select_related/prefetch_related),天然规避 N+1 问题,并支持无缝集成 Redis 缓存与 阅读详情

这里(stackoverflow)有一篇关于使用Django随机获取记录的讨论。

主要意思是说

  1. Record.objects.order_by('?')[:2]  

这样获取2个记录会导致性能问题,原因如下:

“

对于有着相当多数量记录的表来说,这种方法异常糟糕。这会导致一个 ORDER BY RAND() 的SQL查询。举个栗子,这里是MYSQL是如何处理这个查询的(其他数据库的情况也差不多),想象一下当一个表有十亿行的时候会怎样:

  1. 为了完成ORDER BY RAND() ,需要一个RAND()列来排序
  2. 为了有RAND()列,需要一个新表,因为现有的表没有这个列。
  3. 为了这个新表,mysql建立了一个带有新列的,新的临时表,并且将已有的一百万行数据复制进去。
  4. 当其新建完了,他如你所要求的,为每一行运行RAND()函数来填上这个值。是的,你派mysql创建一百万个随机数,这要点时间:)
  5. 几个小时或几天后,当他干完这活,他要排序。是的,你排mysql去排序一个一百万行的,最糟糕的表(说他最糟糕是因为排序的键是随机的)。
  6. 几天或者几星期后,当排序完了,他忠诚地将你实际需要的可怜的两行抓出来返回给你。做的好。;)

注意:只是稍微说一句,得注意到mysql一开始会试着在内存中创建临时表。当内存不够了,他将会把所有东西放在硬盘上,所以你会因为近乎于整个过程中的I/O瓶颈而雪上加霜。

怀疑者可以去看看python代码引起的查询语句,确认是ORDER BY RAND(), 然后去Google下"order by rand()"(带上引号)。

一个更好的方式是将这个耗费严重的查询换成3个耗费更轻的:

  1. last = MyModel.objects.count() - 1  
  2. # 这是一个获取两个不重复随机数的简单方法  
  3. index1 = randint(0, last)  
  4. index2 = randint(0, last - 1)  
  5. if index2 == index1:   
  6.     index2 = last  
  7. MyObj1 = MyModel.objects.all()[index1]  
  8. MyObj2 = MyModel.objects.all()[index2]  

”

如上Manganeez所说的方法,相应的获取n条记录的代码应该如下:

  1. sample = random.sample(xrange(Record.objects.count()),n)  
  2. result = [Record.objects.all()[i]) for i in sample]  
基于Python代码应该简洁优雅的想法,如上的代码似乎可以写成:

  1. result = random.sample(Record.objects.all(),n)  

就性能问题,请教了stackoverflow上的大神 (虽然被踩和被教育了=。=)


“
Record.objects.count() 将被转换成一个相当轻量级的SQL请求:

  1. SELECT COUNT(*) FROM TABLE  

Record.objects.all()[0]也会被转换成一个十分轻量级的SQL请求:

  1. SELECT * FROM TABLE LIMIT 1  
Querying all 是一个耗费十分严重的请求
  1. SELECT * FROM TABLE  


通常情况下Django会不显示其他的结果,这样你不会真正的获取到所有的记录。
  1. SELECT * FROM table LIMIT 20;  // or something similar  

任何时候你将一个Queryset转换成list的时候,将是资源消耗严重的时候。

如果我没错的话,在这个例子里,sample方法将把Queryset转换成list。

这样如果你result = random.sample(Record.objects.all(),n) 这样做的话,全部的Queryset将会转换成list,然后从中随机选择。

想象一下如果你有十亿行的数据。你是打算把它存储在一个有百万元素的list中,还是愿意一个一个的query?

”

在上边Yeo的回答中,freakish回复道:

“

.count的性能是基于数据库的。而Postgres的.count为人所熟知的相当之慢。

”


某人说过,要知道梨子的滋味,就得变革梨子,亲口尝一尝。

在一个已有的测试project中新建一个app,数据库是MYSQL:

  1. D:\PyWorkspace\DjangoTest>python manage.py startapp randomrecords  
在models.py中添加模型:

  1. class Record(models.Model):  
  2.     """docstring for Record"""  
  3.       
  4.     id = models.AutoField(primary_key = True)  
  5.     content = models.CharField(max_length = 16)  
  6.   
  7.     def __str__(self):  
  8.         return "id:%s content:%s" % (self.id, self.content)  
  9.     def __unicode__(self):  
  10.         return u"id:%s content:%s" % (self.id, self.content)  

添加一万行数据:

  1. D:\PyWorkspace\DjangoTest>python manage.py syncdb  
  2. Creating tables ...  
  3. Creating table randomrecords_record  
  4. Installing custom SQL ...  
  5. Installing indexes ...  
  6. Installed 0 object(s) from 0 fixture(s)  
  7.   
  8. D:\PyWorkspace\DjangoTest>python manage.py shell  
  9. Python 2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)] on win  
  10. 32  
  11. Type "help", "copyright", "credits" or "license" for more information.  
  12. (InteractiveConsole)  
  13. >>> from randomrecords.models import Record  
  14. >>> for i in xrange(10000):  
  15. ...   Record.objects.create(content = 'c of %s' % i).save()  
  16. ...  
15分钟以后我得到了这个MYSQL表。真的,不骗你,真的是15分钟。看了记录才知道 每次save都要调用一次insert和一次update。。。。下次一定用SQL语句初始化。。。。

先写了个脚本 在manage.py shell中调用了下 结果让我震惊了。

我表示不敢相信 又写了view 并添加了显示Query的log 

这里是写的view:

  1. def test1(request):  
  2.     start = datetime.datetime.now()  
  3.     result = Record.objects.order_by('?')[:20]  
  4.     l = list(result) # Queryset是惰性的,强制将Queryset转为list  
  5.     end = datetime.datetime.now()  
  6.     return HttpResponse("time: <br/> %s" % (end-start).microseconds/1000))  
  7.   
  8. def test2(request):  
  9.     start = datetime.datetime.now()  
  10.     sample = random.sample(xrange(Record.objects.count()),20)  
  11.     result = [Record.objects.all()[i] for i in sample]  
  12.     l = list(result)  
  13.     end = datetime.datetime.now()  
  14.     return HttpResponse("time: <br/> %s" % (end-start)  
  15.   
  16. def test3(request):  
  17.     start = datetime.datetime.now()  
  18.     result = random.sample(Record.objects.all(),20)  
  19.     l = list(result)  
  20.     end = datetime.datetime.now()  
  21.     return HttpResponse("time: <br/> %s" % (end-start)  

运行结果如下,第一行是页面显示的时间,后边是Queryset实际调用的SQL语句:

  1. test1:  
  2.   
  3. time: 0:00:00.012000  
  4.   
  5. (0.009) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  6. M `randomrecords_record` ORDER BY RAND() LIMIT 20; args=()  
  7. [05/Dec/2013 17:48:19] "GET /dbtest/test1 HTTP/1.1" 200 775  
  8.   
  9.   
  10.   
  11.   
  12. test2:  
  13.   
  14. time: 0:00:00.055000  
  15.   
  16. (0.002) SELECT COUNT(*) FROM `randomrecords_record`; args=()  
  17. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  18. M `randomrecords_record` LIMIT 1 OFFSET 6593; args=()  
  19. (0.001) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  20. M `randomrecords_record` LIMIT 1 OFFSET 2570; args=()  
  21. (0.001) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  22. M `randomrecords_record` LIMIT 1 OFFSET 620; args=()  
  23. (0.001) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  24. M `randomrecords_record` LIMIT 1 OFFSET 5814; args=()  
  25. (0.003) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  26. M `randomrecords_record` LIMIT 1 OFFSET 6510; args=()  
  27. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  28. M `randomrecords_record` LIMIT 1 OFFSET 3536; args=()  
  29. (0.001) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  30. M `randomrecords_record` LIMIT 1 OFFSET 3362; args=()  
  31. (0.003) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  32. M `randomrecords_record` LIMIT 1 OFFSET 8948; args=()  
  33. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  34. M `randomrecords_record` LIMIT 1 OFFSET 7723; args=()  
  35. (0.001) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  36. M `randomrecords_record` LIMIT 1 OFFSET 2374; args=()  
  37. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  38. M `randomrecords_record` LIMIT 1 OFFSET 8269; args=()  
  39. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  40. M `randomrecords_record` LIMIT 1 OFFSET 4370; args=()  
  41. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  42. M `randomrecords_record` LIMIT 1 OFFSET 6953; args=()  
  43. (0.001) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  44. M `randomrecords_record` LIMIT 1 OFFSET 1441; args=()  
  45. (0.000) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  46. M `randomrecords_record` LIMIT 1 OFFSET 772; args=()  
  47. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  48. M `randomrecords_record` LIMIT 1 OFFSET 4323; args=()  
  49. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  50. M `randomrecords_record` LIMIT 1 OFFSET 8139; args=()  
  51. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  52. M `randomrecords_record` LIMIT 1 OFFSET 7441; args=()  
  53. (0.001) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  54. M `randomrecords_record` LIMIT 1 OFFSET 1306; args=()  
  55. (0.001) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  56. M `randomrecords_record` LIMIT 1 OFFSET 5462; args=()  
  57. [05/Dec/2013 17:50:34] "GET /dbtest/test2 HTTP/1.1" 200 777  
  58.   
  59.   
  60.   
  61.   
  62. test3:  
  63.   
  64. time: 0:00:00.156000  
  65.   
  66. (0.032) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  67. M `randomrecords_record`; args=()  
  68. [05/Dec/2013 17:51:29] "GET /dbtest/test3 HTTP/1.1" 200 774  

令人难以置信的,在10000行的MYSQL表中 方法1的效率是最高的

无论是结果上看(12ms)还是SQL语句的运行时间上看(9ms)方法1甩了其他方法一大截


即便数据量增加到21万:

  1. time: 98  
  2.   
  3. (0.094) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  4. M `randomrecords_record` ORDER BY RAND() LIMIT 20; args=()  
  5. [05/Dec/2013 19:18:59] "GET /dbtest/test1 HTTP/1.1" 200 14  
  6.   
  7.   
  8. time: 0:00:00.668000  
  9. //这里没有注意到 掉了一行count语句  
  10. (0.045) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  11. M `randomrecords_record` LIMIT 1 OFFSET 176449; args=()  
  12. (0.016) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  13. M `randomrecords_record` LIMIT 1 OFFSET 68082; args=()  
  14. (0.036) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  15. M `randomrecords_record` LIMIT 1 OFFSET 145571; args=()  
  16. (0.033) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  17. M `randomrecords_record` LIMIT 1 OFFSET 111029; args=()  
  18. (0.043) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  19. M `randomrecords_record` LIMIT 1 OFFSET 169675; args=()  
  20. (0.046) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  21. M `randomrecords_record` LIMIT 1 OFFSET 186234; args=()  
  22. (0.043) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  23. M `randomrecords_record` LIMIT 1 OFFSET 167233; args=()  
  24. (0.015) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  25. M `randomrecords_record` LIMIT 1 OFFSET 54404; args=()  
  26. (0.036) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  27. M `randomrecords_record` LIMIT 1 OFFSET 140395; args=()  
  28. (0.004) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  29. M `randomrecords_record` LIMIT 1 OFFSET 13128; args=()  
  30. (0.039) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  31. M `randomrecords_record` LIMIT 1 OFFSET 153695; args=()  
  32. (0.034) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  33. M `randomrecords_record` LIMIT 1 OFFSET 131863; args=()  
  34. (0.021) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  35. M `randomrecords_record` LIMIT 1 OFFSET 82785; args=()  
  36. (0.015) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  37. M `randomrecords_record` LIMIT 1 OFFSET 57253; args=()  
  38. (0.021) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  39. M `randomrecords_record` LIMIT 1 OFFSET 77836; args=()  
  40. (0.049) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  41. M `randomrecords_record` LIMIT 1 OFFSET 199567; args=()  
  42. (0.002) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  43. M `randomrecords_record` LIMIT 1 OFFSET 3867; args=()  
  44. (0.027) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  45. M `randomrecords_record` LIMIT 1 OFFSET 104470; args=()  
  46. (0.026) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  47. M `randomrecords_record` LIMIT 1 OFFSET 107058; args=()  
  48. (0.043) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  49. M `randomrecords_record` LIMIT 1 OFFSET 150979; args=()  
  50. [05/Dec/2013 19:21:33] "GET /dbtest/test2 HTTP/1.1" 200 15  
  51.   
  52.   
  53. time 0:00:00.781000  
  54.   
  55. [05/Dec/2013 19:23:01] "GET /dbtest/test3 HTTP/1.1" 200 15  
  56. (0.703) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  57. M `randomrecords_record`; args=()  
  58. [05/Dec/2013 19:23:06] "GET /dbtest/test3 HTTP/1.1" 200 15  
方法1也会比其他两种方法快


数据量再次提升至百万级别 1066768条数据

  1. time:   
  2. 0:00:02.197000  
  3.   
  4. (2.193) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  5. M `randomrecords_record` ORDER BY RAND() LIMIT 20; args=()  
  6. [05/Dec/2013 20:00:55] "GET /dbtest/test1 HTTP/1.1" 200 26  
  7.   
  8.   
  9. time:   
  10. 0:00:02.659000  
  11.   
  12. (0.204) SELECT COUNT(*) FROM `randomrecords_record`; args=()  
  13. (0.180) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  14. M `randomrecords_record` LIMIT 1 OFFSET 703891; args=()  
  15. (0.038) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  16. M `randomrecords_record` LIMIT 1 OFFSET 156668; args=()  
  17. (0.013) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  18. M `randomrecords_record` LIMIT 1 OFFSET 50742; args=()  
  19. (0.031) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  20. M `randomrecords_record` LIMIT 1 OFFSET 121107; args=()  
  21. (0.033) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  22. M `randomrecords_record` LIMIT 1 OFFSET 130565; args=()  
  23. (0.017) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  24. M `randomrecords_record` LIMIT 1 OFFSET 66225; args=()  
  25. (0.234) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  26. M `randomrecords_record` LIMIT 1 OFFSET 922479; args=()  
  27. (0.267) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  28. M `randomrecords_record` LIMIT 1 OFFSET 1027166; args=()  
  29. (0.189) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  30. M `randomrecords_record` LIMIT 1 OFFSET 765499; args=()  
  31. (0.009) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  32. M `randomrecords_record` LIMIT 1 OFFSET 31569; args=()  
  33. (0.233) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  34. M `randomrecords_record` LIMIT 1 OFFSET 934055; args=()  
  35. (0.264) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  36. M `randomrecords_record` LIMIT 1 OFFSET 1052741; args=()  
  37. (0.155) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  38. M `randomrecords_record` LIMIT 1 OFFSET 621692; args=()  
  39. (0.014) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  40. M `randomrecords_record` LIMIT 1 OFFSET 52388; args=()  
  41. (0.199) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  42. M `randomrecords_record` LIMIT 1 OFFSET 759669; args=()  
  43. (0.170) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  44. M `randomrecords_record` LIMIT 1 OFFSET 655598; args=()  
  45. (0.035) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  46. M `randomrecords_record` LIMIT 1 OFFSET 139709; args=()  
  47. (0.228) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  48. M `randomrecords_record` LIMIT 1 OFFSET 919480; args=()  
  49. (0.104) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  50. M `randomrecords_record` LIMIT 1 OFFSET 422051; args=()  
  51. (0.017) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  52. M `randomrecords_record` LIMIT 1 OFFSET 67549; args=()  
  53. [05/Dec/2013 20:00:45] "GET /dbtest/test2 HTTP/1.1" 200 26  
  54.   
  55. time:   
  56. 0:00:19.651000  
  57.   
  58. (3.645) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  59. M `randomrecords_record`; args=()  
  60. [05/Dec/2013 20:02:50] "GET /dbtest/test3 HTTP/1.1" 200 26  

第三种方法所用时间长到令人无法接受 但有意思的是 SQL语句所花费的时间“只有”3.6秒。而大部分的时间都用在python上了。

既然第二种方法和第三种方法都需要random.sample 一个百万个数据的list,那就是说,有大量的时间花费在将SELECT到的结果转化为django对象的过程中了。

此后将不再测试第三种方法


最后,数据量增加到5,195,536个

  1. time:   
  2. 0:00:22.278000  
  3.   
  4. (22.275) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FR  
  5. OM `randomrecords_record` ORDER BY RAND() LIMIT 20; args=()  
  6. [05/Dec/2013 21:46:33] "GET /dbtest/test1 HTTP/1.1" 200 26  
  7.   
  8.   
  9. time:   
  10. 0:00:33.319000  
  11.   
  12. (1.393) SELECT COUNT(*) FROM `randomrecords_record`; args=()  
  13. (3.201) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  14. M `randomrecords_record` LIMIT 1 OFFSET 4997880; args=()  
  15. (1.229) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  16. M `randomrecords_record` LIMIT 1 OFFSET 2169311; args=()  
  17. (0.445) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  18. M `randomrecords_record` LIMIT 1 OFFSET 1745307; args=()  
  19. (1.306) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  20. M `randomrecords_record` LIMIT 1 OFFSET 3233861; args=()  
  21. (1.881) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  22. M `randomrecords_record` LIMIT 1 OFFSET 3946647; args=()  
  23. (1.624) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  24. M `randomrecords_record` LIMIT 1 OFFSET 3534377; args=()  
  25. (1.068) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  26. M `randomrecords_record` LIMIT 1 OFFSET 1684337; args=()  
  27. (0.902) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  28. M `randomrecords_record` LIMIT 1 OFFSET 2607361; args=()  
  29. (2.938) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  30. M `randomrecords_record` LIMIT 1 OFFSET 4872494; args=()  
  31. (0.493) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  32. M `randomrecords_record` LIMIT 1 OFFSET 851494; args=()  
  33. (3.275) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  34. M `randomrecords_record` LIMIT 1 OFFSET 5182414; args=()  
  35. (0.946) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  36. M `randomrecords_record` LIMIT 1 OFFSET 1684670; args=()  
  37. (0.701) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  38. M `randomrecords_record` LIMIT 1 OFFSET 1819730; args=()  
  39. (0.915) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  40. M `randomrecords_record` LIMIT 1 OFFSET 1626221; args=()  
  41. (1.809) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  42. M `randomrecords_record` LIMIT 1 OFFSET 3638682; args=()  
  43. (3.237) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  44. M `randomrecords_record` LIMIT 1 OFFSET 4801027; args=()  
  45. (1.187) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  46. M `randomrecords_record` LIMIT 1 OFFSET 1955843; args=()  
  47. (2.736) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  48. M `randomrecords_record` LIMIT 1 OFFSET 4835733; args=()  
  49. (1.705) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  50. M `randomrecords_record` LIMIT 1 OFFSET 2756641; args=()  
  51. (0.286) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content` FRO  
  52. M `randomrecords_record` LIMIT 1 OFFSET 1117426; args=()  

随着表中数据行数的增加,两个方法的所用的时间都到了一个完全不能接受的程度。两种方法所用的时间也几乎相同。

值得注意的是,Mysql数据库有一个特点是,对于一个大表,OFFSET越大,查询时间越长。或许有其他方法可以在offset较大的时候加快select的速度,然而django明显没有做到。如果能够减少这种消耗,方法2明显会优于方法1。


附上三种方法数据量和SQL时间/总时间的图






最后总结,Django下,使用mysql数据库,数据量在百万级以下时,使用

  1. Record.objects.order_by('?')[:2]  

来获取随机记录系列,性能不会比

  1. sample = random.sample(xrange(Record.objects.count()),n)  
  2. result = [Record.objects.all()[i]) for i in sample]  

差。

CentOS 7 + MariaDB + Django 生产部署全指南 关系型数据库是 Web 应用的核心数据底座,其选型直接影响系统稳定性、安全合规性与运维效率。MariaDB 作为 MySQL 的开源演进分支,完全兼容协议且深度适配 CentOS 7 等长期支持(LTS)发行版,成为 Django 生产环境的高性价比选择。它规避了 SQLite 并发能力弱、MySQL 企业版授权复杂、PostgreSQL 在 CentOS 7 上编译依赖多等常见痛点。结合 PyMySQL 驱动可实现零编译安装,配合 SELinux 精细策略、firewalld 端口管控及 Django 连 阅读详情

相关推荐

Django高并发扩展实战:uWSGI调优、多级缓存与异步任务架构

Django作为成熟Python Web框架,其‘开箱即用’特性常被误读为‘天然高并发’。实际上,Django的性能瓶颈不在框架本身,而在于默认配置与未经验证的IO链路——从uWSGI进程模型选择、数据库连接复用,到Redis分库缓存、Varnish整页加速,再到Celery异步解耦,每一层都需按请求生命周期精准编排。本文聚焦生产级Django扩展核心:通过prefork+async协程模型规避GIL阻塞,以radix tree优化token缓存key设计,结合Docker资源配额与Prometheus可观

weixin_34221036的博客 404

Django中数据查询方法

基本条件查询所需数据 email_code_list = EmailVerifyCode.objects.filter(email=email,send_type=3) #查询类型为3的对应邮箱情况 使用Q对象进行限制条件之间 “或” 连接查询 查询同一个表中多个字段满足一个即可的 from django.db.models import Q from .models import UserPr...

起风了 1024

Django网购数据可视化分析系统:从数据库到图表完整实现

数据可视化是理解业务数据的重要方式,它通过图表将原始数据转化为直观信息,帮助分析销售趋势与用户行为。其核心原理在于数据采集、存储、聚合与前端渲染的协同工作。在电商场景中,数据可视化系统能够直观展示订单金额、商品销量、类目占比等关键指标,为企业决策提供依据。本文以Django和MySQL为核心技术栈,结合ECharts图表库,完整讲解了一个网购数据可视化分析系统的设计与实现。从数据库表结构设计、ORM聚合查询、JSON接口封装到前端图表渲染,覆盖全链路开发流程。适合课程设计或毕业设计参考,也适合入门Pytho

weixin_30266885的博客 330

django开发之从数据库读取随机指定数量数据

django开发之从数据库读取随机指定数量数据 1、第一种方法(简单暴力) 在views.py方法中写入如下代码: if request.POST: charge_station_number = int(request.POST.get('standing', '')) stations_obj = models.Chargingstation.objec...

qq_41323150的博客 897

Django单元测试实战:TestCase与TestClient双引擎详解

单元测试是保障Web应用稳定性的核心工程实践,其本质是通过隔离环境、模拟交互、验证状态,实现对业务逻辑的可重复验证。在Django生态中,TestCase提供数据库事务级隔离能力,确保模型操作的纯净性;TestClient则模拟HTTP请求链路,覆盖路由、视图、响应全流程。二者协同构成‘逻辑+接口’双维度验证体系,显著提升API可靠性、重构安全性与团队协作效率。结合Factory Boy数据工厂、APIClient认证适配、assertNumQueries性能探针等关键技术,可系统化构建面向生产环境的高质量

weixin_30416871的博客 321

Python+Django构建施工项目资料数字化管理系统:架构设计与实战指南

在数字化转型浪潮中,企业级文档管理与业务流程的深度结合成为提升运营效率的关键。其核心原理在于通过结构化的数据模型、精细化的权限控制和自动化的工作流引擎,将传统静态文件转化为可关联、可追溯的动态数字资产。这一技术架构的价值在于打通信息孤岛,实现数据驱动的决策支持。在工程建筑、项目管理等强流程性行业,此类系统能有效解决资料散乱、协同困难、版本失控等痛点。本文聚焦于施工行业,探讨如何利用Python与Django框架,结合ORM、Admin后台及权限系统等热词技术,构建一个贴合分部工程验收、材料报验等专业场景的数

weixin_30466039的博客 355

使用Django从数据库中随机取N条记录的不同方法

Django下,使用mysql数据库,数据量在百万级以下时,使用 Record.objects.order_by('?')[:2] 来获取随机记录序列,性能不会比 sample = random.sample(xrange(Record.objects.count()),n) result = [Record.objects.all()[i]) for i in sample] 差。 参...

OneFine的技术博客 2614

Camera(5)metadata

Metadata 是整个 Android camera 中类似于高楼大厦中的管道系统一样,贯穿了整个 Camera 的 Framework 和 vendor HAL。Metadata 里面包含了所有的控制、参数、返回值等等。Metadata分为Android原生的Metadata和芯片商或者用户自定义的Metadata,即Android Tag和Vendor Tag。Vendor Tag在Hal中定义,并在camx和chi目录中使用。

qq_55893245的博客 3054

使用Django从数据库中随机取N条记录的不同方法及其性能实测

http://blog.jobbole.com/52852/

zheng_lan_fang的博客 2782

重塑计算的五层蛋糕:解读黄仁勋CES2026演讲背后的AI新秩序与物理世界

2026年CES演讲揭示AI新纪元:从语言模型到物理智能 NVIDIA CEO黄仁勋在2026年CES演讲中描绘了计算产业的根本性变革。核心突破包括: 计算范式转移:从指令执行转向意图理解,智能体系统崛起 物理AI突破:发布Cosmos世界模型,通过合成数据训练AI理解物理定律 全新VeraRubin计算平台:6芯片协同设计,解决摩尔定律放缓与AI需求增长的矛盾 自动驾驶革命:推出具备推理能力的Alpamayo模型,实现L4级自动驾驶 演讲标志着AI正从数字世界迈向物理世界,NVIDIA通过全栈布局,正在重

老孙 | Ethan Sun 的博客:AI 智能体与 AI 原生软件的工程实践 1275

《MySQL高级篇》十四、多版本并发控制

《MySQL高级篇》十四、多版本并发控制

LXYDSF的博客 3992

【转】使用Django从数据库中随机取N条记录的不同方法及其性能实测

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34132768的博客 305

避坑指南:SpringBoot对接拉卡拉支付常见问题与解决方案(含SDK 1.0.6配置技巧)

本文是一份SpringBoot项目对接拉卡拉支付的实战避坑指南。针对SDK 1.0.6版本,详细剖析了从依赖管理、多环境配置、SDK初始化到支付请求构建、回调验签及生产监控的全流程常见问题,并提供了经过验证的解决方案与配置技巧,旨在帮助开发者高效、稳定地集成支付功能。

k5l6m的博客 330

Python flask django开发的大学生兼职平台的设计与实现 2n5cv

Python版本:python3.7+前端:vue.js+elementui框架:django/flask都有,都支持后端:python数据库:mysql数据库工具:Navicat开发软件:PyCharm。

QQ242219979的博客 1363

从STM32转战小华HC32F448:手把手教你搞定串口复用与超时中断(附完整代码)

本文详细介绍了从STM32迁移到小华HC32F448的串口开发实战指南,重点解析了HC32F448的GPIO复用系统和超时中断机制。通过对比STM32的架构差异,提供了完整的串口配置代码和优化方案,帮助开发者快速掌握HC32F448的串口通信技术,适用于工业控制等应用场景。

weixin_30564901的博客 549

海康网口相机不能被flexscan3d识别到MVS版本为4.6.1,flex为3.3.24在MVS中能够检测到,但是在flex中只能看到电脑自带相机,如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 1045

django2.0.5 数据库的基本操作(不断整理中)

关于数据库的创建等相关步骤,请参考之前的文章,这里我们只做views.py中的操作分享。 针对mysql库(创建语句查看之前的django 博文): 注意,这里操作与在Python中使用原生的数据库操作是不同的。 使用Django从数据库中随机取N条记录的不同方法及其性能实测参考:http://blog.jobbole.com/52852/ 首先从数据库中获取数据所有数据: de...

IT届的小学生 1042

全面解读AI Infra:架构、生态与未来趋势

文章摘要 大模型时代下,AI基础设施(AI Infra)成为关键技术基建,涵盖从数据准备到模型服务的全栈技术体系。文章系统解构了AI Infra的四层架构(硬件资源层、资源管理调度层、开发框架层、平台工具层),并分析了全球AI Infra生态图谱,包括云计算巨头、芯片厂商等全栈服务商,以及中国特色的多元竞合格局。通过对比Data Infra与AI Infra的核心差异,指出AI Infra更关注智能应用的规模化与自动化。文章还探讨了从传统数据设施向AI基础设施的转型路径,强调自主可控、软硬协同等发展趋势,为

技术引领业务创新 610

Django电商平台开发实战:核心模块与性能优化

Web开发框架Django以其强大的ORM和MTV架构闻名,特别适合快速构建数据密集型应用。在电商系统开发中,Django的模型关系(如ForeignKey、OneToOneField)能优雅处理商品SPU/SKU等复杂业务实体。通过select_related和prefetch_related优化查询性能,结合Redis缓存和Celery异步任务,可有效应对高并发场景。本文以在线购物平台为例,详解支付对接、库存管理等核心模块实现,特别分享使用Redis+Lua脚本保证库存扣减原子性、采用策略模式实现多支付

weixin_33829657的博客 424

MFC实现键盘钩子(附完整源码)

MFC实现键盘钩子(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 390

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

揭秘Django bulk_create慢如蜗牛的原因:如何实现千条数据秒级插入

解决Django bulk_create插入性能瓶颈,深入剖析批量提交慢的根源。通过调整批次大小、禁用自动事务、优化数据库配置,实现千条数据秒级写入。适用于日志处理、批量导入等场景,显著提升Django ORM批量操作效率,值得收藏。

simcode的专栏 942

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Python+Django实现协同过滤电影推荐系统

协同过滤是推荐系统中的经典算法,通过分析用户历史行为数据发现相似用户群体,进而预测用户偏好。其核心原理是基于用户-物品评分矩阵计算相似度,常用皮尔逊相关系数等方法解决数据稀疏性问题。在实际工程应用中,需要结合Django等高效框架处理数据存储、算法优化和系统部署等全流程问题。电影推荐场景特别适合验证协同过滤效果,开发者可以学习如何处理冷启动、优化计算性能等关键技术挑战。本文以Python技术栈为例,详细解析了从算法原理到工程实现的完整解决方案,对构建毕业设计级推荐系统具有实用参考价值。

weixin_30731305的博客 334

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Django+GraphQL构建安全可控的私有URL缩短服务

URL缩短服务本质上是轻量级Web路由与数据映射系统,其核心原理在于将长URL通过哈希或编码算法映射为短码,并在请求时完成毫秒级302重定向。技术价值体现在可控性、可审计性与内网部署能力,规避第三方SaaS的数据风险与接口限制。典型应用场景包括企业内部文档共享、营销UTM链路追踪、邮件系统兼容性优化及API集成嵌入。本文聚焦生产级实践,深度融合Django的安全中间件体系与GraphQL的精准数据获取能力,同时贯穿‘防注入’与‘base62’两大关键热词——前者覆盖从输入校验、URL协议白名单到重定向构造的

culi3182的博客 551

Python皮肤病推荐问诊导诊系统(Pycharm Flask Django Vue mysql)

随着数据科学的迅速发展,诸如机器学习,人工智能等新兴技术极大地方便了人们的生活。来越多的应用涉及到大数据,而这些大数据的属性、包括数量、速度、多样性等等都是呈现了大数据不断增长的复杂性。本项目旨在解决数据科学所依赖的数据来源的问题,帮助数据科学工作者获取更多更有价值的数据。1、学习系统开发和设计的技术相关知识和工作流程;2、学习使用 PYCHARM 工具编辑前后台代码;3、学习使用DJANGO/flask框架实现系统的开发;4、掌握使用 MySQL 创建和编辑数据库的方法;

QQ58850198的博客 1473

Django Web开发全流程实战:从MTV架构到生产部署

Web开发框架是构建现代网络应用的核心工具,它通过封装通用功能、提供标准化架构,帮助开发者高效实现业务逻辑。Django作为Python领域最成熟的Web框架,其MTV(Model-Template-View)架构模式清晰分离了数据、业务与展示层,遵循“不重复自己”的设计哲学,显著提升了代码可维护性与团队协作效率。在技术价值层面,Django的ORM系统实现了数据模型与数据库的无缝映射,内置Admin后台极大简化了数据管理界面的开发,而其“开箱即用”的特性覆盖了用户认证、表单处理、安全防护等Web开发常见需

weixin_34242331的博客 497
上一篇: Django 数据库查询优化
下一篇: Django性能数据优化
niushoahan
博客等级 码龄17年 7粉丝 15原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值