MySQL настройка запросов - PullRequest
       10

MySQL настройка запросов

1 голос
/ 22 декабря 2009

У меня есть запрос, который я сделал в представлении MYSQL. Этот конкретный вид является центральным для нашего приложения, поэтому мы смотрим на его настройку. Существует первичный ключ на Map_Id, User_No, X, Y. Я довольно комфортно настраиваю запросы к SQL-серверу, но не совсем уверен в том, как работает MySql в этом аспекте. Поможет ли добавить индекс, который охватывает точки и update_stamp? Чтения в этой таблице составляют 90%, поэтому, хотя в ней много вставок, она не сравнивается с количеством чтений.

Описание: Получить человека с наибольшим количеством очков для каждой координаты x, y на данной карте. Разберитесь с тем, у кого есть последняя отметка об обновлении, а затем с идентификатором пользователя.

    SELECT GP.Map_Id AS Map_Id,GP.User_No AS User_No,GP.X AS X,GP.Y AS Y, GP.Points AS Points,GP.Update_Stamp AS Update_Stamp
    FROM (Grid_Points GP LEFT JOIN Grid_Points GP2
         ON (
       (
        (GP2.Map_Id = GP.Map_Id) AND (GP2.X = GP.X) AND (GP2.Y = GP.Y) AND 
        ((GP2.Points > GP.Points) OR ((GP2.Points = GP.Points) AND (GP2.Update_Stamp > GP.Update_Stamp)) OR 
        ((GP2.Points = GP.Points) AND (GP2.Update_Stamp = GP.Update_Stamp) AND (GP2.User_No < GP.User_No)))
       )
  )
 )

WHERE ISNULL(GP2.User_No);

Ответы [ 2 ]

3 голосов
/ 22 декабря 2009

Ух ты, мужик, тебе действительно нравится использовать круглые скобки. : -)

Вы правы, составной индекс может помочь. Вы могли бы даже сделать это индексом покрытия. Возможно, я либо попробую использовать индекс Grid_Points(Map_Id,X,Y), либо индекс Grid_Points(Points,Update_Stamp,User_No).

Всегда проверяйте оптимизацию запросов с помощью EXPLAIN, чтобы узнать, использует ли оптимизатор ваш индекс. Прочтите этот раздел документации, пока не поймете загадочные примечания в отчете EXPLAIN.

Отчет EXPLAIN, вероятно, покажет вам, какой индекс он решит использовать. Вы должны знать, что MySQL использует только один индекс на таблицу в данном запросе.

Вот как я бы написал этот запрос, полагаясь на порядок приоритетов между AND и OR вместо множества вложенных скобок:

SELECT GP.Map_Id, GP.User_No, GP.X, GP.Y, GP.Points, GP.Update_Stamp
FROM Grid_Points GP LEFT JOIN Grid_Points GP2
  ON GP2.Map_Id = GP.Map_Id AND GP2.X = GP.X AND GP2.Y = GP.Y
    AND (
      GP2.Points > GP.Points
      OR
        GP2.Points = GP.Points
        AND GP2.Update_Stamp > GP.Update_Stamp
      OR
        GP2.Points = GP.Points
        AND GP2.Update_Stamp = GP.Update_Stamp
        AND GP2.User_No < GP.User_No
    )
WHERE GP2.User_No IS NULL;

Вы используете мой любимый метод для нахождения наибольшего числа групп в MySQL. MySQL не очень хорошо оптимизирует GROUP BY (часто используется временная таблица, которая сериализуется на диск), поэтому используемое левое решение для внешнего соединения обычно намного лучше, по крайней мере для MySQL. В других брендах СУБД это решение может не иметь такого преимущества.

1 голос
/ 22 декабря 2009

Я бы не сравнивал это с собой, я бы сделал это как «группа по», а затем, возможно, сопоставил бы, чтобы узнать, кто этот человек.

SELECT Map_Id, X, Y, max (Points) FROM Grid_Points GROUP BY Map_Id, X, Y;

Это даст вам таблицу Map_Id, X и Y, затем максимальные баллы.Затем вы можете присоединить эти результаты обратно к Grid_Points, чтобы определить, какой пользователь = к этим точкам.

...