una rapida optimizar mas lentas hacer consultas consulta con como mysql join sql-order-by query-optimization

mysql - rapida - ¿Cómo hacer ORDER BY en JOIN consulta más rápido? Nada de lo que he probado ha funcionado.



optimizar consultas sql oracle (5)

Tengo la siguiente consulta de JOIN:

SELECT table1.*, table2.* FROM Table1 AS table1 LEFT JOIN Table2 AS table2 USING (col1) LEFT JOIN Table3 as table3 USING (col1) WHERE 3963.191 * ACOS( (SIN(PI() * $usersLatitude / 180) * SIN(PI() * table3.latitude / 180)) + (COS(PI() * $usersLatitude / 180) * COS(PI() * table3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)) ) <= 10 AND table1.col1 != ''1'' AND table1.col2 LIKE ''A'' AND (table1.col3 LIKE ''X'' OR table1.col3 LIKE ''X-Y'') AND (table2.col4 = ''Y'' OR table2.col5 = ''Y'') // Data Types of all columns in the query: // col1: int(11) // col2: char(1) // col3: varchar(3) // col4: char(1) // col5: char(1) // col6: int(11) // latitude: varchar(25) // longitude: varchar(25) // All 3 tables (table1, table2, and table3) are `MyISAM`.

Se ejecuta en menos de 0.15 segundos .

Sin embargo, si simplemente agrego:

ORDER BY table1.col6 DESC

Se ejecuta en más de 3 segundos .

Todas las columnas de la consulta están indexadas , incluido el table1.col6 utilizado en ORDER BY .

Aquí están los resultados de EXPLAIN EXTENDED SIN ORDER BY :

id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE table1 ALL PRIMARY,col2,col3 NULL NULL NULL 140101 72.61 Using where 1 SIMPLE table2 eq_ref PRIMARY,col4,col5 PRIMARY 4 table1.col1 1 100 Using where 1 SIMPLE table3 eq_ref PRIMARY PRIMARY 4 table1.col1 1 100 Using where

Y aquí están los resultados de EXPLAIN EXTENDED AND ORDER BY :

id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE table1 ALL PRIMARY,col2,col3 NULL NULL NULL 140101 72.61 Using where; Using filesort 1 SIMPLE table2 eq_ref PRIMARY,col4,col5 PRIMARY 4 table1.col1 1 100 Using where 1 SIMPLE table3 eq_ref PRIMARY PRIMARY 4 table1.col1 1 100 Using where

Lo que es extraño es que uso ORDER BY DESC en varias otras consultas en este sitio, y no lo ralentiza en ninguna parte tanto como con esta consulta en particular. Hay algo específico a esta consulta que está causando que se ralentice significativamente con el ORDER BY .

También hice una ANALYZE TABLE en las 3 tablas, y todas informaron que estaban OK . Luego reemplacé cada LIKE en la consulta con = y en realidad hice que la consulta SIN ORDER BY pasara de 0.2 segundos a 3 segundos . En otras palabras, reemplazar LIKE con = hace que la consulta original tome el mismo tiempo que agregar ORDER BY ! ¿Cómo es eso posible, considerando que LIKE hace más trabajo que = ? Tal vez ahí reside la clave de por qué el ORDER BY tarda tanto?

AQUÍ LO QUE HE TRATADO (SIN ÉXITO):

1) En lugar de SELECT table1.*, table2.* , Solo probé SELECT table1.col1 y aún SELECT table1.col1 más de 3 segundos en completarse.

2) Intenté agregar un índice compuesto en col1 , col2 , col6 y col6 en la Table1 , pero no mejoró la velocidad de ejecución.

3) Intenté esta solución de realizar la consulta como una subconsulta y luego envolver el ORDER BY fuera de él al final, pero no mejoró la velocidad de ejecución.

4) Probé la siguiente versión de la consulta, pero NO mejoró nada, y en realidad hice que la consulta tomara más de 3 segundos SIN que se agregara ORDER BY (quizás eso proporcione otra pista):

