Como o ORDER BY FIELD () no MySQL funciona internamente

37

Entendo como a ORDER BYcláusula funciona e como a FIELD()função funciona. O que eu quero entender é como os dois trabalham juntos para classificar. Como as linhas são recuperadas e como a ordem de classificação é derivada

+----+---------+
| id |  name   |
+----+---------+
|  1 | stan    |
|  2 | kyle    |
|  3 | kenny   |
|  4 | cartman |
+----+---------+ 

SELECT * FROM mytable WHERE id IN (3,2,1,4) ORDER BY FIELD(id,3,2,1,4)

A consulta acima resultará em

+----+---------+
| id |  name   |
+----+---------+
|  3 | kenny   |
|  2 | kyle    |
|  1 | stan    |
|  4 | cartman |
+----+---------+ 

algo semelhante a dizer ORDEM POR 3, 2, 1, 4

QUESTÕES

  • Como isso funciona internamente?
  • Como o MySQL obtém as linhas e calcula a ordem de classificação?
  • Como o MySQL sabe que precisa classificar pela coluna id?
itz_nsn
fonte
11
tente esta variação da sua consulta: SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);adicione ORDER BY fou ORDER BY FIELD(id,3,2,1,4)tente novamente.
precisa saber é o seguinte

Respostas:

64

Para o registro

SELECT * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);

deve funcionar também porque você não precisa solicitar a lista na WHEREcláusula

Quanto à forma como funciona,

  • FIELD () é uma função que retorna a posição do índice de uma lista delimitada por vírgula se o valor que você está procurando existir.

  • Os ORDER BYvalores são avaliados pelo que FIELD () retorna

Você pode criar todos os tipos de pedidos sofisticados

Por exemplo, usando a função IF ()

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0),FIELD(id,3,2,1,4);

Isso fará com que os 4 primeiros IDs apareçam no topo da lista. Caso contrário, ele aparecerá na parte inferior. Por quê?

No ORDER BY, você recebe 0 ou 1.

  • Se a primeira coluna for 0, faça com que qualquer um dos 4 primeiros IDs apareça
  • Se a primeira coluna for 1, faça com que apareça depois

Vamos virar com DESC na primeira coluna

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0) DESC,FIELD(id,3,2,1,4);

No ORDER BY, você ainda recebe 0 ou 1.

  • Se a primeira coluna for 1, faça com que tudo, menos os 4 primeiros IDs, apareçam.
  • Se a primeira coluna for 0, faça com que os 4 primeiros IDs apareçam na ordem original

SUA PERGUNTA REAL

Se você realmente quer informações internas sobre isso, vá para as páginas 189 e 192 do Livro.

MySQL Internals

para um mergulho profundo.

Em essência, há uma classe C ++ chamada ORDER *order(A ORDER BYárvore de expressão). In JOIN::prepare, *orderé usado em uma função chamada setup_order(). Por que no meio da JOINaula? Cada consulta, até mesmo uma consulta contra uma única tabela é sempre processado como um join (Veja meu post Existe uma diferença entre a execução de uma condição de junção e uma condição em que? )

O código fonte para tudo isso é sql/sql_select.cc

Evidentemente, a ORDER BYárvore vai realizar a avaliação de FIELD(id,3,2,1,4). Assim, os números 0,1,2,3,4 são os valores que estão sendo classificados enquanto carrega uma referência para a linha envolvida.

RolandoMySQLDBA
fonte
11
Esta é uma explicação excepcionalmente excelente. Usando esses métodos, consegui 3 pedidos, um primeiro valor primário que é o máximo do conjunto, depois pelo FIELD, depois por outra coluna para os que não estão no conjunto FIELD. Algo que eu não sonharia há algum tempo atrás. Obrigado por dedicar um tempo para realmente explicar como isso realmente funciona.
Lizardx 04/04
Suponha que haja Nvalores em ambos INe FIELD. Neste exemplo N=4. Entendo corretamente que esta consulta realizará pelo menos ~N^2operações. Porque cada FIELDcálculo faz ~Ncomparações uma vez para cada linha. Em caso afirmativo, isso é bastante lento para grandes Ntalvez não seja uma abordagem muito boa?
Gherman
@Herman A FIELD()função deve ser uma O(1)operação porque FIELD()possui um índice numérico id. Portanto, não vejo mais nada além O(n)de linhas. Não vejo FIELD()nenhuma operação iterativa como a GREATEST()necessária.
RolandoMySQLDBA 15/03
@RolandoMySQLDBA Meu argumento é que, se FIELDhouver Nargumentos para comparar, ele executará Ncomparações. De que outra forma ele irá comparar um número com Noutros números, se não estiver fazendo O(N)? A única possibilidade em que consigo pensar é em algum tipo de otimização por meio de uma estrutura de dados especial, como um hash ou uma árvore de argumentos. Na verdade eu sei que INtem essa otimização. Eu não sei FIELD. O que você quer dizer com "índice numérico"?
Gherman
11
Hey @RaymondNijland, A declaração CASE é mais compreensível.Para este caso, o açúcar sintático tem menos escrita.
RolandoMySQLDBA
1

Talvez isso esteja muito longe do código real, portanto, o nível não é baixo o suficiente do que você queria:

Quando o MySQL não pode usar o índice para recuperar dados em ordem classificada, ele cria uma tabela / conjunto de resultados temporário com todas as colunas selecionadas e alguns dados adicionais - um deles é algum tipo de coluna para armazenar os resultados do valor da expressão ORDER BY para cada linha - em seguida, envia essa tabela tmp para uma rotina "filesort" com informações sobre qual coluna classificar. Depois disso, as linhas estão na ordem de classificação, para selecioná-las uma a uma e retornar as colunas selecionadas.

jkavalik
fonte
Esta explicação não leva em consideração como a FIELDfunção é calculada. Receio que possa ter um impacto significativo no desempenho.
Gherman
@Gherman Acho que não, a menos que você esteja usando uma lista muito longa de argumentos (como a função é linear ao número de argumentos . O acesso a dados é uma ordem de magnitude mais lenta que as comparações simples.
jkavalik
Sim, longa lista de argumentos. Existem tantos argumentos quanto registros neste exemplo.
Gherman
Eu
rotularia
por que não centenas de resultados? São muitos?
Gherman