Как можно оптимизировать запрос





Есть таблица (уже 70млн записей)
Делаю селект, далее инсерт в другую таблицу и затем удаляю строку, которая перенесена в другую таблицу. Селект и Инсерт проходят моментально, а вот удаление весь процесс тормозит.
Можно как-то оптимизировать. 22 минуты уходит на перенос 60000 строк.
  • 29 июня 2009, 02:42
  • ava36

Ответы (8)

RSS
+
0
В таблице raw_a Вам необходимо сделать индекс для всех полей, используемых в условии выборки при удалении.
(При выполнении команды SELECT у Вас не используется никаких условий, то есть база берёт первые попавшиеся строки - это работает быстрее некуда. При выполнении INSERT тоже тормозить особо не на чем - назначительные ресурсы могли бы тратиться на перестройку индексов, но у Вас они отсутствуют. А вот при выполнении DELETE база перебирает всю таблицу, чтобы выбрать нужные строки - на это и уходит время - если сделать индексы, всё быдет работать очень быстро).
Уверен, что добавление одного индекса для всех нужных полей решит Вашу проблему (70млн записей для MySQL - это не так уж много), но если всё-таки не решит, то воспользуйтесь советом kmike - сделайте дополнительное поле-флаг, только не забудьте создать индекс для этого поля. (К сожалению, структуру таблицы raw_a Вы так и не указали, поэтому можно только гадать - нет ли в этой таблице поля с уникальными id, если есть, то вместо дополнительного поля лучше использовать это).
avatar

lia

  • 17 июля 2009, 16:15
