В моем MapperExtension.create_instance как я могу извлечь отдельные данные строки по имени столбца? - PullRequest
1 голос
/ 26 августа 2010

Я получил запрос, который возвращает достаточное количество строк, и обнаружил, что

  • В итоге мы отбрасываем большинство связанных экземпляров ORM;и
  • создание этих экземпляров, которые скоро будут выброшены, идет довольно медленно.

Поэтому я хотел бы создавать только те экземпляры, которые мне нужны!

К сожалению, я не могу сделать это, просто ограничив запрос;Мне нужно немного обработать «бизнес-логику» в каждой строке, прежде чем я укажу, выброшу ли я ее;Я не могу сделать это в SQL.

Поэтому я подумал, что мог бы использовать MapperExtension для обработки этого: я бы создал подкласс MapperExtension, а затем переопределил create_instance;этот метод проверяет данные строки и либо возвращает EXT_CONTINUE, если данные стоит встроить в экземпляр, либо ... что-то еще (что я еще не решил) в противном случае.

Во-первых, используется ли этот подходдаже имеет смысл?

Во-вторых, если это имеет смысл, я не понял, как найти нужные мне данные в аргументах, которые передаются create_instance.Я подозреваю, что он где-то там, но его трудно найти ... вместо того, чтобы получить строку, которая непосредственно соответствует конкретному классу, который меня интересует, я получаю строку, которая соответствует запросу сгенерированная SQLalchemy, которая оказывается довольно сложным соединением между (скажем) таблицами A, B и C.

Проблема в том, что я не знаю, какие элементы строки соответствуют полям в моемКласс ORM: я хочу иметь возможность вытащить (например, A.id, B.weight и C.height.

Я предполагаю, что где-то внутри аргументов mapper, selectcontext или class_ есть некое подобиеотображение между столбцами моей таблицы и смещений в строке.Но я еще не нашел только правильную вещь.Хотя я очень близко подошел.Например, я обнаружил, что selectcontext.statement.columns содержит имена сгенерированных столбцов ... но не имена интересующей меня таблицы. Например:

Column(u'A_id', UUID(), ...
...
Column(u'%(32285328 B)s_weight, MSInt(), ...
...
Column(u'%(32285999 C)s_height', MSInt(), ...

Итак: как мне сопоставить имена столбцов, такие как C.height, со смещениями в строке?

1 Ответ

1 голос
/ 04 сентября 2010

Строка принимает объекты Column в качестве индексов:

row[MyClass.some_element.__clause_element__()]

, но это приведет вас только к классам и конструкциям aliased (), к которым у вас есть доступ извне.Весьма вероятно, что это будет все, что вам нужно для этой части проблемы (даже если в конечном счете идея не сработает, читайте дальше).

Если в вашем утверждении были обернуты подзапросы, от использованиятакие вещи, как from_self () или join () для полиморфной цели, метод create_instance () не дает вам доступа к функциям перевода, которые вам понадобятся для этого.

Если вы пытаетесь добраться до строк, которые связаны с eagerload (), это совсем не то, что вы должны делать.eagerload () - это оптимизация загрузки коллекций.Если вы хотите, чтобы ваш запрос объединился между двумя таблицами, и вы хотите фильтровать объединенную таблицу, используйте join ().

Но, прежде всего, create_instance () относится к версии 0.1 SQLAlchemy, и я сомневаюсь, что кто-либо сомневается в этом.использует его для чего угодно, и у него нет возможности сказать «пропустить этот ряд».Он должен что-то вернуть, иначе маппер создаст экземпляр самостоятельно.Поэтому, независимо от того, насколько хорошо вы можете интерпретировать строку, здесь нет никакой ловушки для того, что вы хотите сделать.

Если бы я действительно хотел сделать такую ​​вещь, вероятно, было бы проще получить «обезьяну-патч» fetchall ()"метод возвращаемого ResultProxy для фильтрации строк и отправки его в Query.instances ().Любой результат может быть отправлен в этот метод.Хотя, если Query выполнил переводы и тому подобное для сопоставленных элементов selectable, ему также понадобился бы оригинальный QueryContext, чтобы знать, как переводить.Но я бы не стал беспокоиться об этом.

В целом, если скорость настолько критична к проблеме во всем этом, что создание объекта так важно, я бы сделал так, чтобыМне не нужны сопоставленные объекты для всей операции, или я бы использовал кэширование или генерировал нужные мне объекты вручную из набора результатов.Я также хотел бы убедиться, что у меня есть доступ ко всем целевым столбцам в выбираемой мной выборке, чтобы я мог повторно извлечь из строк результатов, что означает, что я либо не использую функции автоматической генерации подзапроса / псевдонима в ORM,или я использую язык выражений напрямую (если вы действительно жаждете скорости и хотите писать большие участки оптимизирующего кода, вам, вероятно, следует просто использовать язык выражений).

Итак, реальные вопросыВы должны спросить здесь:

  1. Вы убедились, что реальная разница в скорости - это создание объекта из ряда.Т.е. не выборка строки или выборка ее столбцов и т. Д.
  2. Есть ли в строке только некоторые дорогие столбцы, которые вам не нужны?Вы изучили deferred ()?
  3. Что это за бизнес-правила и почему они не могут быть выполнены в SQL, как хранимые процедуры и т. Д.
  4. Сколько тысяч строк вы действительно пропускаете здесь?что он настолько «медленный», что не «пропускает» их
  5. Исследовали ли вы методы присутствия объектов, такие как кэши в памяти, предварительные загрузки и т. д. Для многих сценариев это соответствует требованиям.
  6. Ничего из этого не работает, и вы действительно хотите взломать некоторый домашний код оптимизации.Так почему бы не использовать язык выражений SQL напрямую?Если в конечном итоге вы имеете дело только со слоем представления, строки результатов являются довольно дружественными (они допускают доступ в стиле «атрибут» и т. Д.) Или строят некоторую быструю процедуру «создания объекта» из него.ORM представляет собой очень специфический вариант использования языка выражений SQL, и если вам действительно нужно что-то гораздо более легкое, чем его, вам лучше его пропустить.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...