2014-11-10 2 views
0

У нас есть большая таблица со следующей структурой таблицы:Оптимизация SQL запросы от большого стола Заказанного Timestamp

CREATE TABLE `location_data` (
    `id` int(20) NOT NULL AUTO_INCREMENT, 
    `dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `device_sn` char(30) NOT NULL, 
    `data` char(20) NOT NULL, 
    `gps_date` datetime NOT NULL, 
    `lat` double(30,10) DEFAULT NULL, 
    `lng` double(30,10) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `dt` (`dt`), 
    KEY `data` (`data`), 
    KEY `device_sn` (`device_sn`,`data`,`dt`), 
    KEY `device_sn_2` (`device_sn`,`dt`) 
) ENGINE=MyISAM AUTO_INCREMENT=721453698 DEFAULT CHARSET=latin1 

Много раз мы выполнили запрос, такие как следующие:

SELECT * FROM location_data WHERE device_sn = 'XXX' AND data = 'location' ORDER BY dt DESC LIMIT 1; 

ИЛИ

SELECT * FROM location_data WHERE device_sn = 'XXX' AND data = 'location' AND dt >= '2014-01-01 00:00:00 ' AND dt <= '2014-01-01 23:00:00' ORDER BY dt DESC; 

Мы оптимизируя это несколькими способами:

  1. С помощью добавления индекса и использования FORCE INDEX на device_sn.
  2. Разделение таблицы на несколько таблиц на основе даты (например, location_data_20140101) и предварительная проверка наличия данных на определенную дату, и мы потянем эту конкретную таблицу отдельно. Эта таблица создается cron один раз в день, и данные в location_data для этой конкретной даты будут удалены.

Таблица location_data HIGH WRITE и LOW READ.

Однако несколько раз запрос работает очень медленно. Интересно, существуют ли другие методы/способы/реструктуризация данных, которые позволяют нам читать данные в последовательном порядке даты на основе заданного device_sn.

Любые советы более чем приветствуются.

EXPLAIN ЗАЯВЛЕНИЕ 1ST QUERY:

+----+-------------+--------------+------+----------------------------+-----------+---------+-------------+------+-------------+ 
| id | select_type | table  | type | possible_keys    | key  | key_len | ref   | rows | Extra  | 
+----+-------------+--------------+------+----------------------------+-----------+---------+-------------+------+-------------+ 
| 1 | SIMPLE  | location_dat | ref | data,device_sn,device_sn_2 | device_sn | 50  | const,const | 1 | Using where | 
+----+-------------+--------------+------+----------------------------+-----------+---------+-------------+------+-------------+ 

EXPLAIN ЗАЯВЛЕНИЕ 2-й QUERY:

+----+-------------+--------------+-------+-------------------------------+------+---------+------+------+-------------+ 
| id | select_type | table  | type | possible_keys     | key | key_len | ref | rows | Extra  | 
+----+-------------+--------------+-------+-------------------------------+------+---------+------+------+-------------+ 
| 1 | SIMPLE  | test_udp_new | range | dt,data,device_sn,device_sn_2 | dt | 4  | NULL | 1 | Using where | 
+----+-------------+--------------+-------+-------------------------------+------+---------+------+------+-------------+ 
+0

'int (20)' for PK не имеет смысла. Индексы с низкой мощностью не имеют никакого смысла. В комплект поставки не входит «EXPLAIN». Вы также используете MyISAM, и если это высокая запись, сомнительно, насколько хорошо он работает (вы не можете даже контролировать огромные сбросы на диск из-за движка). Принуждение индекса с низкой мощностью не имеет смысла. MySQL использует индексы только тогда, когда он быстрее, чем необходимость полного сканирования таблицы. Теперь, если вы можете включить вывод EXPLAIN, это поможет нам проанализировать все, что не так. –

+0

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

+0

@ N.B. Я отредактировал свой вопрос, чтобы включить вывод инструкции EXPLAIN. Можете ли вы объяснить, почему индексы с низкой мощностью не имеют смысла? И почему заставить индекс с низкой мощностью не имеет никакого смысла? Спасибо за вашу помощь! –

ответ

0

Индекс device_sn (device_sn, data, dt) хорошо. MySQL должен использовать его без необходимости делать FORCE INDEX. Вы можете проверить его, запустив «explain select ...»

Однако ваша таблица MyISAM, которая поддерживает только блокировки на уровне таблицы. Если таблица сильно написана, она может быть медленной. Я бы предложил преобразовать его в InnoDB.

+0

Спасибо! Я пытался конвертировать в InnoDB раньше, но почему-то это заставляет писать очень медленно. Есть ли способ ускорить запись InnoDB? Я попробовал 'innodb_flush_log_at_trx_commit' установить' 0'. –

0

Хорошо, я предоставлю информацию, которую знаю, и это может не ответить на ваш вопрос, но может дать некоторое представление.

Выходит определенные отличия между InnoDB и MyISAM. Забудьте о полном индексировании текста или пространственных индексах, огромная разница в том, как они работают.

InnoDB имеет несколько отличных функций по сравнению с MyISAM. Прежде всего, он может хранить набор данных, с которым он работает, в ОЗУ. Вот почему серверы баз данных поставляются с большим количеством оперативной памяти, поэтому операции ввода-вывода могут быть выполнены быстро. Например, сканирование индекса выполняется быстрее, если у вас есть индексы в ОЗУ, а не на жестком диске, потому что поиск данных на HDD на несколько величин медленнее, чем в ОЗУ. То же самое относится к полному сканированию таблицы. Переменная, которая управляет этим при использовании InnoDB, называется innodb_buffer_pool_size. По умолчанию это 8 МБ, если я не ошибаюсь. Я лично установил это значение высоко, иногда даже до 90% доступной ОЗУ.Обычно, когда это значение оптимизировано, многие люди испытывают невероятную прирост скорости.

Другое дело, что InnoDB является транзакционным движком. Это означает, что он скажет вам, что запись на диск завершилась успешно или не удалась, и это будет на 100% правильной. MyISAM этого не сделает, потому что это не заставляет ОС принудительно принудительно фиксировать данные на жестком диске. Вот почему иногда записи теряются при использовании MyISAM, он думает, что данные написаны, потому что OS заявила, что на самом деле ОС пыталась оптимизировать запись, а жесткий диск мог потерять данные буфера, не записывая их. ОС пытается оптимизировать операцию записи и использует буферы HDD для хранения больших фрагментов данных, а затем сбрасывает их в одном вводе-выводе. Затем происходит то, что у вас нет контроля над , как записываются данные. С помощью InnoDB вы можете начать транзакцию, выполнить запрос 100 INSERT и затем совершить транзакцию. Это эффективно заставит жесткий диск сбросить все 100 запросов одновременно, используя 1 ввод-вывод. Если каждый INSERT имеет длину 4 КБ, 100 из них составляют 400 КБ. Это означает, что вы будете использовать 400kb полосы пропускания вашего диска с 1 операцией ввода-вывода, и оставшаяся часть ввода-вывода будет доступна для других целей. Именно так оптимизируются вставки.

Далее представлены индексы с низкой мощностью - мощность - это количество уникальных значений в индексированном столбце. Для первичного ключа это значение равно 1. Это также самое высокое значение. Индексы с низкой мощностью - это столбцы, где у вас есть несколько различных значений, например yes или no или аналогичные. Если индекс слишком мал в мощности, MySQL предпочтет полное сканирование таблицы - это намного быстрее. Кроме того, форсирование индекса, который MySQL не хочет использовать, может (и, вероятно, будет) замедлять работу - это связано с тем, что при использовании индексированного поиска MySQL обрабатывает записи один за другим. Когда он выполняет сканирование таблицы, он может считывать сразу несколько записей и не обрабатывать их. Если эти записи были записаны последовательно на механическом диске, возможны дальнейшие оптимизации.

TL; DR:

  • использовать InnoDB на сервере, где вы можете выделить достаточное количество оперативной памяти
  • установить значение innodb_buffer_pool_size достаточно большой, так что вы можете выделить больше ресурсов для ускорения запросов
  • использовать SSD если возможно
  • попробуйте обернуть несколько транзакций в транзакции, чтобы вы могли лучше использовать полосу пропускания жесткого диска и ввод/вывод
  • избегать индексации столбцов с низким уровнем uni кол-во значений по сравнению с количеством строк - они просто теряют пространство (хотя есть исключения из этого)
Смежные вопросы