Устранить полное сканирование таблицы благодаря BETWEEN (и GROUP BY) - PullRequest
1 голос
/ 12 мая 2010

Описание

В соответствии с командой explain существует диапазон, при котором запрос выполняет полное сканирование таблицы (160 тыс. Строк). Как мне сохранить условия дальности и уменьшить сканирование? Я ожидаю, что виновником будет:

Y.YEAR BETWEEN 1900 AND 2009 AND

Код

Вот код с условием диапазона (STATION_DISTRICT, скорее всего, излишний).

SELECT                                                                  
  COUNT(1) as MEASUREMENTS,                                             
  AVG(D.AMOUNT) as AMOUNT,                                              
  Y.YEAR as YEAR,                                                       
  MAKEDATE(Y.YEAR,1) as AMOUNT_DATE                                     
FROM                                                                    
  CITY C,                                                               
  STATION S,                                                            
  STATION_DISTRICT SD,                                                  
  YEAR_REF Y FORCE INDEX(YEAR_IDX),                                     
  MONTH_REF M,                                                          
  DAILY D                                                               
WHERE                                                                   
  -- For a specific city ...                                            
  --                                                                    
  C.ID = 10663 AND                                                      

  -- Find all the stations within a specific unit radius ...
  --                                                        
  6371.009 *                                                
  SQRT(                                                     
    POW(RADIANS(C.LATITUDE_DECIMAL - S.LATITUDE_DECIMAL), 2) +
    (COS(RADIANS(C.LATITUDE_DECIMAL + S.LATITUDE_DECIMAL) / 2) *
     POW(RADIANS(C.LONGITUDE_DECIMAL - S.LONGITUDE_DECIMAL), 2)) ) <= 50 AND

  -- Get the station district identification for the matching station.
  --                                                                  
  S.STATION_DISTRICT_ID = SD.ID AND                                   

  -- Gather all known years for that station ...
  --                                            
  Y.STATION_DISTRICT_ID = SD.ID AND             

  -- The data before 1900 is shaky; insufficient after 2009.
  --                                                        
  Y.YEAR BETWEEN 1900 AND 2009 AND                          

  -- Filtered by all known months ...
  --                                 
  M.YEAR_REF_ID = Y.ID AND           

  -- Whittled down by category ...
  --
  M.CATEGORY_ID = '003' AND

  -- Into the valid daily climate data.
  --
  M.ID = D.MONTH_REF_ID AND
  D.DAILY_FLAG_ID <> 'M'
GROUP BY
  Y.YEAR

Обновление

SQL выполняет полное сканирование таблицы, в результате чего MySQL выполняет «копирование в таблицу tmp», как показано здесь:

+----+-------------+-------+--------+-----------------------------------+--------------+---------+-------------------------------+--------+-------------+
| id | select_type | table | type   | possible_keys                     | key          | key_len | ref                           | rows   | Extra       |
+----+-------------+-------+--------+-----------------------------------+--------------+---------+-------------------------------+--------+-------------+
|  1 | SIMPLE      | C     | const  | PRIMARY                           | PRIMARY      | 4       | const                         |      1 |             |
|  1 | SIMPLE      | Y     | range  | YEAR_IDX                          | YEAR_IDX     | 4       | NULL                          | 160422 | Using where |
|  1 | SIMPLE      | SD    | eq_ref | PRIMARY                           | PRIMARY      | 4       | climate.Y.STATION_DISTRICT_ID |      1 | Using index |
|  1 | SIMPLE      | S     | eq_ref | PRIMARY                           | PRIMARY      | 4       | climate.SD.ID                 |      1 | Using where |
|  1 | SIMPLE      | M     | ref    | PRIMARY,YEAR_REF_IDX,CATEGORY_IDX | YEAR_REF_IDX | 8       | climate.Y.ID                  |     54 | Using where |
|  1 | SIMPLE      | D     | ref    | INDEX                             | INDEX        | 8       | climate.M.ID                  |     11 | Using where |
+----+-------------+-------+--------+-----------------------------------+--------------+---------+-------------------------------+--------+-------------+

Ответ

После использования STRAIGHT_JOIN:

+----+-------------+-------+--------+-----------------------------------+---------------+---------+-------------------------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys                     | key           | key_len | ref                           | rows | Extra                           |
+----+-------------+-------+--------+-----------------------------------+---------------+---------+-------------------------------+------+---------------------------------+
|  1 | SIMPLE      | C     | const  | PRIMARY                           | PRIMARY       | 4       | const                         |    1 | Using temporary; Using filesort |
|  1 | SIMPLE      | S     | ALL    | PRIMARY                           | NULL          | NULL    | NULL                          | 7795 | Using where                     |
|  1 | SIMPLE      | SD    | eq_ref | PRIMARY                           | PRIMARY       | 4       | climate.S.STATION_DISTRICT_ID |    1 | Using index                     |
|  1 | SIMPLE      | Y     | ref    | PRIMARY,STAT_YEAR_IDX             | STAT_YEAR_IDX | 4       | climate.S.STATION_DISTRICT_ID | 1650 | Using where                     |
|  1 | SIMPLE      | M     | ref    | PRIMARY,YEAR_REF_IDX,CATEGORY_IDX | YEAR_REF_IDX  | 8       | climate.Y.ID                  |   54 | Using where                     |
|  1 | SIMPLE      | D     | ref    | INDEX                             | INDEX         | 8       | climate.M.ID                  |   11 | Using where                     |
+----+-------------+-------+--------+-----------------------------------+---------------+---------+-------------------------------+------+---------------------------------+

Относящиеся

Спасибо!

Ответы [ 3 ]

2 голосов
/ 12 мая 2010

ОДИН запрос ... Похоже, вы ЗНАЕТЕ свои данные. Добавьте ключевое слово "STRAIGHT_JOIN" и посмотрите результаты ...

SELECT STRAIGHT_JOIN ... остальная часть вашего запроса ...

Straight-join говорит MySql, ЧТОБЫ СДЕЛАТЬ ЭТО, КАК Я УКАЗАЛ. Итак, ваша таблица CITY является первой в списке FROM, что указывает на то, что вы ожидаете, что она будет вашей основной ... Кроме того, предложение WHERE в CITY является непосредственным фильтром. С учетом вышесказанного он, вероятно, пройдет через остальную часть запроса ...

Надеюсь, это поможет ... Это сработало для меня, когда были запрошены данные миллионов записей, и они присоединились к 10+ поисковым таблицам, где mySql пытался думать за меня.

0 голосов
/ 12 мая 2010

Можете ли вы перейти от поиска в радиусе к поиску в ограничительной рамке?

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

Возможно, это

S.LATITUDE_DECIMAL >= latitude_lower and  
S.LATITUDE_DECIMAL <= latitude_upper and
S.LONGITUDE_DECIMAL >= longitude_lower and 
S.LONGITUDE_DECIMAL <= longitude_upper

может быть немного быстрее?

0 голосов
/ 12 мая 2010

для того, чтобы сделать эффективные между запросами, вы захотите использовать индекс дерева b в столбце YEAR. например:

CREATE INDEX id_index USING BTREE ON YEAR_REF (YEAR);

Индексы BTREE учитывают эффективные запросы диапазона, если это на самом деле является основной проблемой, тогда наличие такого индекса должно избавить от полного сканирования таблицы и обеспечить сканирование только той части таблицы, которая находится в диапазоне. Узнайте больше о btrees в Википедии

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

...