SELECT STRAIGHT_JOIN T1.*, T2.* FROM Table1 AS T1 JOIN Table2 AS T2 ON T1.Col1 = T2.Col1 AND ( T2.Col4 = ''Y'' OR T2.Col5 = ''Y'' ) JOIN Table3 as T3 ON T1.Col1 = T3.Col1 AND 3963.191 * ACOS( (SIN(PI() * $usersLatitude / 180) * SIN(PI() * T3.latitude / 180)) + ( COS(PI() * $usersLatitude / 180) * COS(PI() * T3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180) ) ) <= 10 WHERE T1.Col2 LIKE ''A'' AND ( T1.col3 LIKE ''X'' OR T1.col3 LIKE ''X-Y'') AND T1.Col1 != ''1'' ORDER BY T1.Col6 // With the following composite indexes: // On Table 1, index on ( Col2, Col3, Col1, Col6 ) // On Table 2, index on ( Col1, Col4, Col5 ) // Remember, all individual columns are already indexed.

...

¿Cómo puedo hacer que esta consulta obstinada se ejecute rápidamente CON ORDER BY ? ¿O es que simplemente no es posible?

EDITAR:

Resultados de SHOW CREATE TABLE para las 3 tablas:

CREATE TABLE `Table1` ( `col1` int(11) unsigned NOT NULL AUTO_INCREMENT, `col100` varchar(25) CHARACTER SET utf8 DEFAULT NULL, `col101` varchar(60) COLLATE utf8_bin DEFAULT NULL, `col102` varchar(50) CHARACTER SET utf8 DEFAULT NULL, `col103` varchar(10) COLLATE utf8_bin DEFAULT ''00000000'', `col104` date NOT NULL, `col105` int(3) DEFAULT NULL, `col106` varchar(25) COLLATE utf8_bin DEFAULT NULL, `col107` varchar(20) COLLATE utf8_bin DEFAULT ''Blah'', `col108` varchar(2) COLLATE utf8_bin DEFAULT ''No'', `col109` varchar(15) COLLATE utf8_bin DEFAULT ''Blah'', `col2` enum(''A'',''B'') COLLATE utf8_bin DEFAULT NULL, `col3` enum(''A'',''B'',''A-B'') COLLATE utf8_bin DEFAULT NULL, `col110` decimal(10,7) NOT NULL DEFAULT ''0.0000000'', `col111` decimal(10,7) NOT NULL DEFAULT ''0.0000000'', `col112` char(1) COLLATE utf8_bin DEFAULT ''N'', `col113` char(1) COLLATE utf8_bin DEFAULT ''N'', `col114` int(11) DEFAULT NULL, `col115` varchar(15) COLLATE utf8_bin DEFAULT ''Blah'', `col6` int(11) DEFAULT NULL, `col117` varchar(45) COLLATE utf8_bin DEFAULT NULL, `col118` varchar(2) COLLATE utf8_bin NOT NULL, `col119` tinyint(2) NOT NULL, `col120` int(6) NOT NULL, `col121` varchar(7) COLLATE utf8_bin NOT NULL, `col122` varchar(6) COLLATE utf8_bin NOT NULL, `col123` char(1) COLLATE utf8_bin NOT NULL DEFAULT ''A'', `col124` varchar(200) COLLATE utf8_bin NOT NULL, `col125` tinyint(4) NOT NULL, `col126` tinyint(1) NOT NULL, `col127` varchar(1) COLLATE utf8_bin NOT NULL DEFAULT ''A'', `col128` tinyint(1) NOT NULL DEFAULT ''0'', `col129` smallint(5) unsigned NOT NULL, `col130` varchar(1) COLLATE utf8_bin NOT NULL DEFAULT ''A'', `col131` int(11) NOT NULL, `col132` tinyint(1) NOT NULL, `col133` tinyint(1) NOT NULL, `col134` varchar(1) COLLATE utf8_bin NOT NULL, `col135` varchar(200) COLLATE utf8_bin NOT NULL, `col136` int(11) NOT NULL, `col137` int(10) unsigned NOT NULL, `col138` int(11) NOT NULL, `col139` tinyint(1) NOT NULL, `col140` tinyint(1) NOT NULL, `col141` tinyint(4) NOT NULL, `col142` varchar(25) COLLATE utf8_bin NOT NULL, `col143` varchar(25) COLLATE utf8_bin NOT NULL, `col144` tinyint(1) unsigned NOT NULL, `col145` tinyint(4) NOT NULL, PRIMARY KEY (`col1`), KEY `col2` (`col2`), KEY `col3` (`col3`), KEY `CompositeIndex0` (`col1`,`col2`,`col3`,`col6`), KEY `CompositeIndex1` (`col2`,`col3`,`col1`,`col6`), KEY `idx01` (`col1`,`col2`,`col3`) [19 other indexes that do not involve col1, col2, col3, or col6...] ) ENGINE=MyISAM AUTO_INCREMENT=160640 DEFAULT CHARSET=utf8 COLLATE=utf8_bin //*******************************************************// CREATE TABLE `Table2` ( `col1` int(11) unsigned NOT NULL DEFAULT ''0'', `col201` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT ''Blah'', `col202` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT ''Blah'', `col203` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col204` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col205` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col206` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col207` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col208` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col209` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col210` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col211` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col212` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col213` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col214` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col215` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col216` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col217` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col218` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col219` varchar(45) COLLATE utf8_bin DEFAULT ''Blah'', `col220` varchar(255) COLLATE utf8_bin DEFAULT ''Blah'', `col221` varchar(255) COLLATE utf8_bin DEFAULT ''Blah'', `col222` varchar(255) COLLATE utf8_bin DEFAULT ''Blah'', `col223` varchar(255) COLLATE utf8_bin DEFAULT ''Blah'', `col224` varchar(45) COLLATE utf8_bin DEFAULT ‘Blah’, `col225` varchar(255) COLLATE utf8_bin DEFAULT NULL, `col4` char(1) COLLATE utf8_bin DEFAULT ''A'', `col226` char(1) COLLATE utf8_bin DEFAULT ''A'', `col227` varchar(5) COLLATE utf8_bin DEFAULT ''Blah'', `col228` char(1) COLLATE utf8_bin NOT NULL, `col229` text COLLATE utf8_bin, `col5` char(1) COLLATE utf8_bin DEFAULT ''A'', `col230` varchar(255) COLLATE utf8_bin DEFAULT ''Blah'', `col231` varchar(255) COLLATE utf8_bin DEFAULT NULL, `col232` varchar(255) COLLATE utf8_bin DEFAULT NULL, `col233` varchar(255) COLLATE utf8_bin DEFAULT NULL, PRIMARY KEY (`col1`), KEY `col4` (`col4`), KEY `col5` (`col5`), KEY `CompositeIndex1` (`col1`,`col4`,`col5`), [4 other indexes not involving col1, col4, col5...] FULLTEXT KEY `col220` (`col220`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin //*******************************************************// CREATE TABLE `Table3` ( `col1` int(11) unsigned NOT NULL DEFAULT ''0'', `col300` varchar(255) COLLATE utf8_bin DEFAULT NULL, `latitude` varchar(25) COLLATE utf8_bin NOT NULL DEFAULT ''0'', `longitude` varchar(25) COLLATE utf8_bin NOT NULL DEFAULT ''0'', `col301` int(11) DEFAULT NULL, `static2` float(18,16) DEFAULT ''0.0000000000000000'', `static3` float(18,16) DEFAULT ''0.0000000000000000'', PRIMARY KEY (`col1`), KEY `latitude` (`latitude`), KEY `longitude` (`longitude`), KEY `static2` (`static2`), KEY `static3` (`static3`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin

