Django QuerySet против производительности Raw Query

Я заметил огромную разницу во времени между использованием django connection.cursor и использованием интерфейса модели, даже с небольшими наборами запросов. Я сделал интерфейс модели максимально эффективным, используя values_list, чтобы объекты не создавались и тому подобное. Ниже приведены две протестированные функции, не обращайте внимания на испанские имена.

def t3():
    q = "select id, numerosDisponibles FROM samibackend_eventoagendado LIMIT 1000"
    with connection.cursor() as c:
        c.execute(q)
        return list(c)

def t4():
    return list(EventoAgendado.objects.all().values_list('id','numerosDisponibles')[:1000])

Затем с помощью функции времени (самостоятельно сделал с time.clock ())

r1 = timeme(t3); r2 = timeme(t4)

Результаты следующие: 0,00180384529631 и 0,00493390727024 для t3 и t4

И просто чтобы убедиться, что запросы выполняются и выполняются одинаково:

connection.queries[-2::]

Урожайность:

[
    {u'sql': u'select id, numerosDisponibles FROM samibackend_eventoagendado LIMIT 1000',  u'time': u'0.002'},
    {u'sql': u'SELECT `samiBackend_eventoagendado`.`id`, `samiBackend_eventoagendado`.`numerosDisponibles` FROM `samiBackend_eventoagendado` LIMIT 1000', u'time': u'0.002'}
]

Как вы можете видеть, два точных запроса, возвращающих два точных списка (выполнение r1 == r2 возвращает True), требуют совершенно разных временных интервалов (разница увеличивается с большим набором запросов), я знаю, что python медленный, но django делает так много работать за кулисами, чтобы сделать запрос медленнее? Кроме того, просто чтобы убедиться, я сначала попытался создать объект набора запросов (вне таймера), но результаты те же, поэтому я на 100% уверен, что дополнительное время приходит от извлечения и построения структуры результата. Я также пытался использовать функцию iterator () в конце запроса, но это тоже не помогает. Я знаю, что разница минимальна, обе выполняются невероятно быстро, но это сравнивается с apache ab, и эта минимальная разница при наличии 1k одновременных запросов делает день и свет легче.

Кстати, я использую django 1.7.10 с mysqlclient в качестве коннектора db.

РЕДАКТИРОВАТЬ: для сравнения, тот же тест с набором 11k результатов запроса, разница становится еще больше (в 3 раза медленнее, чем в первом, где примерно в 2,6 раза медленнее)

r1 = timeme(t3); r2 = timeme(t4)
0.0149241530889
0.0437563529558

РЕДАКТИРОВАТЬ 2: Еще один забавный тест, если я на самом деле преобразую объект queryset в его фактический строковый запрос (с помощью str (queryset.query)) и вместо этого использую его внутри необработанного запроса, я получаю такую ​​же хорошую производительность, что и необработанный запрос, Исключение составляет то, что использование строки queryset.query иногда дает мне действительный недопустимый запрос SQL (т. е. если в наборе запросов есть фильтр для значения даты, значение даты не экранируется с помощью '' в запросе строки, что приводит к ошибке sql при выполнении это с сырым запросом, это еще одна загадка)

- EDIT3: просматривая код, кажется, что разница заключается в том, как извлекаются данные результата, для необработанного набора запросов он просто вызываетiter(self.cursor) Я полагаю, что при использовании соединителя, реализованного на C, все будет выполняться в коде C (поскольку iter также является встроенным), тогда как ValuesListQuerySet на самом деле представляет собой уровень python для цикла с оператором yield tuple (row), который будет довольно медленным. Я думаю, что в этом вопросе ничего нельзя сделать, чтобы иметь такую ​​же производительность, как и у необработанного набора запросов: '(. Если кому-то интересно, медленный цикл такой:

for row in self.query.get_compiler(self.db).results_iter():
    yield tuple(row)

- РЕДАКТИРОВАТЬ 4: Я пришел с очень хакерским кодом для преобразования набора запросов списка значений в пригодные для использования данные для отправки в необработанный запрос, с той же производительностью, что и при выполнении необработанного запроса, я думаю, это очень плохо и будет работать только с mysql, но ускорение очень хорошее, позволяя мне сохранять фильтрацию API модели и тому подобное. Как вы думаете? Вот код

def querysetAsRaw(qs):
    q = qs.query.get_compiler(qs.db).as_sql()
    with connection.cursor() as c:
        c.execute(q[0], q[1])
        return c

Ответы на вопрос(1)

Ваш ответ на вопрос