В предыдушем же посте написал 1 почти всегда, редко 2-3. Если ты про rows в explain-e то 103610, Тоже выше написал. Если про что -то еще, то я не понимаю про что.
Еще раз прошу всех прощения за то что из мухи сделал слона. Вообщем разобрался окончательно. Правильный ответ был: alter table wins add index xxx (LID,DrawNum,TckNum); И все работает мгновенно. А до этого меня приглючило что будет достаточно только PRIMARY KEY(`LID`,`DrawNum`,`Module`,`Tour`,`TckNum`)
Не хочу никого обидеть, но у меня такое впечатление, что 440Hz очень сильно заблуждается по поводу джоинов. Есть один знакомый очень хороший Джава-прогер. Последние лет семь работает с различными высоконагруженными системами. И он говорит, что нету ничего лучше Джоина по индексу, ведь джоины работают очень быстро и качественно. Еще он утверждал, что те кто боится Джоинов — боятся их просто из-за недостатка знаний об их устройстве.
Значит, ты утверждаешь, что количество пройденных записей равно перемноженному количеству записей всех таблиц: На консольном форуме сейчас не очень серьезная статистика, конечно, но для анализа вполне сойдет. итак, запрос: В таблице 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ы — это зло. Они — недостаточно компетенты. Джоины по индексам работают очень быстро и очень качественно. Это НАМНОГО лучше, чем несколько запросов.
Phantik Интересно, какая такая специфика задачи диктует такой праймари? По моему ВСЕГДА можно сделать один столбец праймари со значением инт, ну разве что диапазона может не хватить, но этого я еще не встречал. Пойми у тебя не только селект но и апдейт твой залетает. Каждый апдей переписывает индекса, а у тебя аж пять полей в нём. Ты понимаешь как это?
[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: <?php error_reporting(E_ALL); $db = mysql_connect('localhost', 'root', 'root'); mysql_select_db('test', $db); $i = 100000; while($i--) { $sql = 'insert into `second` (`sirname`) values ("' . rand(4, 5000000) . '")'; $res= mysql_query($sql, $db); $id = mysql_insert_id($db); $sql = 'insert into `first` (`name`, `second_id`) values ("'. rand(2, 80000) . '", ' . $id .')'; $res = mysql_query($sql, $db); } /////Джоин $sql = 'select `f`.`name`, `f`.`second_id`, `s`.`sirname` from `first` f left join `second` s on (`f`.`second_id` = `s`.`id`) where `f`.`id` = 10000'; //`f`.`id` < 10000'; $i = 1000; $AllQueryTime = 0; $AllPhpTime = microtime(TRUE); while($i--) { $start = microtime(TRUE); $result = mysql_query($sql, $db); $AllQueryTime += microtime(TRUE) - $start; while($row = mysql_fetch_assoc($result)) { $data = $row['name'] . ' ' . $row['second_id']. ' ' . $row['sirname'] . '<br/>'; } } $AllPhpTime = microtime(TRUE) - $AllPhpTime; echo 'Query: ' . $AllQueryTime . ' PHP: ' . $AllPhpTime . '<br>'; /////Антиджоин $sql = 'select `f`.`name`, `f`.`second_id`, (select `s`.`sirname` from `second` s where `s`.`id`=`f`.`second_id`) as `sirname` from `first` f where `f`.`id` = 10000'; //`f`.`id` < 10000'; $i = 1000; $AllQueryTime = 0; $AllPhpTime = microtime(TRUE); while($i--) { $start = microtime(TRUE); $result = mysql_query($sql, $db); if($result == FALSE) {echo mysql_error(); exit(0);} $AllQueryTime += microtime(TRUE) - $start; while($row = mysql_fetch_assoc($result)) { $data = $row['name'] . ' ' . $row['second_id']. ' ' . $row['sirname'] . '<br/>'; } } $AllPhpTime = microtime(TRUE) - $AllPhpTime; echo 'Query: ' . $AllQueryTime . ' PHP: ' . $AllPhpTime . '<br>'; ?> Не могу воспроизвести. Всегда Антиджоин дольше.
Эта совокупность полей является уникальным идентификатором записи. Это из лотерейной области. Совопукность этих полей определяет совокупность выигрышей определенной лотереи определенного билета определенного типа в определенном тираже.
Phantik Да это конечно круто, но лотерейная область и организация первичных ключей в СУБД это разные вещи. Вот скажи почему тебе надо делать именно эти пять полей первичным ключом? Что это дает?
А каким способом кроме автоинкремента, я могу задать уникальность записи? Вот я и делаю ключ на ту совокупность полей, которая может встречаться в таблице только 1 раз. Если убрать из этого ключа хоть одно поле, то он уже не будет уникальным.
По японски не надо, я и по русски ваши сообщения не понимаю. Я первичный ключ делал не ради прикола, а ради уникальности. Если есть какие-то другие способы задания уникальности, то я просто их не знаю. Но я, в принципе, и не делал публичных заявлений о том, что являюсь спецом в базах данных.
Первичный ключ делают для "первичного ключа", а уникальность это второстепенное - уникальность потому что первичность, а не наоборот. Поставь просто уникальные обычные ключи U, а первичный ключ сделай отдельным одним полем id, тогда у тебя сохраниться уникальность на уровне базы данных и запросы быстрее будут, потому что праймари будет по одному целочисленному столбцу.
Т.е. на практике ты предлагаешь при создании таблицы просто добавить поле автоинкремент и сделать его PRIMARY KEY, а те поля, которые у меня были праймери, описать просто как KEY? Я не совсем понимаю в чем между ними разница и на что это повлияет непосредственно в моем контексте. К тому же тогда связывать с другими таблицами по PRIMARY KEY не получится.
последняя попытка. Фантик, вы нагромоздили индексов не понимая как они работают и зачем, в этом и проблема. объяснения бесполезны, поскольку вы НЕ ХОТИТЕ понимать что вам говорят. записи в таблице в подавляющем большинстве случаев ДОЛЖНЫ иметь уникальный НОМЕР (ид). чтобы не искать адрес в городе по принципу "зеленый дом с голубой крышей, 4 этажный 2-подъездный с двумя деревьями рядом". связь с другими таблицами у вас сделана так же коряво.
обидеть можно только того, хто хочет быть обиженным. эт не ко мне. я не говорил, что JOIN зло, я хотел показать что может происходить. ессно при грамотной организации ключей ниче чего такого не будет. любой мало-мальский человек понимает что при нормальных ключах нет смысла бегать по всему масиву, а DB бегает по ключам. но тут ИМХО с ключами - капец. === JOIN не зло. Зло - непонимание происходящего.