2015-09-15 4 views
0

У меня есть таблица Bitcoin сделок:MySQL: SUM/MAX/MIN GROUP BY запроса оптимизации

 
    CREATE TABLE `transactions` (
     `trans_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
     `trans_exchange` int(10) unsigned DEFAULT NULL, 
     `trans_currency_base` int(10) unsigned DEFAULT NULL, 
     `trans_currency_counter` int(10) unsigned DEFAULT NULL, 
     `trans_tid` varchar(20) DEFAULT NULL, 
     `trans_type` tinyint(4) DEFAULT NULL, 
     `trans_price` decimal(15,4) DEFAULT NULL, 
     `trans_amount` decimal(15,8) DEFAULT NULL, 
     `trans_datetime` datetime DEFAULT NULL, 
     `trans_sid` bigint(20) DEFAULT NULL, 
     `trans_timestamp` int(10) unsigned DEFAULT NULL, 
     PRIMARY KEY (`trans_id`), 
     KEY `trans_tid` (`trans_tid`), 
     KEY `trans_datetime` (`trans_datetime`), 
     KEY `trans_timestmp` (`trans_timestamp`), 
     KEY `trans_price` (`trans_price`), 
     KEY `trans_amount` (`trans_amount`) 
    ) ENGINE=MyISAM AUTO_INCREMENT=6162559 DEFAULT CHARSET=utf8; 

Как видно из значения AUTO_INCREMENT, таблица имеет более 6 миллионов словарных статей. В конечном итоге их будет гораздо больше.

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

 
    SELECT 
    DATE_FORMAT(MIN(transactions.trans_datetime), 
     '%Y/%m/%d %H:%i:00' 
     ) AS trans_datetime, 
    SUM(transactions.trans_amount) as trans_volume, 
    MAX(transactions.trans_price) as trans_max_price, 
    MIN(transactions.trans_price) as trans_min_price, 
    COUNT(transactions.trans_id) AS trans_count 
    FROM 
    transactions 
    WHERE 
    transactions.trans_datetime BETWEEN '2014-09-14 00:00:00' AND '2015-09-13 23:59:00' 
    GROUP BY 
    transactions.trans_timestamp DIV 86400 

Это следует выбирать сделки, совершенные в течение года, сгруппированных по день (86400 секунд).

Идея - это поле метки времени, которое содержит то же значение, что и дата и время, но как временную метку ... Я нашел это быстрее, чем UNIX_TIMESTAMP (trans_datetime), делится на количество секунд, в которые я хочу быть вовремя интервалы.

Проблема: запрос выполняется медленно. Я получаю 4-секундное время обработки. Вот результат EXPLAIN:

 
    id select_type table type possible_keys key key_len ref rows Extra 
    1 SIMPLE transactions ALL trans_datetime,trans_timestmp NULL NULL NULL 6162558 Using where; Using temporary; Using filesort 

Вопрос: возможно оптимизировать это лучше? Является ли эта структура или подход ошибочной? Я попробовал несколько подходов и добился успеха лишь в миллисекундах.

+0

Почему транзакции.trans_datetime как аргумент для агрегатной функции, так и в предложении GROUP BY? – jarlh

+0

Как и в целом, вы должны GROUP BY тем же, что и SELECT. Итак, если вы выбрали DATE_FORMAT, тогда GROUP BY DATE_FORMAT. Это правда, что вам это не нужно, но это не приведет к ошибкам. – Strawberry

+0

Бит DATE_FORMAT не предназначен для группировки; это было только там, поэтому с каждой группой появляется некоторое представление времени, так что оно может быть построено на графике. Извлечение его из SQL-запроса, по-видимому, не влияет на скорость. – suzerain

ответ

0

Большая часть данных в таблице находится за последние 12 месяцев? Так что вам нужно прикоснуться к большей части стола? Тогда нет способа ускорить , что запрос. Тем не менее, вы можете получить одинаковые порядки вывода быстрее ...

Создайте сводную таблицу. Он будет иметь DATE как PRIMARY KEY, и столбцы будут эффективно поля, упомянутые в вашем SELECT.

После того, как вы изначально заполнили сводную таблицу, затем сохраните ее, добавив новую строку каждую ночь для транзакций дня. More in my blog.

Тогда запрос, чтобы получить желаемый результат, попадет в эту сводную таблицу (всего несколько сотен строк), а не таблицу с миллионами или строками.

+0

Большое спасибо. Именно такой подход я начал работать после отказа от оптимизации запроса, который, к сожалению, устранит произвольное качество поиска, которое я надеялся получить. Данные охватывают несколько лет; цель состояла в том, чтобы иметь возможность выбирать любые промежутки времени, с некоторым автоматическим регулированием «интервала», который был бы соответствующим набору данных. Таким образом, вы можете просматривать данные за последние 10 месяцев или последние 10 часов или что-то еще, с системным интеллектуальным масштабированием интервалов ... возможно, эта гибкость не возможна при текущей настройке. – suzerain

+0

Сводная таблица с детализацией одного дня будет охватывать большинство применений.Вы можете переключиться на выборку из таблицы фактов для разрешения часа, с оговоркой, что если кто-то запросит точно последние 12345 часов, это будет медленным (из таблицы фактов). Принимая во внимание, что просить последние 500 дней будет достаточно быстро (из сводной таблицы). В «реальной жизни» люди не просят 12345 часов, и они не просят 3-часовой период в апреле прошлого года. –