EDIT 2:

A continuación se muestra mi archivo de configuración de MySQL . Entre otras cosas, tenga en cuenta cómo el sort-buffer-size se establece en 1M . De acuerdo con this , no debe establecerse por encima de 256K o puede ralentizar las cosas en "37x". Podría ser eso parte del problema?

# The MySQL database server configuration file. [mysqld] open-files-limit = 20000 thread-cache-size = 16 table-open-cache = 2048 table-definition-cache = 512 query-cache-type = 1 query-cache-size = 32M query-cache-limit = 1M sort-buffer-size = 1M read-buffer-size = 1M read-rnd-buffer-size = 8M join-buffer-size = 1M tmp-table-size = 64M max-heap-table-size = 64M back-log = 100 max-connections = 200 max-connect-errors = 10000 max-allowed-packet = 16M interactive-timeout = 600 wait-timeout = 180 net_read_timeout = 30 net_write_timeout = 30 back_log = 128 myisam-sort-buffer-size = 128M innodb-buffer-pool-size = 320M innodb-log-buffer-size = 4M innodb-log-file-size = 128M innodb-log-files-in-group = 2 innodb-file-per-table = 1 [mysqldump] max-allowed-packet = 16M

En una cuestión diferente, aquí están los RESULTADOS DE EXPLAIN EXTENDED EN LA ÚLTIMA PREGUNTA DE IVAN:

