Rendimiento de Django QuerySet vs Raw Query

He notado una gran diferencia de tiempo entre usar django connection.cursor y usar la interfaz del modelo, incluso con pequeños conjuntos de consultas. He hecho que la interfaz del modelo sea lo más eficiente posible, con values_list para que no se construyan objetos y demás. A continuación se muestran las dos funciones probadas, no importa los nombres en español.

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])

Luego, usando una función para cronometrar (self made with time.clock ())

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

Los resultados son los siguientes: 0.00180384529631 y 0.00493390727024 para t3 y t4

Y solo para asegurarse de que las consultas son y tomar lo mismo para ejecutar:

connection.queries[-2::]

Rendimientos:

[
    {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'}
]

Como puede ver, dos consultas exactas, que devuelven dos listas exactas (realizar r1 == r2 devuelve True), toma tiempos totalmente diferentes (la diferencia aumenta con un conjunto de consultas más grande), sé que Python es lento, pero Django está haciendo mucho trabajar detrás de escena para que la consulta sea más lenta? Además, solo para asegurarme, he intentado construir el objeto de conjunto de consultas primero (fuera del temporizador) pero los resultados son los mismos, por lo que estoy 100% seguro de que el tiempo extra proviene de buscar y construir la estructura de resultados. También intenté usar la función iterator () al final de la consulta, pero eso tampoco ayuda. Sé que la diferencia es mínima, ambos se ejecutan increíblemente rápido, pero esto se está aprovechando con apache ab, y esta diferencia mínima, cuando tiene 1k solicitudes simultáneas, hace que el día y la luz.

Por cierto, estoy usando django 1.7.10 con mysqlclient como conector db.

EDITAR: en aras de la comparación, la misma prueba con un conjunto de consultas de resultados de 11k, la diferencia se hace aún mayor (3 veces más lento, en comparación con el primero, donde es alrededor de 2.6 veces más lento)

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

EDIT2: Otra prueba divertida, si realmente convierto el objeto de conjunto de consultas en su consulta de cadena real (con str (queryset.query)), y lo uso dentro de una consulta sin formato, obtengo el mismo buen rendimiento que la consulta sin formato, por el La exención de que el uso de la cadena queryset.query a veces me da una consulta SQL no válida real (es decir, si el conjunto de consultas tiene un filtro en un valor de fecha, el valor de la fecha no se escapa con '' en la consulta de cadena, dando un error sql al ejecutar con una consulta en bruto, este es otro misterio)

- EDITAR3: Al recorrer el código, parece que la diferencia está marcada por la forma en que se recuperan los datos del resultado, para un conjunto de consultas sin procesar, simplemente llamaiter(self.cursor) que creo que cuando se usa un conector implementado en C se ejecutará todo en código C (ya que también está integrado), mientras que ValuesListQuerySet es en realidad un nivel de python para el bucle con una declaración de tupla de rendimiento (fila), que será bastante lento. Supongo que no hay nada que hacer en este asunto para tener el mismo rendimiento que el conjunto de consultas sin formato: '(. Si alguien está interesado, el bucle lento es este:

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

- EDITAR 4: He venido con un código muy hacky para convertir un conjunto de consultas de lista de valores en datos utilizables para enviar a una consulta sin formato, con el mismo rendimiento que ejecutar una consulta sin formato, supongo que esto es muy malo y solo funcionará con mysql, pero , la velocidad es muy buena y me permite mantener el filtro de la API del modelo y demás. ¿Qué piensas? Aquí está el código.

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

Respuestas a la pregunta(1)

Su respuesta a la pregunta