MySQL: оптимизация SELECT из 6 огромных идентичных таблиц с различными данными, разделенными по отметке времени - PullRequest
2 голосов
/ 03 сентября 2010

пожалуйста, у меня такая же проблема, как я нашел здесь

MySQL - выбор данных из нескольких таблиц с одинаковой структурой, но с разными данными ,

Мне нужно выбрать данные из многих таблиц MySQL с идентичной структурой, но разными данными (разделить на table_0, table_1, table_2 и т. Д. На table_5, чтобы распределить миллионы записей данных).

Аппаратные средства, генерирующие записи данных для каждого устройства, перемещаются из таблицы в таблицу в соответствии с полем отметки времени, которое НЕ является уникальным. например 50 записей в table_0 могут иметь одинаковую метку времени. Когда данные доходят до конца таблицы_5, они возвращаются к таблице_0, чтобы начать перезапись данных там. Мне нужно получить данные на каждом устройстве за определенный промежуток времени.

Столбцы данных каждой таблицы (для таблицы_0, таблицы_1 ... до таблицы_5):
timestamp, robotGroupID, robotID, sensor1, sensor2, sensor3, ... (many of them)

Однако таблицы ОГРОМНЫ, и UNION ALL (я читаю его быстрее, чем DISTINCT) выполняется вечно, даже с двумя таблицами, не говоря уже о 6. Например. Ниже я приведу две таблицы.

Оператор MySQL в PHP: (показан только для датчика 1, датчика 2 и датчика 3)
(SELECT sensor1, sensor2, sensor3 FROM table_0 WHERE robotID=".$robotID." AND timestamp BETWEEN ".$timeStampStart." AND ".$timeStampStop)<br/> UNION ALL<br /> (SELECT sensor1, sensor2, sensor3 FROM table_1 WHERE robotID=".$robotID." AND timestamp BETWEEN ".$timeStampStart." AND ".$timeStampStop)

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

Я не могу использовать LIMIT, потому что количество отчетов от роботов в каждом временном диапазоне не может быть известно заранее. Я не могу использовать MERGE STORAGE ENGINE, потому что у меня есть только доступ только для чтения к базе данных компании.

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

Пожалуйста, как вы думаете, я могу сделать это быстрее для 6 таблиц и еще большего количества столбцов, поскольку столбцов намного больше, чем показано на рисунке? Заранее спасибо!

Ответы [ 3 ]

1 голос
/ 03 сентября 2010

Индексируются ли поля RobotID и Timestamp?

Я бы добавил индекс из нескольких полей (RobotId, timestamp) как минимум.

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

0 голосов
/ 16 августа 2012

Если вы можете убедить их позволить вам изменить структуру базы данных, вы можете БОЛЬШО оптимизировать структуру вашей базы данных с помощью MySQL Partitioning. Вы захотите исследовать «Range Partitioning» и настроить правила разделения, которые скажут MySQL автоматически сортировать ваши данные в невидимые подтаблицы для более быстрого результата SELECT. Вам даже не понадобится несколько таблиц.

См. http://dev.mysql.com/doc/refman/5.1/en/partitioning-overview.html

0 голосов
/ 03 сентября 2010

Должен признаться, я все еще начинающий PHP / MySQL-кодер, но со многими идеями;поэтому мой код, вероятно, «грязный».

Так что я решил проблему таким образом, чтобы двигаться вперед, но, пожалуйста, лучшие решения приветствуются.Что касается любого странного синтаксиса, я использую класс базы данных, построенный на PHP PDO, потому что я использую много разных типов RBDMS в этом проекте.

Для переменной $ myQuery_start я добавил имена других столбцов кака также датчики с 1 по 3. <br /> $myQuery_start = "(SELECT sensor1, sensor2, sensor3 FROM ";<br/> $myQueryCount_start = "(SELECT COUNT(*) FROM ";<br/> $myQuery_stop = " WHERE robotID=".$robotID." AND timestamp BETWEEN ".$timeStampStart." AND ".$timeStampStop.")";<br /> $count_0 = DB::getDB("mysql", $myDB)->query($myQueryCount_start."table_0".$myQuery_stop)->fetchColumn();<br /> $count_1 = DB::getDB("mysql", $myDB)->query($myQueryCount_start."table_1".$myQuery_stop)->fetchColumn();<br /> $count_2 = DB::getDB("mysql", $myDB)->query($myQueryCount_start."table_2".$myQuery_stop)->fetchColumn();<br /> $count_3 = DB::getDB("mysql", $myDB)->query($myQueryCount_start."table_3".$myQuery_stop)->fetchColumn();<br /> $count_4 = DB::getDB("mysql", $myDB)->query($myQueryCount_start."table_4".$myQuery_stop)->fetchColumn();<br /> $count_5 = DB::getDB("mysql", $myDB)->query($myQueryCount_start."table_5".$myQuery_stop)->fetchColumn();<br /> А теперь я проверяю, нужно ли добавлять UNION ALL к запросу каждой таблицы или нет.Не нужно иметь UNION ALL, если в следующей таблице нет записи данных для присоединения. $union_0 = (($count_1 + $count_2 + $count_3 + $count_4 + $count_5) > 0)?" UNION ALL ":"";<br /> $union_1 = (($count_2 + $count_3 + $count_4 + $count_5) > 0)?" UNION ALL ":"";<br /> $union_2 = (($count_3 + $count_4 + $count_5) > 0)?" UNION ALL ":"";<br /> $union_3 = (($count_4 + $count_5) > 0)?" UNION ALL ":"";<br /> $union_4 = (($count_5) > 0)?" UNION ALL ":"";<br /> и теперь мы строим таблицу запросов и объединяем, чтобы сформировать полный запрос $query_0 = ($count_0 > 0)?$myQuery_start."ip_minute_stats_0".$myQuery_stop.$union_0:"";<br /> $query_1 = ($count_1 > 0)?$myQuery_start."ip_minute_stats_1".$myQuery_stop.$union_1:"";<br /> $query_2 = ($count_2 > 0)?$myQuery_start."ip_minute_stats_2".$myQuery_stop.$union_2:"";<br /> $query_3 = ($count_3 > 0)?$myQuery_start."ip_minute_stats_3".$myQuery_stop.$union_3:"";<br /> $query_4 = ($count_4 > 0)?$myQuery_start."ip_minute_stats_4".$myQuery_stop.$union_4:"";<br /> $query_5 = ($count_5 > 0)?$myQuery_start."ip_minute_stats_5".$myQuery_stop:""; Затем соединены: $myQuery = $query_0.$query_1.$query_2.$query_3.$query_4.$query_5; И, наконец, $ myQuery выполняется для получения всех необходимых данных.

По крайней мере, это примерно в 8 раз быстрее, чем предыдущий способ, которым я использовал UNION ALL, поэтому я думаю, что это правильно.Любая предложенная дальнейшая оптимизация?

...