id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE T1 ref PRIMARY,col2,col3,col1,CompositeIndex1,idx01 CompositeIndex1 2 const 92333 Using where; Using filesort 1 SIMPLE T3 eq_ref PRIMARY PRIMARY 4 T1.col1 1 Using where 1 SIMPLE T2 eq_ref PRIMARY,CompositeIndex1,idx_static1 PRIMARY 4 T1.col1 1 Using where

En un asunto diferente, aquí hay algo MUY extraño. La siguiente versión de la consulta CON ORDER BY completa en solo 0.2 segundos :

SELECT STRAIGHT_JOIN T1 . * , T2 . * FROM Table3 AS T3 JOIN Table2 AS T2 ON T3.col1 = T2.col1 AND ( T2.col4 = ''Y'' OR T2.col5 = ''Y'' ) JOIN Table1 AS T1 ON T3.col1 = T1.col1 AND 3963.191 * ACOS( ( SIN( PI( ) * - 87.8819594 /180 ) * SIN( PI( ) * T3.latitude /180 ) ) + ( COS( PI( ) * - 87.8819594 /180 ) * COS( PI( ) * T3.latitude /180 ) * COS( PI( ) * T3.longitude /180 - PI( )* 37.1092162 /180 ) ) ) <=10 WHERE T1.col2 LIKE ''A'' AND ( T1.col3 LIKE ''X'' OR T1.col3 LIKE ''X-Y'' ) AND T1.col1 != ''1'' ORDER BY T1.col6 DESC

Básicamente, esta versión de la consulta realiza las tablas 1 y 2 de FROM Table3 AS T3 y JOIN mientras que la consulta original realiza las tablas FROM Table1 AS T1 y JOIN .

Aquí está EXPLAIN EXTENDED para la consulta anterior:

id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE T3 ALL PRIMARY NULL NULL NULL 141923 100 Using where; Using temporary; Using filesort 1 SIMPLE T2 eq_ref PRIMARY,col4,col5,CompositeIndex1 PRIMARY 4 T3.col1 1 100 Using where 1 SIMPLE T1 eq_ref PRIMARY,col2,col3,col1,CompositeIndex1,idx01 PRIMARY 4 T2.col1 1 100 Using where

Observe cómo esta consulta realmente hace AMBOS un filesort y un temporary frente a solo un filesort en las consultas originales y nuevas de Ivan. ¿Cómo puede ser 10 veces más rápido?

Aún más extraño, cambiar el orden de JOIN no parece mejorar ni la consulta original ni las nuevas consultas de Ivan. ¿Porqué es eso?


¿Cuál es el tipo de table1.col6? ¿Cuál es su diámetro de campo (longitud del valor máximo)?

BTW precalcula los valores, que no dependen de los valores de campo, como sugirió Ivan Buttinoni. No ayudará con el pedido, pero hará que la consulta sea más rápida


Bueno, te sugiero algunos estilos de la consulta:

  1. poner en donde las condiciones no se unen relacionadas, ver segunda consulta:

    Y (T1.col3 ME GUSTA "X" O T1.col3 ME GUSTA "X-Y")

  2. evitar O utilizar EN

  3. evitar como uso =

    Y T1.col3 IN (''X'', ''X-Y'')

  4. evitar el cálculo en donde

Crea algunas nuevas columnas para almacenar:

SIN(PI() * T3.latitude / 180) COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180) COS(PI() * T3.latitude / 180)

  1. preevaluar

    SIN (PI () * $ usersLatitude / 180) COS (PI () * $ usersLatitude / 180)

  2. Si todos estos "trucos" no pueden evitar la ordenación de archivos, forzar los índices

Sugerencia de índice de consultas mysql

ADEMÁS AÑADIR

para eliminar:

( T2.Col4 = ''Y'' OR T2.Col5 = ''Y'' )

en este caso, no puede usar IN , así que cree una nueva columna que sea el resultado de esta expresión.

alter table table2 add static1 bit default 0; alter table add index idx_static1(static1); update table2 t2 set static1=1 where ( T2.Col4 = ''Y'' OR T2.Col5 = ''Y'' ); alter table table3 add static2 float(18,16) default 0; update table3 set static2=SIN(PI() * T3.latitude / 180) where 1 alter table table3 add static3 float(18,16) default 0; update table3 set static3 = COS(PI() * T3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180) where 1

Si table1.col2 tiene pocos valores

alter table table1 change col2 col2 enum(''A'',''B'',''C'');

