SQLAlchemy: Просканировать огромные таблицы с помощью ORM?

Просто подумать ... ради вызова ;-) будет ли это работать ... (для базовых массивов строк, чисел и т. Д.) Нет вложенных массивов

function diffArrays(arr1, arr2, returnUnion){
  var ret = [];
  var test = {};
  var bigArray, smallArray, key;
  if(arr1.length >= arr2.length){
    bigArray = arr1;
    smallArray = arr2;
  } else {
    bigArray = arr2;
    smallArray = arr1;
  }
  for(var i=0;i<bigArray.length;i++){
    key = bigArray[i];
    test[key] = true;
  }
  if(!returnUnion){
    //diffing
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = null;
      }
    }
  } else {
    //union
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = true;
      }
    }
  }
  for(var i in test){
    ret.push(i);
  }
  return ret;
}

array1 = "test1", "test2","test3", "test4", "test7"
array2 = "test1", "test2","test3","test4", "test5", "test6"
diffArray = diffArrays(array1, array2);
//returns ["test5","test6","test7"]

diffArray = diffArrays(array1, array2, true);
//returns ["test1", "test2","test3","test4", "test5", "test6","test7"]

Обратите внимание на сортировку скорее всего, будет не так, как указано выше ... но при желании вызовите .sort () для массива, чтобы отсортировать его.

39
задан grebneke 2 February 2014 в 20:46
поделиться

3 ответа

Хорошо, я просто нашел способ сделать это сам. При изменении кода на

session = Session()
for p in session.query(Picture).yield_per(5):
    print(p)

загружаются только 5 изображений за раз. Похоже, что по умолчанию запрос будет загружать все строки за раз. Однако я еще не понимаю отказ от ответственности по этому методу. Цитата из документации SQLAlchemy

ВНИМАНИЕ: используйте этот метод с осторожностью; если один и тот же экземпляр присутствует более чем в одном пакете строк, изменения атрибутов конечным пользователем будут перезаписаны. В частности, обычно невозможно использовать этот параметр с нетерпеливо загруженными коллекциями (т. Е. С любыми ленивыми = False), поскольку эти коллекции будут очищены для новой загрузки при обнаружении в последующем пакете результатов.

Так что при использовании yield_per на самом деле правильный способ (tm) сканировать большие объемы данных SQL при использовании ORM, когда это безопасно использовать?

52
ответ дан 27 November 2019 в 02:20
поделиться

Вы можете отложить получение изображения только при доступе. Вы можете сделать это по запросу. например

session = Session()
for p in session.query(Picture).options(sqlalchemy.orm.defer("picture")):
    print(p)

или вы можете сделать это в картографе

mapper(Picture, pictures, properties={
   'picture': deferred(pictures.c.picture)
})

. Как вы это делаете, описано в документации здесь

Если вы сделаете это в любом случае, изображение будет загружено только при доступе к атрибуту.

7
ответ дан 27 November 2019 в 02:20
поделиться

вот что я обычно делаю в этой ситуации:

def page_query(q):
    offset = 0
    while True:
        r = False
        for elem in q.limit(1000).offset(offset):
           r = True
           yield elem
        offset += 1000
        if not r:
            break

for item in page_query(Session.query(Picture)):
    print item

Это позволяет избежать различной буферизации, которую также делают DBAPI (например, psycopg2 и MySQLdb). Его по-прежнему нужно использовать надлежащим образом, если ваш запрос имеет явные JOIN, хотя с нетерпением загруженные коллекции гарантированно загружаются полностью, поскольку они применяются к подзапросу, который имеет фактический LIMIT / OFFSET.

Я заметил, что Postgresql принимает почти столько же long для возврата последних 100 строк большого набора результатов, как и для возврата всего результата (за вычетом фактических накладных расходов на выборку строк), поскольку OFFSET просто выполняет простое сканирование всего этого.

32
ответ дан 27 November 2019 в 02:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: