За последние 24 часа нас посетили 22846 программистов и 1234 робота. Сейчас ищут 760 программистов ...

Оптимизировать запрос UPDATE.

Тема в разделе "MySQL", создана пользователем Phantik, 18 авг 2009.

  1. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    сколько строк выдает селект?
     
  2. Phantik

    Phantik Активный пользователь

    С нами с:
    2 июл 2009
    Сообщения:
    163
    Симпатии:
    0
    В большинстве случаев 1, но иногда возможны варианты 2-3
     
  3. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    [очередной мат]
    сколько строк выдает селект с условием от update?
     
  4. Phantik

    Phantik Активный пользователь

    С нами с:
    2 июл 2009
    Сообщения:
    163
    Симпатии:
    0
    В предыдушем же посте написал 1 почти всегда, редко 2-3.
    Если ты про rows в explain-e то 103610, Тоже выше написал.
    Если про что -то еще, то я не понимаю про что.
     
  5. Phantik

    Phantik Активный пользователь

    С нами с:
    2 июл 2009
    Сообщения:
    163
    Симпатии:
    0
    Еще раз прошу всех прощения за то что из мухи сделал слона. Вообщем разобрался окончательно. Правильный ответ был:

    alter table wins add index xxx (LID,DrawNum,TckNum);

    И все работает мгновенно.

    А до этого меня приглючило что будет достаточно только PRIMARY KEY(`LID`,`DrawNum`,`Module`,`Tour`,`TckNum`)
     
  6. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    Не хочу никого обидеть, но у меня такое впечатление, что 440Hz очень сильно заблуждается по поводу джоинов.

    Есть один знакомый очень хороший Джава-прогер. Последние лет семь работает с различными высоконагруженными системами. И он говорит, что нету ничего лучше Джоина по индексу, ведь джоины работают очень быстро и качественно. Еще он утверждал, что те кто боится Джоинов — боятся их просто из-за недостатка знаний об их устройстве.
     
  7. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    Значит, ты утверждаешь, что количество пройденных записей равно перемноженному количеству записей всех таблиц:
    На консольном форуме сейчас не очень серьезная статистика, конечно, но для анализа вполне сойдет. итак, запрос:

    В таблице Subjects у меня 214 строк, в таблице messages у меня 2561 строк, в таблице Users у меня 715 строк и в таблице Directories у меня 49 записей. Messages и Users у меня подключаются дважды по разным айдишникам. Вот запрос
    [sql]SELECT SQL_NO_CACHE * FROM `Subjects`
    INNER JOIN `Directories`
    ON `Directories`.`ID` = `Subjects`.`DirID`
    LEFT JOIN `Messages` as `MsgFirst`
    ON `MsgFirst`.`ID` = `Subjects`.`MsgFirstID`
    LEFT JOIN `Users` as `AuthorFirst`
    ON `AuthorFirst`.`ID` =`MsgFirst`.`AuthorID`
    LEFT JOIN `Messages` as `MsgLast`
    ON `MsgLast`.`ID` = `Subjects`.`MsgLastID`
    LEFT JOIN `Users` as `AuthorLast`
    ON `AuthorLast`.`ID` =`MsgLast`.`AuthorID`
    LIMIT 0, 10000[/sql]
    По твоей странной теории у меня база должна пройти 214*49*2561*2561*715*715 = 35159370753857350 строк. Даже если таблицу Users и Messages она проходит только один раз, то она должна обойти, по твоей теории, 19201071890 строк. И все это на моем дешевом, загруженном хостинге за 5 уе обрабатывается всего 0.005 секунды (обратите внимание, это не первые 30 строк, а все строки результата).
    Конечно, я понимаю, что можно сказать, что у меня слишном маленькие таблицы. Но даже на таких маленьких таблицах, согласно твоей теории, должны были бы быть затраты. А их, как видишь, нету.
    [sql]SELECT SQL_NO_CACHE * FROM `Directories` LIMIT 0, 10000; -- 0.0005
    SELECT SQL_NO_CACHE * FROM `Subjects` LIMIT 0, 10000; -- 0.001
    SELECT SQL_NO_CACHE * FROM `Messages` LIMIT 0, 10000; -- 0.008
    SELECT SQL_NO_CACHE * FROM `Users` LIMIT 0, 10000; -- 0.002[/sql]
    итого 0.011 против 0.005, то есть с OUTER JOIN'ами вдвое быстрее. а после этого ты еще и пхп кучей работы нагрузить предлагаешь, плюс накладные расходы и т.п. и т.д. Ты уж извини 440Hz, но, хоть я не гурру в MySQL, но даже я вижу, что этом вопросе ты — некомпетентен.


    Кстати, а такой запрос, с условием, отработал вообще за 0.001 секунды, вернув полсотни строк, так что твоя теория полностью несостоятельна:
    [sql]SELECT SQL_NO_CACHE * FROM `Subjects`
    INNER JOIN `Directories`
    ON `Directories`.`ID` = `Subjects`.`DirID`
    LEFT JOIN `Messages` as `MsgFirst`
    ON `MsgFirst`.`ID` = `Subjects`.`MsgFirstID`
    LEFT JOIN `Users` as `AuthorFirst`
    ON `AuthorFirst`.`ID` =`MsgFirst`.`AuthorID`
    LEFT JOIN `Messages` as `MsgLast`
    ON `MsgLast`.`ID` = `Subjects`.`MsgLastID`
    LEFT JOIN `Users` as `AuthorLast`
    ON `AuthorLast`.`ID` =`MsgLast`.`AuthorID`
    WHERE `Directories`.`ID` = 2 LIMIT 0, 10000[/sql]

    И всем: не слушайте людей, которые говорят, что JOINы — это зло. Они — недостаточно компетенты. Джоины по индексам работают очень быстро и очень качественно. Это НАМНОГО лучше, чем несколько запросов.
     
  8. kostyl

    kostyl Guest

    Phantik
    Интересно, какая такая специфика задачи диктует такой праймари? По моему ВСЕГДА можно сделать один столбец праймари со значением инт, ну разве что диапазона может не хватить, но этого я еще не встречал. Пойми у тебя не только селект но и апдейт твой залетает. Каждый апдей переписывает индекса, а у тебя аж пять полей в нём. Ты понимаешь как это?
     
  9. kostyl

    kostyl Guest

    [sql]
    CREATE TABLE IF NOT EXISTS `second` (
    `id` int(10) NOT NULL AUTO_INCREMENT,
    `sirname` varchar(255) NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;[/sql]

    [sql]CREATE TABLE IF NOT EXISTS `first` (
    `id` int(10) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) NOT NULL,
    `second_id` int(10) NOT NULL,
    PRIMARY KEY (`id`),
    KEY `second_id` (`second_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;[/sql]

    PHP:
    1. <?php
    2. $db = mysql_connect('localhost', 'root', 'root');
    3. mysql_select_db('test', $db);
    4. $i = 100000;
    5. while($i--)
    6. {
    7.     $sql = 'insert into `second` (`sirname`) values ("' . rand(4, 5000000) . '")';
    8.     $res= mysql_query($sql, $db);
    9.     $id = mysql_insert_id($db);
    10.     $sql = 'insert into `first` (`name`, `second_id`) values ("'. rand(2, 80000) . '", ' . $id .')';
    11.     $res = mysql_query($sql, $db);
    12. }
    13. /////Джоин
    14. $sql = 'select `f`.`name`, `f`.`second_id`, `s`.`sirname`  from `first` f
    15.        left join `second` s on (`f`.`second_id` = `s`.`id`)
    16.        where `f`.`id` = 10000'; //`f`.`id` < 10000';
    17. $i = 1000;
    18. $AllQueryTime = 0;
    19. $AllPhpTime = microtime(TRUE);
    20. while($i--) {
    21.     $start = microtime(TRUE);
    22.     $result = mysql_query($sql, $db);
    23.   $AllQueryTime += microtime(TRUE) - $start;
    24.         while($row = mysql_fetch_assoc($result)) {
    25.         $data = $row['name'] . ' ' . $row['second_id']. ' ' . $row['sirname'] . '<br/>';
    26.     }
    27. }
    28. $AllPhpTime = microtime(TRUE) - $AllPhpTime;
    29. echo 'Query: ' . $AllQueryTime . ' PHP: ' . $AllPhpTime . '<br>';
    30. /////Антиджоин
    31. $sql = 'select `f`.`name`, `f`.`second_id`,
    32.        (select `s`.`sirname` from `second` s where `s`.`id`=`f`.`second_id`) as `sirname`
    33.        from `first` f where `f`.`id` = 10000'; //`f`.`id` < 10000';
    34. $i = 1000;
    35. $AllQueryTime = 0;
    36. $AllPhpTime = microtime(TRUE);
    37. while($i--) {
    38.     $start = microtime(TRUE);
    39.     $result = mysql_query($sql, $db);
    40.     if($result == FALSE) {echo mysql_error(); exit(0);}
    41.   $AllQueryTime += microtime(TRUE) - $start;
    42.         while($row = mysql_fetch_assoc($result)) {
    43.         $data = $row['name'] . ' ' . $row['second_id']. ' ' . $row['sirname'] . '<br/>';
    44.     }
    45. }
    46. $AllPhpTime = microtime(TRUE) - $AllPhpTime;
    47. echo 'Query: ' . $AllQueryTime . ' PHP: ' . $AllPhpTime . '<br>';
    48. ?>
    Не могу воспроизвести. Всегда Антиджоин дольше.
     
  10. Phantik

    Phantik Активный пользователь

    С нами с:
    2 июл 2009
    Сообщения:
    163
    Симпатии:
    0
    Эта совокупность полей является уникальным идентификатором записи. Это из лотерейной области. Совопукность этих полей определяет совокупность выигрышей определенной лотереи определенного билета определенного типа в определенном тираже.
     
  11. kostyl

    kostyl Guest

    Phantik
    Да это конечно круто, но лотерейная область и организация первичных ключей в СУБД это разные вещи. Вот скажи почему тебе надо делать именно эти пять полей первичным ключом? Что это дает?
     
  12. Phantik

    Phantik Активный пользователь

    С нами с:
    2 июл 2009
    Сообщения:
    163
    Симпатии:
    0
    А каким способом кроме автоинкремента, я могу задать уникальность записи? Вот я и делаю ключ на ту совокупность полей, которая может встречаться в таблице только 1 раз. Если убрать из этого ключа хоть одно поле, то он уже не будет уникальным.
     
  13. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    фантик, вам по японски сказать? отдельно первичный ключ делают не ради прикола
     
  14. Phantik

    Phantik Активный пользователь

    С нами с:
    2 июл 2009
    Сообщения:
    163
    Симпатии:
    0
    По японски не надо, я и по русски ваши сообщения не понимаю.
    Я первичный ключ делал не ради прикола, а ради уникальности. Если есть какие-то другие способы задания уникальности, то я просто их не знаю. Но я, в принципе, и не делал публичных заявлений о том, что являюсь спецом в базах данных.
     
  15. kostyl

    kostyl Guest

    Первичный ключ делают для "первичного ключа", а уникальность это второстепенное - уникальность потому что первичность, а не наоборот. Поставь просто уникальные обычные ключи U, а первичный ключ сделай отдельным одним полем id, тогда у тебя сохраниться уникальность на уровне базы данных и запросы быстрее будут, потому что праймари будет по одному целочисленному столбцу.
     
  16. Phantik

    Phantik Активный пользователь

    С нами с:
    2 июл 2009
    Сообщения:
    163
    Симпатии:
    0
    Т.е. на практике ты предлагаешь при создании таблицы просто добавить поле автоинкремент и сделать его PRIMARY KEY, а те поля, которые у меня были праймери, описать просто как KEY? Я не совсем понимаю в чем между ними разница и на что это повлияет непосредственно в моем контексте. К тому же тогда связывать с другими таблицами по PRIMARY KEY не получится.
     
  17. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    последняя попытка. Фантик, вы нагромоздили индексов не понимая как они работают и зачем, в этом и проблема.
    объяснения бесполезны, поскольку вы НЕ ХОТИТЕ понимать что вам говорят.
    записи в таблице в подавляющем большинстве случаев ДОЛЖНЫ иметь уникальный НОМЕР (ид).

    чтобы не искать адрес в городе по принципу "зеленый дом с голубой крышей, 4 этажный 2-подъездный с двумя деревьями рядом".

    связь с другими таблицами у вас сделана так же коряво.
     
  18. kostyl

    kostyl Guest

    Phantik
    Вообщем, чтобы правильно было и быстрее работало надо всю структуру менять.
     
  19. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    обидеть можно только того, хто хочет быть обиженным. эт не ко мне.

    я не говорил, что JOIN зло, я хотел показать что может происходить.

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

    но тут ИМХО с ключами - капец.

    ===

    JOIN не зло. Зло - непонимание происходящего.
     
  20. kostyl

    kostyl Guest

    а я тут блин тестю всякую хрень....
    Однозначно