Si table1.col3 tiene pocos valores

alter table table1 change col3 col3 enum(''X'',''Y'',''X-Y'');

Cree un índice único para todas las columnas involucradas en donde alterar tabla agregue el índice idx01 (col1, col2, col3)

SELECT STRAIGHT_JOIN T1.*, T2.* FROM Table1 AS T1 JOIN Table2 AS T2 ON T1.Col1 = T2.Col1 JOIN Table3 as T3 ON T1.Col1 = T3.Col1 WHERE static1=1 AND T1.Col2 = ''A'' AND T1.col3 IN ( ''X'', ''X-Y'') AND T1.Col1 != 1 AND ACOS( ( $usersLatitude_sin_pi_fract180 * t3.static2 + $usersLatitude_cos_pi_fract180 * t3.static3 ) ) <= 0,00252321929476 -- this''s 10/3963.191 ORDER BY T1.Col6

Tu comentario me sugiere que tengas una intercalación diferente en la consulta (col1 es latin1_swedish y col2 es utf8) o tu conexión usa una intercalación diferente (tu conexión es utf-8 y consultas una columna latin1_german), así que cuando consultes:

t1.col2 = ''A''

Mysql tiene que convertir de utf-8 a latin1 cada valor.

Vea también la sección de cotejo de la documentación de mysql.

Una forma rápida es convertir todos (columna, tabla, servidor, conexión, cliente) a la misma intercalación. El byte de singel será mejor si no necesita utf-8.

Tenga cuidado con mi error de tipo o error de sintaxis que podría hacer.

ADEMÁS AÑADIR 2

Reconstruí las tablas en una base de datos de prueba y arreglé estas columnas: t1.col2, t2.col3 no debe ser anulable , t1.col1 es principal y no puede ser nulo.

El índice "t1.CompositeIndex1" solo debe indexar: col2, col3, col1; Índice de una columna "orden por" es inútil o peor.

Creo static1 y creo un índice en t2.col1 y t2.static1 pero con mis 6 filas en DB no se usa (ver explicación más adelante). t2.static1 no debe ser anulable también.

También adapto la consulta al cotejo de las columnas:

SELECT T1.*, T2.* FROM Table1 AS T1 JOIN Table2 AS T2 ON ( T1.Col1 = T2.Col1 ) JOIN Table3 as T3 ON T1.Col1 = T3.Col1 WHERE ( T1.Col2 = ''A'' collate utf8_bin AND T1.col3 IN ( ''X'' collate utf8_bin , ''X-Y'' collate utf8_bin ) AND T1.Col1 != 1 ) and T2.static1=1 AND ACOS( ( 2.3 * T3.static2 + 1.2 * T3.static3 ) ) <= 0.00252321929476 ORDER BY T1.Col6

Aquí sigue la explicación extendida.

+----+-------------+-------+--------+-----------------------------------+-----------------+---------+----------------+------+----------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+--------+-----------------------------------+-----------------+---------+----------------+------+----------+-----------------------------+ | 1 | SIMPLE | T1 | ref | PRIMARY,col2,col3,CompositeIndex1 | CompositeIndex1 | 1 | const | 1 | 100.00 | Using where; Using filesort | | 1 | SIMPLE | T2 | eq_ref | PRIMARY,CompositeIndex1 | PRIMARY | 4 | testdb.T1.col1 | 1 | 100.00 | Using where | | 1 | SIMPLE | T3 | eq_ref | PRIMARY | PRIMARY | 4 | testdb.T1.col1 | 1 | 100.00 | Using where | +----+-------------+-------+--------+-----------------------------------+-----------------+---------+----------------+------+----------+-----------------------------+

¿Es lo mismo para las columnas: tipo de selección, tabla, tipo, clave, ref, filtrado, Extra?

Mis objetivos de optimización son: - ajustar las condiciones donde se encuentran en pocos índices - evitar cálculos - evitar la conversión de clasificación - evitar O - evitar NULL en donde condición

Ahora las malas noticias Parece que en las tablas tienes ~ 140K registros, y la consulta mediante el orden puede implicar el uso del enfoque del conjunto de archivos si la consulta involucra muchas filas, por lo que la respuesta final puede aumentar el búfer memsort como se sugiere por @mavroprovato.

ADEMÁS AÑADIR 3

Para evaluar la adecuación de key_buffer_size, visite http://dba.stackexchange.com

ADEMÁS AÑADIR 4

