кто нибудь подскажет альтернативу COUNT(*), а то делаю выборку по таблице в которой более 1млн записей, сама выборка проходит меньше 0 сек, а вот COUNT(*) по тем же параметрам WHERE работает более 10 сек, а то более 20 сек. Мне надо сделать постраничный вывод, а для этого я так понимаю обязательно знать сколько всего записей попадающих под условие WHERE. Выборка идёт по LIMIT-у и с ORDER BY. EXPLAIN: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE main range PRIMARY PRIMARY 4 NULL 602188 Using where спасибо за внимание.
http://dev.mysql.com/doc/refman/5.0/en/ ... found-rows Только не уверен, что тормоза исчезнут. Обязательно выводить полный список страниц?
если бы не стоял, то врядли выборка из млн записей шла бы меньше 0 сек конечно стоит, все условия из WHERE построены строго по индексным полям одно индекса. Я вывожу только 10 стр из всей выборки, но навигацию надо сделать с учетом общего кол-ва из COUNT(*)
Запрос в студию, это раз (и оформляйте вставки тегом [ code ] и SQL запросы [ sql ] тегом). Cтруктуру тоже в студию - два. У вас там что-то очень не хорошо.
CREATE TABLE `main` ( `datasort` int(11) unsigned NOT NULL default '1', `field1` mediumint(5) unsigned NOT NULL default '1', `data` int(8) unsigned NOT NULL default '1', `area` smallint(4) unsigned NOT NULL default '1', `field2` smallint(4) unsigned NOT NULL default '1', `field3` tinyint(1) unsigned NOT NULL default '1', `celm` tinyint(1) unsigned NOT NULL default '1', `cel1` tinyint(1) NOT NULL, `cel2` tinyint(1) NOT NULL, `cel3` tinyint(1) NOT NULL, `cel4` tinyint(1) NOT NULL, `kol` smallint(3) NOT NULL, `id` int(11) unsigned NOT NULL default '1', PRIMARY KEY (`datasort`,`field1`,`data`,`area`,`field2`,`feild3`,`celm`,`cel1`,`cel2`,`cel3`,`cel4`), KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; [SQL] SELECT `id` FROM `main` WHERE `datasort` > 0 AND `field1` = 7 AND `data` > '19601010' AND `data` < '19951010' AND `area` > 0 AND `field2` > 0 AND `field3` > 0 AND `celm` = 1 AND `cel1` > 1 AND `cel2` >=0 AND `cel3` >=0 AND `cel4` >=0 AND `kolfoto` > 0 ORDER BY `datasort` DESC LIMIT 0,10 [SQL] Показывает записи 0 - 9 (10 всего, Запрос занял 0.6881 сек) с COUNT(*) 7 секунд
насколько я понял необходимо переделать индекс на простой INDEX? а поле `ID` можно поставить первым и сделать его PRIMARY INDEX?
pioner7 Если у тебя в условии идет не жесткое сравнение (datasort = 12345), а более мягкое (datasort > 0), то пихать несколько полей в индекс не имеет смысла - это дополнительные поля все равно невозможно использовать для оптимизации выборки. Кроме того, попробуй запрос не с LIMIT 0,10, а с LIMIT 500000,10. Думается мне, что скорость будет сравнима с COUNT'ом.
datasort я ставлю на первое место потому что это поле у меня в ORDER BY и насколько я заметил опытным путем (я его перемещал в разные места) если поле из ORDER BY не первое в индексе то EXPLAIN показывает "file sort". Насколько я понимаю это плохо, а так только "Using where", поэтому мне все равно какое значение в datasort > 0. Может я ошибаюсь с order by, поправьте.
pioner7 Ты все правильно говоришь, datasort должен быть первым в индексе, раз уж по нему ты сортируешь, я лишь хотел сказать, что смысла цеплять к индексу дополнительные поля в твоем случае нет. По крайней мере индекс будет меньше места занимать, и операции добавления/удаления будут быстрее.
Это вообще лирика. Если я правильно перевел, тут говориться, что типа если хотите мульти-праймари кей, пишите его отдельно, ибо указывая праймари кей как свойство поля сделать мультипл кей нельзя.
Зы: а можно эксплейны в студию... - обычный запрос - обычный запрос без лимита - запрос с каунтом полностью, со временем исполнения Ну и просто запрос с каунтом... сколько строк и время
Первое что тебе нужно сделать - это залезть в мануал и прочитать, а еще лучше ПОНЯТЬ как используются индексы, когда используются индексы и как нужно строить запросы. Блин, ТАКОГО как я еще нигде не видел. Первое. Оптимизатор начинает использовать индексы ТОЛЬКО если по его предварительной оценке, количество записей в результате будет не более 30% от общего количества записей в таблице. Иначе, он абсолютно справедливо считает, что быстрее будет тупо перелопатить ВСЕ записи таблицы не используя индексы. Ну и сколько записей вернет условие `datasort` > 0 ? По твоему эксплайну оптимизатор считает 602188. Можешь тупо удалить любые индексы, скорость выполнения запроса будет та же. Второе. Посмотри на порядок условий в WHERE. Почитай мануал как он и на что влияет. Третье ... .... Восьмое ... И главное. Первое условие выбора в запросе ДОЛЖНО возвращать минимальное количество записей. Думаю понятно зачем. Почитай как работает COUNT и LIMIT. И никогда больше не пиши Тебе тут выше абсолютно справедливо заметили И т.д. и т.п.
[sql] EXPLAIN SELECT COUNT( * ) FROM `main` WHERE `datasort` >0 AND `f1` = '1' AND `data` <= '19730807' AND `data` >= '19240807' AND `f2` >0 AND `f3` >0 AND `celm` =1 AND `cel1` >1 AND `cel2` > -1 AND `cel3` > -1 AND `cel4` > -1 AND `f4` >0 AND `kolfoto` > -1 [/sql] Результат: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE main ALL datasort NULL NULL NULL 1002813 Using where [sql] EXPLAIN SELECT `f1` , `data` , `f2` , `cel1` , `cel2` , `kolfoto` , `id` , ( SELECT `name` FROM `uname` WHERE `id` = `main`.`id` LIMIT 1 ) FROM `main` WHERE `datasort` >0 AND `f1` = '1' AND `data` <= '19730807' AND `data` >= '19240807' AND `f2` >0 AND `f3` >0 AND `celm` =1 AND `cel1` >1 AND `cel2` > -1 AND `cel3` > -1 AND `cel4` > -1 AND `f4` >0 AND `kolfoto` > -1 ORDER BY `datasort` DESC LIMIT 0 , 10 [/sql] Результат EXPLAIN id select_type table type possible_keys key key_len ref rows | Extra 1 PRIMARY main range datasort datasort 4 NULL 338498 | Using where 2 DEPENDENT SUBQUERY uname eq_ref PRIMARY PRIMARY 4 myworld.main.id | 1 Далее вставил в скрипт перед выборками и после функцию echo microtime и вот результаты: Запрос 1 Выбрало 557 записей: перед выборками microtime = 0.59375500 1218115664 сразу после COUNT(*) и перед обычной выборкой с LIMIT 0,10 = 0.70165500 1218115667 после обычной выборки = 0.09092200 1218115668 Запрос 2 Выбрало 3885 записей: перед выборками microtime = 0.57813000 1218116665 сразу после COUNT(*) и перед обычной выборкой с LIMIT 0,10= 0.78304600 1218116668 после обычной выборки = 0.16738900 1218116669 Запрос 3 Выбрало 1 запись: перед выборками microtime = 0.15625500 1218116859 сразу после COUNT(*) и перед обычной выборкой с LIMIT 0,10 = 0.16158500 1218116862 после обычной выборки = 0.54541500 1218116872 Запрос 4 Выбрало 4583 записей: перед выборками microtime = 0.98437900 1218117017 сразу после COUNT(*) и перед обычной выборкой с LIMIT 0,10 = 0.11133700 1218117021 после обычной выборки = 0.49315100 1218117021 Запрос такой же как и 4 только с LIMIT 3000, 10 Выбрало 4583 записей: перед выборками microtime = 0.75000400 1218117453 сразу после COUNT(*) и перед обычной выборкой с LIMIT = 0.88853300 1218117456 после обычной выборки = 0.85412600 1218117462
Это непобедимо Мож расстреливать тех кто мануал читать не хочет. quote from manual Во всех остальных случаях перебираются ВСЕ записи. Забудь лимит. Читай мануал 5.2 Оптимизация SELECT и других запросов
ну ты интересный, лекго ляпнуть не используй LIMIT, а как на практике выбрать только 10 записей без LIMIT? а как делать навигацию без LIMIT 100,10 ? может подскажешь? Да ещё, если ты внимательно прочитаешь заголовок, то увидешь что у меня нет претензий к LIMIT, а только к COUNT(*).
Задаешь вопрос Тебя посылают на мануал, хотя наверное стоило бы подальше. Там написано как работает COUNT Там написано ЧТО нужно делать что бы было быстрее В твоем эксплайне черным по белому написано где у тебя тормоза И насрать на то сколько времени у тебя выполняется запрос с LIMIT'ом COUNT от этого быстрее работать не будет А точное количество записей ты по другому не получишь. А если ты не только мануал не прочитал , но и то что в топике написано Выбирает у тебя по 500-5000 записей, а в эксплайне А теперь попробуй извилины напрячь и понять , что у тебя не так.
тогда предложи вариант, как сделать ORDER BY `datasort` так что бы EXPLAIN не показывал Use filesort? я знаю что, это у меня узкое место.