+
0
<?
//config
$config[mysql_host] = "localhost";
$config[mysql_login] = "root";
$config[mysql_password] = "7e7b33d7";
$config[ulog_limit] = "10000";
$config[ulog_limit_s] = "5";
//ulog connect
echo "Загрузка базы ulog...";
flush();
$ulog_mysqlcon = mysqli_connect($config[mysql_host], $config[mysql_login], $config[mysql_password]);
mysqli_select_db($ulog_mysqlcon, "ulog");
echo "<font color='green'>выполнено</font><br>";
flush();
echo "Создание второго подключения для отгрузки...";
flush();
$mscon = mysqli_connect($config[mysql_host], $config[mysql_login], $config[mysql_password]) or die(mysqli_error());
mysqli_select_db($mscon, "ulog_2008");
echo "<font color='green'>выполнено</font><br>";
flush();
$all_time = 0;
//Выборка
for($i=0; $i<=$config[ulog_limit_s];$i++)
{
$var_time = time();
echo "<br>Выборка ".$config[ulog_limit]." записей...";
flush();
$ulog_mysql_query = mysqli_query($ulog_mysqlcon, "SELECT * FROM raw_a LIMIT ".$config[ulog_limit]."") or die(mysqli_error($ulog_mysqlcon));
$i_num = 0;
$ms_aff = 0;
$i_np = 0;
$i_percent = $config[ulog_limit]/100;
echo "<font color='green'>выполнено</font><br>";
flush();
echo "[";
while($ulog_mysql_array = mysqli_fetch_array($ulog_mysql_query))
{
$table = date("m_d_Y", $ulog_mysql_array[unix_secs]);
$mysql_add_tb = mysqli_query($mscon, "CREATE TABLE IF NOT EXISTS $table (
  `id` int(15) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `unix_secs` int(11) unsigned NOT NULL default '0',
  `unix_nsecs` int(11) unsigned NOT NULL default '0',
  `sysuptime` int(11) unsigned NOT NULL default '0',
  `exaddr` varchar(45) NOT NULL default '0',
  `dflows` int(11) unsigned NOT NULL default '0',
  `dpkts` int(11) unsigned NOT NULL default '0',
  `doctets` int(11) unsigned NOT NULL default '0',
  `first` int(11) unsigned NOT NULL default '0',
  `last` int(11) unsigned NOT NULL default '0',
  `engine_type` tinyint(3) unsigned NOT NULL default '0',
  `engine_id` tinyint(3) unsigned NOT NULL default '0',
  `srcaddr` varchar(45) NOT NULL default '0',
  `dstaddr` varchar(45) NOT NULL default '0',
  `nexthop` varchar(45) NOT NULL default '0',
  `input` smallint(5) unsigned NOT NULL default '0',
  `output` smallint(5) unsigned NOT NULL default '0',
  `srcport` smallint(5) unsigned NOT NULL default '0',
  `dstport` smallint(5) unsigned NOT NULL default '0',
  `prot` tinyint(3) unsigned NOT NULL default '0',
  `tos` tinyint(3) unsigned NOT NULL default '0',
  `tcp_flags` tinyint(3) unsigned NOT NULL default '0',
  `src_mask` tinyint(3) unsigned NOT NULL default '0',
  `dst_mask` tinyint(3) unsigned NOT NULL default '0',
  `counted` int(0) unsigned NOT NULL default '0'
) ENGINE=MyISAM") or die(mysqli_error($mscon));
$mysql_add_line = mysqli_query($mscon, "INSERT INTO $table
(id,
unix_secs,
unix_nsecs,
sysuptime,
exaddr,
dflows,
dpkts,
doctets,
first,
last,
engine_type,
engine_id,
srcaddr,
dstaddr,
nexthop,
input,
output,
srcport,
dstport,
prot,
tos,
tcp_flags,
src_mask,
dst_mask) VALUES
(NULL,
'$ulog_mysql_array[unix_secs]',
'$ulog_mysql_array[unix_nsecs]',
'$ulog_mysql_array[sysuptime]',
'$ulog_mysql_array[exaddr]',
'$ulog_mysql_array[dflows]',
'$ulog_mysql_array[dpkts]',
'$ulog_mysql_array[doctets]',
'$ulog_mysql_array[first]',
'$ulog_mysql_array[last]',
'$ulog_mysql_array[engine_type]',
'$ulog_mysql_array[engine_id]',
'$ulog_mysql_array[srcaddr]',
'$ulog_mysql_array[dstaddr]',
'$ulog_mysql_array[nexthop]',
'$ulog_mysql_array[input]',
'$ulog_mysql_array[output]',
'$ulog_mysql_array[srcport]',
'$ulog_mysql_array[dstport]',
'$ulog_mysql_array[prot]',
'$ulog_mysql_array[tos]',
'$ulog_mysql_array[tcp_flags]',
'$ulog_mysql_array[src_mask]',
'$ulog_mysql_array[dst_mask]')") or die(mysqli_error($mscon));
       $mysql_delete_line = mysqli_query($ulog_mysqlcon, "DELETE FROM raw_a WHERE
                                                          unix_secs = '$ulog_mysql_array[unix_secs]' AND
                                                          unix_nsecs = '$ulog_mysql_array[unix_nsecs]' AND
                                                          sysuptime = '$ulog_mysql_array[sysuptime]' AND
                                                          exaddr = '$ulog_mysql_array[exaddr]' AND
                                                          dflows = '$ulog_mysql_array[dflows]' AND
                                                          doctets = '$ulog_mysql_array[doctets]' AND
                                                          srcaddr = '$ulog_mysql_array[srcaddr]' AND
                                                          dstaddr = '$ulog_mysql_array[dstaddr]' AND
                                                          srcport = '$ulog_mysql_array[srcport]' AND
                                                          dstport = '$ulog_mysql_array[dstport]' LIMIT 1");
       $ms_aff = $ms_aff + mysqli_affected_rows($ulog_mysqlcon);
       $i_num++;
       if($i_num == $i_percent)
                 {
                 $i_num = 0;
                 echo ":";
                 $i_np ++;
                 flush();
                 }
       if($i_np == "50")
                {
                echo "50%";
                flush();
                $i_np++;
                }
       if($i_np > "100")
                {
                echo "]";
                flush();
                }
}
$var_time_end = time();
$var_sec = $var_time_end-$var_time;
echo "<br>".$config[ulog_limit]."/".$ms_aff." записей обработано за ".$var_sec." секунд";
$all_time = $all_time+$var_sec;
}
echo "<br>Общее время: ".$all_time." секунд";
//data
?>
Написал весь скрипт.
avatar

eter-2008

  • 15 июля 2009, 08:11
+
0
Уже сделал индекс. Я просто не хотел его делать, т.к понимал, что база уйдет в даун на часик - два. Так и получилось, точнее не в даун, а просто она ушла думать:) Сейчас ключи уже расставлены, стало действительно быстрее. По 1,5 млн за 5 минут.  Единственное после удаления 5млн надо оптимизацию делать постоянно, на что уходит дополнительно 3-4 минуты времени.
avatar

eponyatnaya-lichnost

  • 21 июля 2009, 19:12
+
0
не знаю- вот линк хороший
avatar

imax

  • 26 июля 2009, 22:13
+
0
а собственно где сам запрос то ?
что именно оптимизировать ?
получается не оптимизация а написание своего :)
avatar

piker01

  • 4 июля 2009, 09:12
+
0
если 2 таблицы одинаковые, может, просто использовать только 1 таблицу и добавить доп. поле с флагом? - вместо селектов, инсертов, делитов - один апдейт
еще вариант без delete каждый раз - в строке ставь какой-нить флаг, что она удалена (перенесена), а удалять потом все кучей, по расписанию.
avatar

imple

  • 23 июля 2009, 23:49
+
0
На пароль пофиг, везде разные.
avatar

lena-ucky

  • 18 июля 2009, 08:46
+
0
avatar

atros-heleznyak

  • 2 августа 2009, 13:14

Только зарегистрированные и авторизованные пользователи могут отвечать.