2013-09-11 2 views
0

Я не очень привык к MySQL, но я думаю, что это может быть намного быстрее, чем есть.Как оптимизировать запрос при группировке по метке даты/времени unix?

Вот мой стол:

CREATE TABLE `crashes` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`added_date` int(11) NOT NULL, 
`status` int(11) NOT NULL, 
`issue_id` varchar(32) NOT NULL, 
`report_id` text NOT NULL, 
`app_version_code` text NOT NULL, 
`app_version_name` text NOT NULL, 
`package_name` varchar(80) NOT NULL, 
`package_name_id` tinyint(4) NOT NULL, 
`file_path` text NOT NULL, 
`phone_model` text NOT NULL, 
`android_version` text NOT NULL, 
`build` text NOT NULL, 
`brand` text NOT NULL, 
`product` text NOT NULL, 
`total_mem_size` int(11) NOT NULL, 
`available_mem_size` int(11) NOT NULL, 
`custom_data` text NOT NULL, 
`stack_trace` text NOT NULL, 
`initial_configuration` text NOT NULL, 
`crash_configuration` text NOT NULL, 
`display` text NOT NULL, 
`user_comment` text NOT NULL, 
`user_app_start_date` text NOT NULL, 
`user_crash_date` text NOT NULL, 
`dumpsys_meminfo` text NOT NULL, 
`dropbox` text NOT NULL, 
`logcat` text NOT NULL, 
`eventslog` text NOT NULL, 
`radiolog` text NOT NULL, 
`is_silent` text NOT NULL, 
`device_id` text NOT NULL, 
`installation_id` text NOT NULL, 
`user_email` text NOT NULL, 
`device_features` text NOT NULL, 
`environment` text NOT NULL, 
`settings_system` text NOT NULL, 
`settings_secure` text NOT NULL, 
`shared_preferences` text NOT NULL, 
`application_log` text NOT NULL, 
`media_codec_list` text NOT NULL, 
`thread_details` text NOT NULL, 
`user_ip` text NOT NULL, 
PRIMARY KEY (`id`), 
KEY `package_name_id` (`package_name_id`) 
) ENGINE=MyISAM AUTO_INCREMENT=202364 DEFAULT CHARSET=utf8 

Как вы можете видеть, он заполнен 200k строк. Я хотел бы получить строку added_date (unix timestamp, int(11)) и количество строк в этот день.

Так я выбираю дату, день (как Y-M-D), и посчитайте:

SELECT date_format(from_unixtime(added_date), '%Y-%c-%d') as date, added_date, count(*) as nb_crashes FROM crashes WHERE package_name = 'net.bicou.redmine' GROUP BY date ORDER BY date ASC 

Это очень медленно! Почти 1,5 секунды на выделенном сервере mysql на моем хосте.

Поэтому я полагал, что я мог бы оптимизировать вещь, немного: я добавил package_name_id, который является tinyint, который является уникальным для каждого package_name (у меня есть 5 различных package_name значения на что 200k строк). Я сделал это INDEX, чтобы MySQL мог быстрее его просматривать.
Результат: 0.9sec. Это намного лучше, но я все равно не ожидаю!

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

Edit:

Вот что я сделал, чтобы обновить таблицу:

ALTER TABLE `crashes` ADD `temp` DATETIME NOT NULL 
UPDATE crashes SET temp = FROM_UNIXTIME(added_date) 
ALTER TABLE `crashes` ADD INDEX ( `temp`) 

Вот обновленный запрос:

SELECT added_date, count(*) as nb_crashes FROM crashes WHERE package_name_id=3 GROUP BY year(temp),month (temp),dayofmonth(temp) ORDER BY temp ASC 

У меня все еще есть время выполнения около одной секунды ... Я сделал что-то не так?

ответ

2

Нельзя использовать значения временных меток unix, если вам нужно запросить это поле по дате. Вы должны использовать типы полей даты, времени и времени.

Почему?

Потому что, если вы хотите сделать что-то вроде результатов запроса для определенной даты или группы записей по дате, для этого вам всегда нужно использовать FROM_UNIXTIME(). Этот вызов функции не позволит вам использовать какой-либо индекс для значения даты, если вы пытаетесь использовать его для сортировки, объединения, где фильтры, группы и т. Д. Вы ничего не можете сделать, чтобы улучшить свой запрос за пределами использования надлежащего тип данных, а затем индексирование полей, которые вы собираетесь использовать для сортировки, фильтров, объединений, групп и т. д.

Действительно, использование временных меток unix в БД, по-видимому, размножается неопытными разработчиками PHP, которые считают, что работать с датами в этом формате на PHP проще (либо они слишком ленивы, чтобы преобразовать вывод DB/datetime в unix timestamps в PHP, или они не выяснили, как использовать классы dateTime и dateInterval PHP, чтобы упростить работу с датами в PHP).

Мое предложение состоит в том, чтобы разбить эту привычку и начать изучать, как работать с полями даты/даты в MySQL.

Antoher thing Я бы предложил посмотреть на ваш стол. DDL - это то, что вы, вероятно, должны вернуться к использованию текстовых полей. Большинство из этих случаев выглядят так, как будто они могут быть лучшими полями varchar.

+0

Большое спасибо. Я грязный разработчик php, который учился как любитель 10 лет назад, я только начал снова. Я сделаю все правильно, спасибо за подсказки. –

+0

Эй, я обновил свой вопрос, потому что я все еще не могу оптимизировать таблицу так, как хочу. Об этих «текстовых» полях они не используются в выборе, объединении или группе, поэтому я решил, что это не имеет значения. –

1

Если вам нужна производительность, вам нужен индекс, и если вам нужен индекс, вам необходимо создать столбец с нужными типами данных, прежде чем вы сделаете свой запрос.

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

Почему вы храните дату в качестве метки времени, а не как надлежащую колонку DATE, так или иначе?

+0

Спасибо. Смотрите мой комментарий на ответ Майка. Я преобразую поле в поле даты! –

+0

Хороший план, и у Майка есть более подробный ответ. – tadman

0

Вы можете сделать индекс как на package_name, так и на столбцах added_date. Кроме того, измените свой ORDER BY на заказ added_date вместо date, так как при заказе date, вероятно, потребуется шаг filesort.

В любом случае EXPLAIN помогает лучше диагностировать запрос.

+0

Это все равно не поможет всему, что ему еще нужно группировать по вычисленному полю даты, которое вообще не может использовать индекс. Единственное решение здесь - использовать правильный тип данных даты/даты и времени в поле. –

Смежные вопросы