Creo que solo alguien en Oracle puede decir exactamente lo que sucede, pero tengo mi idea.

Creo que esta consulta es peculiar:

  1. Todas las tablas (t1, t2, t3) están unidas por clave principal
  2. Otras condiciones dependen solo de calcs (t3.colX)
  3. Algunas condiciones dependen solo por el índice (t1.colX)

Debido a 1 from_table_rows> = join1_table_rows> = join2_table_rows, por lo que menos filas devuelven de la tabla más rápido serán los 2 otros JOINs

El optimizador para evaluar el esfuerzo calculará una ecuación similar:

effort = num_rows*key_size/index_cardinality

(index_cardinality se muestra por phpmyadmin al lado de cada índice)

Debido a 2 esfuerzo es> = num_rows

Mi consulta debido a 3 la tabla1 (de la tabla) devuelve 92333 filas, tabla3 (join1_table) reducida a 1 (!) Fila, tabla2 mantiene 1 fila (esfuerzo ~ 3).

Tu consulta debido a 2 deberías tener un esfuerzo = 140000, pero por suerte para ti, el cálculo devuelve solo 1 resultados, por lo que tu consulta es extremadamente rápida

Demostración

En su consulta, al cambiar de "<= 10" (en condición de unión) a "<= 1000" o más, verá una disminución exponencial de los rendimientos.

En mi consulta, al cambiar de "<= 10" (en condición de unión) a "<= 1000" o más, verá una disminución lineal / logarítmica de los rendimientos.

ADEMÁS AÑADIR 5

Responda a la pregunta: ¿es demasiado grande el tamaño del búfer de clasificación?

pararse en el artículo, sí, pruebe un poco de tono, puede ser que pueda resolver el problema

Responde a la pregunta: ¿es imposible hacer una consulta rápida?

En mi humilde opinión no, es posible (incluso si sort-buffer-size no se resuelve).

Mi idea es bastante simple, y puede resumirse en esta mot: "Cirlce es agradable pero cuadrada es mejor".

En este momento, la mayor cardinalidad se encuentra en las coordenadas de la tabla 3, pero debido a la fórmula no es aplicable ningún índice. Entonces, en lugar de buscar todos los puntos dentro de un radio, puedes buscar todos los puntos dentro de un "cuadrado"

FROM table3 ... WHERE (t3.latitude-0.15) < $usersLatitude AND $usersLatitude < t3.latitude+0.15 AND t3.longitue - 0.15 < $usersLongitude AND $usersLongitude < t3.longitue + 0.15

para que pueda crear un índice en (t3.latitude, t3.longitue).

0.15 grados deben ser de 10 millas. Por supuesto, deberías arreglar los cálculos cerca del meridiano del cambio diurno y al lado de los polos.

Si necesita estrictamente un radio, puede volver a unir table3 con la fórmula de radio (vea el ejemplo a continuación) o, si es posible, ejecute (/ elabore) la fórmula hasta que pueda comparar directamente valores con columnas.

FROM table3 t3 JOIN table3 t3bis ON t3.id=t3bis.id ... WHERE (t3.latitude-0.15) < $usersLatitude AND $usersLatitude < t3.latitude+0.15 AND t3.longitue - 0.15 < $usersLongitude AND $usersLongitude < t3.longitue + 0.15 AND 3963.191 * ACOS( (SIN(PI() * $usersLatitude / 180) * SIN(PI() * t3bis.latitude / 180)) + ( COS(PI() * $usersLatitude / 180) * COS(PI() * t3bis.latitude / 180) * COS(PI() * t3bis.longitude / 180 - PI() * 37.1092162 / 180) ) ) <= 10

ADEMÁS AÑADIR 6

tema: las funciones compiladas lo hacen mejor

uso de la función RADIANES ()

degree * PI / 180 == radians(degree)

Uso de la extensión GIS de mysql.

Ver este artículo sobre la extensión MySQL GIS


Después de mucho ensayo y error, finalmente encontré la solución a mi pregunta.

Si colocamos la cláusula WHERE completa, excepto la parte que calcula el radio, fuera de la consulta original, obtendremos una consulta muy rápida que no usa temporary como cambiar el orden de la JOIN :

