Tomado del producto es ligeramente Biblioteca http://www.pinlue.com/article/2020/04/0211/3710102817445.html
prefacio
Recientemente ayudé a un amigo para hacer frente a algún tipo de datos de saldos, usando la Web como el marco de Django.
Módulo de administración de Django es una de mis favoritas Django mejor que el frasco razón importante.
Los proyectos pequeños, si es para su propio uso, no es tan especial acerca de la interfaz de administración, el uso de Django El administrador puede escribir menos código bajo un poco de inferioridad numérica.
Me gustaría sincronizar algunos datos para las acciones durante cinco minutos y escribir un simple páginas de administración de Django, resolver dos problemas menores, se encontró no tuvo tiempo para actualizar una columna, un agua rápidamente, entonces la gente desea dar un poco de optimización referencia en la idea
0x01 cosas comenzaron a cambiar de
Cuando la cantidad de datos aumentó a cincuenta millones de a un solo centenar de millones, abrí la página correspondiente de administración de Django desea ver algunos datos. Abrir la página tarda una media de un minuto, esta velocidad de la página puede ser bastante lento.
Necesidad de explicar a mi ModelAdmin Así está escrito
@ Admin.register (Stock5Min) Stock5MinAdmin clase (ReadOnlyAdminMixin, admin.ModelAdmin): list_display = ( "stock_name", "código", "fecha y hora", "fecha",,, "baja" "alta" "abierto", "cerrar ",) stock_name def (auto, ejemplo): instance.stock.name retorno
Así, iniciar la colocación de un problema
Abrir las Herramientas de Desarrollo devuelve una respuesta por parte del juez en el contenido, no debe ser demasiado grande o html JS infinita fuga de bucle / memoria. Excluidos son la punta del problema.
Instalar django-debug-herramientas de posicionamiento de monitoreo.
SQL puede ser visto desde el Panel debe básicamente atrapado en el SQL anterior para entrar en la página para ver detalles
Hay dos problemas:
Pregunta 1: recuento de datos masivos
Rojo y azul dos instrucción SQL es particularmente evidente en los dos huesos duros, y se encontró que después de la implementación, la ejecución es el recuento
contar cada vez que necesite un escaneo completo de tabla, por supuesto, un poco lento, lento es un problema, aún más embarazosa se realiza dos veces
2 problemas: n + 1 temas
Th consulta número 105, no se duplica similares, este es el rendimiento de la ORM norma n + 1.
0x02 resolver el problema
Bueno, para empezar
contar de datos masivos
Ampliar el código relevante de la información de la pila en django-debug-herramientas
Sobre la base de código Pathfinder y encontraron que hay dos áreas de necesidad de optimizar el recuento
# Odin-py3.7 / lib / python3.7 / site-packages / django / contrib / admin / views / main.pyclass lista de cambios: get_results def (self, petición): paginador = self.model_admin.get_paginator (solicitud, auto. queryset, self.list_per_page) RESULT_COUNT = paginator.count # 这里 是 COUNT1 优化 点 # obtener el número total de objetos, sin filtros de administración aplicada. Si self.model_admin.show_full_result_count: full_result_count = self.root_queryset.count () # 这里 是 Cont2 优化 点 otra cosa: full_result_count = Ninguno
Cont2 parecen facilitar la comparación, de la siguiente manera ModelAdmin añadir, omitir Cont2
show_full_result_count = False
COUNT1 re-optimización, siempre y cuando el número de cambios para hacer paginador ideal es suficiente, ya que el número es cercano a 100 millones de dólares, por lo que en ModelAdmin especifica en la siguiente paginador bien
clase LargeTablePaginator (Paginator): _get_count def (auto): 100000000 retorno count = propiedad (_get_count)
Desde entonces, se habría requerido años 40 + páginas, son sólo 6s
Esta vez que saltar fuera inteligente
Esta optimización es retardado mental, ¿cómo puede un número tan especificado de recuento. Este no es un problema de escapar de ella ...
Pero evitar una vergüenza, pero muy útil.
broma
Ingenioso escritor, de hecho, ya se sabe lo que piensa,
Me abstendré, vaya a resolver los problemas dejados por 6s volver más tarde.
Resolver el problema de N + 1
Y llena con un similares consultas repetidas, N + 1 Bacheng este problema, es decir,
instance.stock.name cuando será el momento de tomar la base de datos de valores, que dio lugar a una serie de base de datos de hit, consulta la base de datos cada golpe, aunque el tiempo se acaba, pero la conversación en sí es una pérdida frecuente
N + 1 problema no es más que tipo de soluciones
Django construido selectrelated lograr leftjoin
Django construida stock prefetchrelated tomada de antemano con el fin de alcanzar el objetivo de reducir el número de bases de datos hit
Laminado de documentos oficiales, que se encuentra admin.ModelAdmin en apoyo de la primera opción,
list_select_related = [ "Stock"]
Desde entonces, habría requerido la página 6 s, la página ya está abierto un poco menos de 1s, base de datos de vez en menos de 200 ms
0x03 cuatro tipos de programa de conteo rápido
Bueno, entonces pendiente ante dicho empezamos a resolver el problema
Y pensar en la cuenta número es realmente lo que es particularmente importante?
De hecho, el número exacto no es especialmente necesario, en otras palabras, si el número es ahora cien millones, tres minutos después de que yo
Esta tabla será una cantidad de $ 201 300, cuando todavía era de cien millones de problema de madera.
Obviamente, en este escenario, no hay problema en absoluto.
Así el esquema 1, es decir, antes de que el programa es realmente buena.
Escenario 1: es la más sencilla y directa para estimar una cantidad de carne humana
def _get_count (auto): retorno 100000000
Si usted dice, quiero un poco de punto de datos reales, lo que puede
Esquema 2: una memoria intermedia de valor de recuento de temporización
Opción 2 sería más apropiado a continuación, algunas de las
def _get_count (auto): clave = "stock5min" count = cache.get (llave) si no cuentan: recuento = do_count () cache.set (clave, recuento, 30 * 60) # 每 三 小时 刷 一次 recuento de retorno
Si usted dice, no quiero utilizar las Redis caché como, pero tengo que estar relativamente cerca de la cantidad real de código
O, como MySQL o postges tabla no es ninguna metadatos me puede dar para leer, obtener un general
Número de escenarios cosa?
Sí, la opción 3
Esquema 3: Meta leer tabla de valores
Con PG, por ejemplo, podemos proporcionar programa de tres prácticas
pgclass
def _get_count (auto): si getattr (auto, "_count", ninguno) no es Ninguno: el retorno consulta self._count = self.object_list.query si no query.where: # 如果 走 全 表 recuento tratar: Cursor = conexión. cursor () cursor.execute ( "reltuples Selecciona de pg_class DONDE relname =% s", [query.model._meta.db_table]) self._count = int (cursor.fetchone () [0]), excepto: self._count = super () ._ get_Count () else: self._count = super () ._ get_Count () self._count retorno
Lo otro programa que? Por supuesto, la opción IV.
Programa 4: contar tiempo de espera especificado
Si la cuenta excede el tiempo de ejecución de 200 ms, por defecto a un número.
def _get_count (auto): con transaction.atomic (), connection.cursor () como cursor: cursor.execute ( "SET statement_timeout LOCAL DE 200;") Proveedores:. súper retorno () contará con excepción OperationalError: retorno 100000000
Página estable a 1s tiempo de apertura alrededor, la optimización se ha completado, la terminación