简而言之:一个包含超过1600万条记录的表[大小为2GB].使用ORDER BY*primary_key时,使用SELECT的LIMIT偏移越高,查询变得越慢
所以
SELECT * FROM large ORDER BY `id` LIMIT 0, 30
Run Code Online (Sandbox Code Playgroud)
远远不及
SELECT * FROM large ORDER BY `id` LIMIT 10000, 30
Run Code Online (Sandbox Code Playgroud)
这也只能订购30条记录.所以这不是ORDER BY的开销.
现在,当获取最新的30行时,大约需要180秒.如何优化该简单查询?
该表包含大约一千万行.
for event in Event.objects.all():
print event
Run Code Online (Sandbox Code Playgroud)
这导致内存使用量稳定增加到4 GB左右,此时行快速打印.第一行打印之前的漫长延迟令我感到惊讶 - 我预计它几乎可以立即打印出来.
我也尝试过Event.objects.iterator()以同样的方式行事.
我不明白Django加载到内存中的原因或为什么会这样做.我希望Django的通过在数据库级别的结果迭代,which'd意味着结果将在大约(长时间的等待之后,而不是一次全部)以恒定的速率进行打印.
我误解了什么?
(我不知道它是否是相关的,但我使用PostgreSQL.)
默认情况下,MySQL ResultSet会在完成任何工作之前从服务器中完全检索.在巨大的结果集的情况下,这变得无法使用.我希望实际上从服务器中逐个检索行.
在Java中,按照这里的说明(在"ResultSet"下),我创建一个这样的语句:
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
Run Code Online (Sandbox Code Playgroud)
这在Java中很有效.我的问题是:有没有办法在python中做同样的事情?
我试过的一件事是一次将查询限制为1000行,如下所示:
start_row = 0
while True:
cursor = conn.cursor()
cursor.execute("SELECT item FROM items LIMIT %d,1000" % start_row)
rows = cursor.fetchall()
if not rows:
break
start_row += 1000
# Do something with rows...
Run Code Online (Sandbox Code Playgroud)
但是,较高的start_row似乎会变慢.
不,使用fetchone()而fetchall()不是改变任何东西.
我用来重现这个问题的天真代码如下所示:
import MySQLdb
conn = MySQLdb.connect(user="user", passwd="password", db="mydb")
cur = conn.cursor()
print "Executing query"
cur.execute("SELECT * FROM bigtable");
print "Starting loop"
row = cur.fetchone()
while row is not None:
print …Run Code Online (Sandbox Code Playgroud) 我有一个表,我在LIMIT和OFFSET之前进行ORDER BY,以便进行分页.
在ORDER BY列上添加索引会对性能产生巨大影响(与小LIMIT结合使用时).在一个500,000行表中,只要有一个小的LIMIT,我看到增加索引的10,000倍改进.
但是,索引对高OFFSET(即我的分页中的后续页面)没有影响.这是可以理解的:b树索引可以很容易地从头开始按顺序迭代但不能找到第n个项.
似乎有用的是计算的b树索引,但我不知道PostgreSQL中对这些的支持.还有其他解决方案吗?似乎优化大型OFFSET(特别是在分页用例中)并不是那么不寻常.
不幸的是,PostgreSQL手册简单地说"OFFSET子句跳过的行仍然必须在服务器内部计算;因此大的OFFSET可能效率低下."
当settings.DEBUG = True时,Django将SQL操作记录到内部缓冲区(无论是否记录到文件).因为我有长时间运行的进程来执行大量的数据库操作,所以这会导致程序的开发模式实例在内存消耗中迅速增长.
我想禁用内部SQL日志记录机制,同时保留settings.DEBUG开启我的开发:这可能吗?
Django版本1.3.0.
在使用大偏移LIMIT的mysql 时遇到性能问题SELECT:
SELECT * FROM table LIMIT m, n;
Run Code Online (Sandbox Code Playgroud)
如果偏移m量大于1,000,000,则操作非常慢.
我必须使用limit m, n; 我不能用类似的东西id > 1,000,000 limit n.
如何优化此声明以获得更好的性能?
我有一个任务需要每隔一段时间(每天一次,每周一次,无论如何)在我的数据库中的"大多数"对象上运行一次.基本上这意味着我有一些看起来像这样运行在它自己的线程中的查询.
for model_instance in SomeModel.objects.all():
do_something(model_instance)
Run Code Online (Sandbox Code Playgroud)
(请注意,它实际上是一个filter()而不是所有()但是我仍然最终选择了一大组对象.)
我遇到的问题是,运行一段时间之后线程被我的托管服务提供商杀死,因为我使用了太多内存.我假设所有这些内存使用正在发生,因为即使QuerySet我的查询返回的对象最初具有非常小的内存占用量,它最终会随着QuerySet对象model_instance在迭代它们时缓存每个内容而增长.
我的问题是," SomeModel以内存有效的方式迭代几乎每个数据库中的最佳方法是什么?" 或者我的问题是"如何从django查询集中取消缓存'模型实例?"
编辑:我实际上使用查询集的结果来构建一系列新对象.因此,我最终不会更新查询的对象.
我有一个tmp_drop_ids包含一列的表id,以及330万个条目.我想迭代表,每200个条目做一些事情.我有这个代码:
LIMIT = 200
for offset in xrange(0, drop_count+LIMIT, LIMIT):
print "Making tmp table with ids %s to %s/%s" % (offset, offset+LIMIT, drop_count)
query = """DROP TABLE IF EXISTS tmp_cur_drop_ids; CREATE TABLE tmp_cur_drop_ids AS
SELECT id FROM tmp_drop_ids ORDER BY id OFFSET %s LIMIT %s;""" % (offset, LIMIT)
cursor.execute(query)
Run Code Online (Sandbox Code Playgroud)
一开始运行良好(〜0.15s生成tmp表),但它会偶尔减速,例如大约300k票据开始需要11-12秒生成这个tmp表,再次大约400k.它基本上似乎不可靠.
我将在其他查询中使用这些ID,因此我认为将它们放在tmp表中的最佳位置.有没有更好的方法来迭代这样的结果?
django ×3
limit ×3
mysql ×3
performance ×3
postgresql ×3
sql ×3
python ×2
database ×1
django-orm ×1
logging ×1
offset ×1
sql-order-by ×1