SELECT * FROM { SELECT col1, col2, col3, col4, col5, col6 FROM Table1 AS table1 LEFT JOIN Table2 AS table2 USING (col1) LEFT JOIN Table3 as table3 USING (col1) WHERE 3963.191 * ACOS( (SIN(PI() * $usersLatitude / 180) * SIN(PI() * table3.latitude / 180)) + (COS(PI() * $usersLatitude / 180) * COS(PI() * table3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)) ) <= 10 ) AS sub WHERE col1 != ''1'' AND col2 LIKE ''A'' AND (col3 LIKE ''X'' OR col3 LIKE ''X-Y'') AND (col4 = ''Y'' OR col5 = ''Y'') ORDER BY col6 DESC

Esencialmente, esta consulta primero obtiene los resultados de JOIN de las 3 tablas en función del radio, y solo luego aplica el resto de los filtros para obtener los resultados que necesitamos. Esta versión de la consulta devuelve exactamente los mismos resultados que mi consulta original, pero se ejecuta en solo 0.2 segundos en lugar de 3 segundos para mi consulta original.

Aquí está la EXPLAIN EXTENDED para ello:

id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY <derived2> ALL NULL NULL NULL NULL 43 100 Using where; Using filesort 2 DERIVED T3 ALL PRIMARY NULL NULL NULL 143153 100 Using where 2 DERIVED users eq_ref PRIMARY,col1,idx01 PRIMARY 4 T3.col1 1 100 2 DERIVED userProfile eq_ref PRIMARY,CompositeIndex1 PRIMARY 4 users.col1 1 100

Quería agradecer a Ivan Buttinoni por su excelente trabajo en esto. Encontró varias formas inteligentes de hacer esta consulta aún más rápido.

Moraleja de la historia: no es solo la cláusula ORDER BY que puede hacerse más rápido colocándola fuera de la consulta principal , también puede obtener una consulta más rápida colocando parte de la cláusula WHERE fuera de ella también en situaciones como esta.


Hay tres (3) cosas que veo que puedes hacer:

1) Refactorizar la consulta

2) Aplique ORDER BY en Table1 anteriormente en la consulta

3) Índice Table1 para apoyar refactor

Tal vez este ...

ALTER TABLE Table1 ADD INDEX col2_col6_ndx (col2,col6); SELECT table1.*, table2.* FROM ( SELECT * FROM Table1 WHERE col2=''A'' AND ORDER BY col6 DESC ) AS table1 LEFT JOIN ( SELECT * FROM Table2 WHERE (col4=''Y'' OR col5=''Y'') ) AS table2 USING (col1) LEFT JOIN Table3 as table3 USING (col1) WHERE table1.col1 != ''1'' AND table1.col3 IN (''X'',''X-Y'') AND 3963.191 * ACOS( (SIN(PI() * $usersLatitude / 180) * SIN(PI() * table3.latitude / 180)) + (COS(PI() * $usersLatitude / 180) * COS(PI() * table3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)) ) <= 10 ;

Aquí hay otra variación que intenta refactorizar la consulta para que solo las claves se recopilen primero (creando tablas temporales mucho más pequeñas) y luego se apliquen las UNIONES:

ALTER TABLE Table1 ADD INDEX col2613_ndx (col2,col6,col1,col3); ALTER TABLE Table2 ADD INDEX col4_col1_ndx (col4,col1); ALTER TABLE Table2 ADD INDEX col5_col1_ndx (col5,col1); SELECT table1.*, table2.* FROM ( SELECT table1.col1,table3.latitude,table3.longitude FROM ( SELECT col1 FROM Table1 WHERE col2=''A'' AND AND col3 IN (''X'',''X-Y'') ORDER BY col6 DESC ) AS table1 LEFT JOIN ( SELECT col1 FROM Table2 WHERE col4=''Y'' UNION SELECT col1 FROM Table2 WHERE col5=''Y'' ) AS table2 USING (col1) LEFT JOIN Table3 as table3 USING (col1) ) col1_keys LEFT JOIN Table1 table1 USING (col1) LEFT JOIN Table2 table2 USING (col1) WHERE 3963.191 * ACOS( (SIN(PI() * $usersLatitude / 180) * SIN(PI() * col1_keys.latitude / 180)) + (COS(PI() * $usersLatitude / 180) * COS(PI() * col1_keys.latitude / 180) * COS(PI() * col1_keys.longitude / 180 - PI() * 37.1092162 / 180)) ) <= 10 ;

Darle una oportunidad !!!


Prueba la primera consulta:

... FROM Table1 AS table1 USE INDEX (col6) LEFT JOIN Table2 AS table2 ...