django.db.utils.OperationalError:解析器堆栈溢出

时间:2015-08-30 19:12:22

标签: django python-3.x sqlite pypy

我有一个可重复使用的django应用程序,它应该支持python2.7python 3.xpypy。我在开始时在python 2.7开发了它,我的所有测试都运行得很好。我也让他们在python3.3工作。但我对python3.4pypypypy3有疑问;

django.db.utils.OperationalError: parser stack overflow

我的测试在sqlite3上运行。我检查了跟踪,我猜它是关于查询大小的。我找不到任何解决方案来解决这个问题。

我在我的sqlite3环境中覆盖了内置python3.4代码来pring哪个sql,它是否会引发错误。这真是个大sql。 这没关系,你不需要检查sql,我只是在这里发布它以显示它是多么大。这也可能比这更大。因为queryset正在for循环中运行时构建。

顺便说一下,正如我之前所说,python2.7python3.3没有问题。问题引起了他人的注意。

是否有任何配置可以解决这个问题?

这是sql:

SELECT "river_approvement".
"id", "river_approvement".
"content_type_id", "river_approvement".
"object_id", "river_approvement".
"field", "river_approvement".
"meta_id", "river_approvement".
"transactioner_id", "river_approvement".
"transaction_date", "river_approvement".
"status", "river_approvement".
"skip", "river_approvement".
"order", "river_approvement".
"enabled"
FROM "river_approvement"
INNER JOIN "river_approvementmeta"
ON("river_approvement".
    "meta_id" = "river_approvementmeta".
    "id") INNER JOIN "river_transition"
ON("river_approvementmeta".
    "transition_id" = "river_transition".
    "id") WHERE("river_approvement".
    "field" = ? AND "river_transition".
    "source_state_id"
    IN(SELECT AB0.
        "id"
        FROM "river_state"
        AB0 WHERE AB0.
        "id"
        IN(SELECT AA2.
            "destination_state_id"
            FROM "river_approvement"
            AA0 INNER JOIN "river_approvementmeta"
            AA1 ON(AA0.
                "meta_id" = AA1.
                "id") INNER JOIN "river_transition"
            AA2 ON(AA1.
                "transition_id" = AA2.
                "id") WHERE(AA0.
                "field" = ? AND AA2.
                "source_state_id"
                IN(SELECT Z0.
                    "id"
                    FROM "river_state"
                    Z0 WHERE Z0.
                    "id"
                    IN(SELECT Y2.
                        "destination_state_id"
                        FROM "river_approvement"
                        Y0 INNER JOIN "river_approvementmeta"
                        Y1 ON(Y0.
                            "meta_id" = Y1.
                            "id") INNER JOIN "river_transition"
                        Y2 ON(Y1.
                            "transition_id" = Y2.
                            "id") WHERE(Y0.
                            "field" = ? AND Y2.
                            "source_state_id"
                            IN(SELECT X0.
                                "id"
                                FROM "river_state"
                                X0 WHERE X0.
                                "id"
                                IN(SELECT W2.
                                    "destination_state_id"
                                    FROM "river_approvement"
                                    W0 INNER JOIN "river_approvementmeta"
                                    W1 ON(W0.
                                        "meta_id" = W1.
                                        "id") INNER JOIN "river_transition"
                                    W2 ON(W1.
                                        "transition_id" = W2.
                                        "id") WHERE(W0.
                                        "field" = ? AND W2.
                                        "source_state_id"
                                        IN(SELECT V0.
                                            "id"
                                            FROM "river_state"
                                            V0 WHERE V0.
                                            "id"
                                            IN(SELECT U2.
                                                "destination_state_id"
                                                FROM "river_approvement"
                                                U0 INNER JOIN "river_approvementmeta"
                                                U1 ON(U0.
                                                    "meta_id" = U1.
                                                    "id") INNER JOIN "river_transition"
                                                U2 ON(U1.
                                                    "transition_id" = U2.
                                                    "id") WHERE(U0.
                                                    "field" = ? AND U2.
                                                    "source_state_id"
                                                    IN( ? ) AND U0.
                                                    "object_id" = ? AND U0.
                                                    "content_type_id" = ? ))) AND W0.
                                        "object_id" = ? AND W0.
                                        "content_type_id" = ? ))) AND Y0.
                            "object_id" = ? AND Y0.
                            "content_type_id" = ? ))) AND AA0.
                "object_id" = ? AND AA0.
                "content_type_id" = ? ))) AND "river_approvement".
    "object_id" = ? AND "river_approvement".
    "content_type_id" = ? )

1 个答案:

答案 0 :(得分:0)

默认sqlite3 parser stack size是100个词汇项。他们认为"它很可能远远超出任何人理解的能力。。我在你的例子中看到了许多嵌套级别:15个parenheses,9" SELECT",9" WHERE",9" IN",5" AND&#34 ;。这是我可以用任何可能的解析器graologic在堆栈上想象的最小必要术语。也许连接或隐形的东西被计入,但100的大小是有道理的。可以使用选项YYSTACKDEPTH = -1或大正数来重新编译Sqlite3(-1是从100开始并每次加倍的动态深度堆栈),但它不是可重用公共应用程序的解决方案。

通过在AND之前移动复杂的术语(子选择)作为布尔表达式的第一项,可以稍微改进一下。它可以通过以下方式完成:

MyModel.objects. \
    filter(meta__transition__destination_state_id__in=
         MyModel.objects.filter(...)
    ).filter(field=...)

它可以将堆栈大小稍微提高5" AND" 100项。

您可能会在一个过滤器中使用包含更多条件的过滤器表达式:filter(field_1=value_1, field_2=value_2)filter(**{'field_1': value_1, 'field_2': value_2})相同。字典中项目的顺序取决于相应CPython版本中hash函数的实现,甚至取决于pypy上字典本身的实现细节。这就是为什么只有某些Python版本才会引发异常的原因。如果添加一个类似复杂的附加子选择,则每个Python都必须引发异常。

Django queryset使用的结果可以很容易地检查而不运行它:

print(my_complicated_queryset.query.get_compiler('default').as_sql())

'default'settings.DATABASES中的连接别名。