глянь, возможно пригодится http://www.php.ru/forum/viewtopic.php?p=226643#226643 случайно подглядел идею в оскоммерце, но ее тамошняя реализация конечно крамешный капец как и весь оск в принципе)
PHP: <?php public function buildCountSql($key = '*') { $sql = $this->sqlTpl; if(preg_match("#select.*?(distinctrow|distinct).*?from#ism", $sql, $distinct)) { $key = strtoupper($distinct[1])." ".$this->db->escape($key); } else { $key = $this->db->escape($key); } $countSql = "SELECT COUNT(".$key.") `count` "; $regex = "(?:\sHAVING\s|\sORDER\s|\sLIMIT\s|\sPROCEDURE\s|\sINTO\s|\sFOR\s+UPDATE\s|$)"; preg_match("#(FROM.*?)$regex#ism", $sql, $sqlInner); $countSql .= $sqlInner[1]; return $countSql; }
phpdude Ага, а потом у тебя есть запросы с JOIN. В одном случае COUNT(*) нужно делать только по одной таблице без JOIN, в другой с JOIN, в третем у тебя FROM table1 JOIN table2 - а COUNT(*) FROM table2 идёт. А если оставлять лишние JOIN, то эффект от COUNT(*) сильно уменьшается, а то и ещё хуже чем от SQL_CALC_FOUND_ROWS. Так что не вариант, тут всё гораздо тоньше
Psih ну в этой ситуации да)) универсальное решение тяжелее найти)) я про среднячковые запросы имел ввиду), жойн то она хавает)) новоть исключить какой нить жойн это да
phpdude Исключение JOIN'а часто имеет разницу в скорости работы такую, что тогда можно и SQL_CALC_FOUND_ROWS использовать если оставить JOIN.
самый крутой подход, это когда ты не делаешь каунтов всяких и всё. Закончился фетч, не результатов запроса - вот тебе и всё как бы...
Напишите большими буквами над форумом "Читайте документацию" и закройте форум. Если кроме этой фразы сказать нечего. Я тебе не с документации разве приводил примеры? Нашел такое. Получается все опять же просто. Не желательно применять данную конструкцию для UNION. Но для просых запросов без UNION в работе ведет себя адекватно. То есть применение его в простых запросах обосновано. К тому же еще и быстрее работает. Считаем вопрос исчерпан? А применять ли данную конструкцию в коде или нет пусть каждый решает для себя. Для меня она достаточно удобная. Если знать в каких случаях лучше не применять а здесь хорошо этот случай описан то можно использвать без проблем. Использую ее давно и от вас только услышал что она работает где то некорректно.
mpak чел, пиши свой говнокод, и не парь людям мозг, которые знают больше тебя, поверь, больше. Ты ничего не докажешь, и не надо гнать на форум по поводу того что ТЫ зелёный.
mpak Ну как хотите, раз вы не способны сами довести дело до конца, не умеете или не хотите помучать гугль и не видите дальше своего носа, то я назову вас троллем, теоретиком, буквоедом и ещё кучей страшных обидных слов. У вас за спиной голая теория из мануала и ничего более. В реальности есть масса обстоятельств, которые всё меняют. К тому же часто документация не упоминает о подводных камнях или особенностях работы, потому что они всплывают только на практике и при некоторых условиях (в данном случае это незнание механики работы SQL_CALC_FOUND_ROWS + объемные таблицы). Начните с этого: http://www.mysqlperformanceblog.com/200 ... ound_rows/ - это блог основателей и авторов самого MySQL в том виде, в котором вы его сегодня используете. Данный блог один из самых точных и наиболее полных по внутренностям MySQL как таковым. Это что бы не быть голословным. А теперь немного логики и знания как работает MySQL изнутри: У вас есть запрос: SELECT field1, field2 FROM table WHERE field3 = 25 LIMIT 0, 30. Таблица состоит из 3-х полей типа int по 4 байта каждый По field3 у нас есть индекс. PRIMARY KEY индекс не учитываю, это ещё 4 байта умноженное на кол-во записей. Берём ситуацию с 1000 строчек. Данные весят 4 * 3 * 1000 + индекс 4 * 1000 = итого 16000 байт + внутренние расходы. При таком объёме данных они легко умещаются в RAM и их так мало, что можно даже не ставить индекс - всёравно всё будет работать моментально. Увеличим до 100 000 записей. Данных у нас на 4 * 3 * 100 000 ~ 1.17 MB + индекс. В общем-то тоже легко лезет в память и очень быстро фильтруется, хотя индекс уже даст о себе знать. Что COUNT(*), что SQL_CALC_FOUND_ROWS - особой разницы не будет. Давайте увеличим радикально объём данных и кол-во строчек. Возмём сразу 10 000 000, что кстати для соц. сети не много (к примеру оценки фоток за пол года набежало на 40 000 000 записей) - это уже ~150+ MB с данными и индексом. Более-менее объёмчик есть. В память влезет, но кол-во строк, которые надо перебрать будет занимать более-менее весомое время. Вот тут и начинается веселье и сказывается та самая разница, как работает COUNT и SQL_CALC_FOUND_ROWS. COUNT(*) для innodb просто считает сколько записей удовлетворяет условию. При этом основной запрос в данном случае работает так: берётся индекс и по нему отбираются записи. Как только набираем 30 штук - останавливаемся и возвращаем результат. Если ещё и ORDER BY по индексу, так вообще всё очень шустро, т.к. индекс сам по себе сортирован всегда. В результате выбрали 30 записей, потом сделали COUNT(*) который по индексу быстро подсчитал сколько там примерно записей и вернул результат. В случае с SQL_CALC_FOUND_ROWS всё работает уже совсем по другому. SQL_CALC_FOUND_ROWS говорит в запросе буквально следующее: отдай мне на вывод 30 записей, но посчитай сколько их всего есть. Это ВАЖНЫЙ момент. Выборка работает так-же по индексу, но выбирает не 30 записей, а ВСЕ которые удовлетворяют WHERE, т.е. происходит full index/table scan в зависимости от есть/нету индекса. Т.е. если по запросу из 40 миллионов записей соотвествует хотя-бы миллион, то весь этот миллион выбирается в буффер, сортируется, обрабатывается, записывается сколько в нём было записей и от него отсекается 30 нужных записей для отправки результата к клиенту. Чувствуете разницу между выборкой в буфер 30 записей и миллионом? Кол-во процессорного времени и памяти, используемое во втором случае в сотни и даже тысячи раз больше чем в первом случае. У вас даже может просто не хватить памяти при сложных запросах с JOIN и всё это полезет на хард в виде temporary table, что ещё сильнее всё усугубит. Апогеем будет когда вы пару вот таких многомиллионных таблиц свяжете через JOIN и влепите туда SQL_CALC_FOUND_ROWS. Поздравляю с запросами, которые работают по 2-5 секунд даже на очень мощьных серверах. Именно по этой причине SQL_CALC_FOUND_ROWS правильно работает в двух условиях, которые я знаю: * Поисковые запросы, где поиск часто идёт по полям, на которых нет индексов (20-30 индексов не сделаешь - база просто загнётся на UPDATE/INSERT/DELETE) * Сложные JOIN запросы, где в WHERE условиях фигурируют поля из JOIN'ed таблиц (и то не всегда) В остальных случаях COUNT(*) работает быстрее, частенько в десятки раз и с ростом объёма таблиц разница только растёт. Особенно это видно, когда запрос у вас типа такого? [sql] SELECT .... FROM t1 JOIN t2 ON t1.id = t2.t1_id JOIN t3 ON t1.id = t3.t1_id WHERE t1.status = "active" ORDER BY t1.added DESC LIMIT 0, 30 [/sql] По status и added ставим естественно индексы. В таком случае добавление SQL_CALC_FOUND_ROWS смерти подобно, особенно когда у вас данные быстро копятся. [sql]SELECT COUNT(*) FROM t1 WHERE t1.status = "active"[/sql] выполнится в купе с основным запросом быстрее, чем один с SQL_CALC_FOUND_ROWS гарантировано. Смотрите выше почему ещё раз, если не понятно.
зачем вобще тогда нужен калк? =( в случае с сорокамиллионной базой запрос вернет тридцать записей, но калк выдаст число миллион?
igordata Именно так и будет. И если COUNT(*) делает просто счётчик и не жрёт память, то CALC сделает temporary table со всеми вытекающими. А зачем он нужен я описал - запросы со сложными условиями (а особенно когда не на все поля есть индексы - тогда без него вообще никуда), в некоторых случаях с GROUP BY и прочие условия, которые в WEB реально встречаются не часто и в основном в проектах среднего и большого масштаба в единичных случаях на фоне общего кол-ва SQL запросов. А вот к примеру всякие корпоративные системы и прочий специализированный софт как раз может потребовать серьёзно думать где использовать COUNT(*), а где CALC_FOUND_ROWS
Psih та что ты ему объясняешь, чел реально думает, что он Бог программирования... udp: ну вы поняли, кому именно объясняешь..
Костян Плевать, зато всю злость выпустил. А вдруг работодатель его будущий/текущий прочитает топик на форуме и даст ему хорошего пинка из реальности?
да.. дружелюбненько тут у вас. зачем обсер то сразу устраивать? нормальная дискуссия получилась. я бы даже перенес в подфорум по оптимизации/производительности/итд
engager Да потому что это уже такая избитая тема, по которой столько информации в интернете, что только полный идиот будет спорить против.
Господа. Опять же хочу проверить все практическим путем. Есть таблица чуть меньше двух миллионов записей. SELECT * FROM mp_facebook_feed LIMIT 10 Время исполнения: 0.000181 c. SELECT COUNT(*) FROM mp_facebook_feed Время исполнения: 0.000104 c. COUNT(*) 1620373 Если верить всему вышесказанноу то CALC_FOUND_ROWS должен ужасно тормозить при током количестве записей так как если верить вышесказанному должен выбрать все записи из базы. Проверяем. SELECT SQL_CALC_FOUND_ROWS * FROM mp_facebook_feed LIMIT 10 Время исполнения: 0.000194 c. C учетом того что помимо количества записей из базы еще и вернулось какое то количество строк то это вполне достойный результат. Судя по скорости выборки я могу сделать вывод что алгоритм работы не тот что описал Psih. Хорошо видно что данный запрос все записи из таблицы не возвращаются. Вот как раз поэтому и нужно сомневаться во всем. Начитаются всякого говна пятригодичной давности. И живут в своем мирке. Думают что самые умные. Допускаю что в работе SQL_CALC_FOUND_ROWS на каком то этапе разработки mysql и были проблемы в работе. Но их уже давно пофиксили а вы друг другу так гавно в уши и льете что это шаманство оно глючит и тд. А проверить никто не может. Ссылку за все время обсуждения, какой то другой источник информации я только одну увидел. Пример плохо медленного или глючного запроса я так и не увидел. Хотя привел уже кучу ссылок и кучу примеров скорости работы. Обсуждение превращается в подобие. - Я лучше всех знаю мне даже в мануал не надо смотреть бла бла бла - Да вы все уроды я лучше знаю и проверять не буду я бог бла бла бла - Какие примеры в жопу все примеры я и сам знаю вы уроды я лучше всех бла бла бла ПРоверяйте то что пишите. И ищине информацию. То о чем вы говорите уже давным давно не актуально. Запрос хорошо работает при больших таблицах. На UNION только не проверял но и это думаю сделаю скоро. Запрос при котором данная конструкция работает некорректно или долго мне не смог привести никто. Во всех запросах которые я проверял SQL_CALC_FOUND_ROWS работает быстрее. Плюс другие плюсы этой конструкции. Некоторое время назад я спросил у одного человека о его мнении об mysql и он сказал что это гавно. Выяснилось что у него был опыт использования mysql лет пять назад на версии три какой то. В итоге он сделал выводы что это гавно и так и считает до сих пор. Так вот те кто меня убеждает что запрос не работает (хотя все тесты показывают обратное) похожи на этого человека. Я когда то пробовал и поэтому это так. А проверять как то не хочется.
ты кроме myisam табличек слышал что нить? ты знаешь чем они плохи? ты знаешь почем используют innodb? тесты у тебя опять сферические в вакууме, на них смотреть не интереснее чем ногти грызть на ногах ... хотя мне кажется что даже ногти грызть на ногах интереснее, имхо конечно.