2015-08-30 49 views
0

我有一個可重用的django應用程序,它應該支持python2.7python 3.xpypy。我在一開始就在python 2.7中開發了它,並且我的所有測試都很有效。我也讓他們在python3.3也工作。但我有一個問題python3.4pypy,pypy3;django.db.utils.OperationalError:解析器堆棧溢出

django.db.utils.OperationalError: parser stack overflow 

我的測試運行在sqlite3。我檢查跟蹤,我可以猜測它是關於查詢大小。我找不到解決此問題的任何解決方案。

我覆蓋了內建的sqlite3代碼在我的python3.4環境中,以檢查哪個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" = ?) 
+0

您是否在同一個系統上看到過不同,它是從源代碼編譯更多的Python版本,還是在不同的系統上使用不同的'/ usr/lib/libsqlite3.so *'? – hynekcer

回答

0

默認sqlite3 parser stack size是100個詞項。他們認爲「這很可能超出了任何人理解」「的能力。我在你的例子中看到很多嵌套的層次:15個parenheses,9「SELECT」,9「where」,9「in」,5「和」。這是我可以在任何可能的語法分析器中使用的必要條件的最小值。也許還有加入或不可見的東西被計入,但尺寸100是合理的。 Sqlite3可以用選項YYSTACKDEPTH = -1或一個很大的正數(-1是一個動態深度堆棧,以100開頭並每次加倍)重新編譯,但它不是可重用公共應用程序的解決方案。

作爲布爾表達式的第一項,可以通過在AND之前移動複雜的項(子選擇)來改進一點。這是可以做到的:

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

它可以在100個項目提高堆棧大小還真有點5「AND」。

你probaby在一個過濾器中使用更多條件的過濾器表達式:filter(field_1=value_1, field_2=value_2)這與filter(**{'field_1': value_1, 'field_2': value_2})相同。字典中的項目順序取決於相應CPython版本中的hash函數的實現,甚至取決於pypy上字典本身的實現細節。這就是爲什麼只有在某些Python版本中才會引發異常。如果添加一個類似的複雜附加子查詢,每個Python都必須引發異常。

通過Django的使用的結果的SQL查詢集可以在不運行它可以容易地檢查:

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

'default'settings.DATABASES連接別名。