Ru-Board.club
← Вернуться в раздел «Web-программирование»

» Оптимизация запроса MySQL

Автор: rtyug
Дата сообщения: 17.11.2009 20:54
LFO

это понятно, а с двух таблиц можно ли удалить, я в предыдущем посту хотел спросить именно это


Цитата:
но стоит ли, зависит от того, сколько запоросов на удаления


может быть всего штук 10 с 2-4 таблиц

как правильнее:
тут нужно это написать в одном запросом или можно много маленьких запросов делать?



Автор: israel_rider
Дата сообщения: 28.11.2009 09:34
Отловил профайлером тормозящий запрос. Вот он:

SELECT hash,
(SELECT COUNT( photos.hash ) FROM photos WHERE photos.hash = uploads.hash) AS count
FROM uploads HAVING count=0

Время - 0.6 сек. Вроде многовато...
Вопрос. Можно ли его переписать подругому?
Автор: Cheery
Дата сообщения: 28.11.2009 20:56
SELECT uploads.hash, tmp.cnt FROM uploads, (SELECT hash, COUNT(hash) cnt FROM photos GROUP BY hash) tmp WHERE tmp.cnt=0 AND uploads.hash=tmp.hash
может быть сообщение об ошибке, но что то в этом роде
чтобы этот запрос по подсчету выполнялся один раз
Автор: israel_rider
Дата сообщения: 28.11.2009 21:07
Cheery, плиз, можно ссылочку, где можно почитать, что это -
tmp.cnt
такое? Или хотя бы название этого, что бы вбить в Гугл.
cnt это алиас, это понятно. а tmp ?
Извиняюсь, вроде понял, tmp это тоже алиас. Просто я привык, что алиасы пишут через AS

Добавлено:
Вообще то, в мануале написано, что всё это делается гораздо проще.
[more]
Если запись для правой таблицы в частях ON или USING в LEFT JOIN не найдена, то для данной таблицы используется строка, в которой все столбцы установлены в NULL. Эту возможность можно применять для нахождения результатов в таблице, не имеющей эквивалента в другой таблице:
mysql> SELECT table1.* FROM table1
LEFT JOIN table2 ON table1.id=table2.id
WHERE table2.id IS NULL;

Этот пример находит все строки в таблице table1 с величиной id, которая не присутствует в таблице table2 (т.е. все строки в table1, для которых нет соответствующих строк в table2). Конечно, это предполагает, что table2.id объявлен как NOT NULL.
[/more]
Но проблема в том, что у меня в таблице то как раз поле hash объявлено как NULL. А менять на NOT NULL стрёмно.
Автор: Cheery
Дата сообщения: 28.11.2009 21:23
israel_rider

Цитата:
Просто я привык, что алиасы пишут через AS

это необязательно.
Автор: israel_rider
Дата сообщения: 28.11.2009 21:27
MySQL returned an empty result set (i.e. zero rows). ( Query took 0.0837 sec )

Cheery, огромный сенкс, только ещё разобраться в нём до конца надо.
Автор: Cheery
Дата сообщения: 28.11.2009 22:22
israel_rider

Цитата:
MySQL returned an empty result set (i.e. zero rows). ( Query took 0.0837 sec )

ну так ничего не вернуло же. я сказал, что что то в этом роде, но не гарантировал, что будет работать
Автор: israel_rider
Дата сообщения: 28.11.2009 22:28
Да нет же! Всё правильно. Старый запрос работал точно так же. Это запрос, что бы находить поля, заполненые только в одной таблице, и не имеющие соответствия во второй. В данный момент все записи исправны, поэтому, естественно, запрос ни чего находить не должен.
Автор: UncoNNecteD
Дата сообщения: 17.12.2009 10:25
Давайте еще про оптимизацию:
Есть таблица
country    smallint(5)
city    smallint(5)
typeid    smallint(5)
datefill    mediumint(8)
num    float(8,2)
kod    int(11)
Записей около 350 000.

индексы определены:
Primary:
country
city
typeid
datefill

trrindex)
typeid
city
country

reg_df: (index)
datefill
country

Запрос, выбирает последнюю дату, для которой есть запись о статистике по нужной country:
SELECT `datefill` FROM `tablestat`
WHERE `country` = '123'
ORDER BY `datefill` DESC
LIMIT 1

Работает медленно (до 0.5 сек)
Предложения по оптимизации?
Автор: andead
Дата сообщения: 17.12.2009 18:06

Цитата:
Предложения по оптимизации?

CREATE TABLE скопируйте сюда, и EXPLAIN запроса желательно
Автор: APTEM
Дата сообщения: 17.12.2009 18:31

Цитата:
Работает медленно (до 0.5 сек)
Предложения по оптимизации?
в первичном индексе datefill поставь сразу после country
Автор: UncoNNecteD
Дата сообщения: 17.12.2009 20:16
APTEM
Гениально. Дайте покурить маны на тему!

EXPLAIN изменился так:
1    SIMPLE    tablestat    ref    PRIMARY    PRIMARY    2    const    53016    Using where; Using index
1    SIMPLE    tablestat    ref    PRIMARY    PRIMARY    2    const    49437    Using where; Using index; Using filesort

Ожидать теперь проблем с другими запросами к этой таблице?
Почему не использовался индекс reg_df ?

Время запроса уменьшилось до 0.0005 сек!!
Спасибо!
Автор: APTEM
Дата сообщения: 17.12.2009 22:43
индексы строятся исходя из используемых запросов. если первичный ключ построен на col1, col2, col3 (именно в таком порядке), то сервер БД может использовать фрагменты col1+col2+col3, или col1+col2, или col1 для оптимизации поиска в таблице. если нужен поиск по col1+col3, следует дополнительно создать индекс по этим двум полям. разрывы в перечне полей недопустимы - сервер в этом случае откинет те поля индекса, которые попадают в разрыв и идут после него.

в твоём случае ключ построен по country+city+typeid+datefill, а в запросе используются поля `country`+`datefill` (именно в этом порядке, ибо сначала происходит ограничивание индекса диапазоном, а потом сортировка в диапазоне)

в результате сервер использовал единственный подходящий (пусть и не 100%) индекс - первичный. перестановка полей первичного индекса позволила серверу использовать ключ в данном запросе на 100%. индекс reg_df построен по полям в неподходящем порядке, поэтому был откинут сервером, как неудачный для данного запроса.
Автор: UncoNNecteD
Дата сообщения: 17.12.2009 23:54
APTEM
Спасибо еще раз, пшел дальше искать тяжкие запросы.

А что есть filesort в explain?
Автор: rtyug
Дата сообщения: 17.12.2009 23:59
хотел вывести одим запросом ближайщие подкатегории, так сделано тут например: http://yaca.yandex.ru/yca/cat/Entertainment/

категори: Игры
подкатегории: 3D-шутеры, RPG, стратегии, Флеш-игры ...

работает


Код: SELECT t3.id_se, t3.name_se, t3.parent_se_id
FROM section AS t3
WHERE t3.parent_se_id = 1


UNION ALL

SELECT t1.id_se, t1.name_se, t1.parent_se_id
FROM section AS t1
WHERE
t1.parent_se_id = t3.id_se
Автор: DarkSmoke
Дата сообщения: 18.12.2009 12:50
есть бд

Код: CREATE TABLE `Users` (
`id` int(10) unsigned NOT NULL auto_increment,
`login` tinytext NOT NULL,
`password` tinytext NOT NULL,
`status` enum('0','1') NOT NULL,
`date` date NOT NULL,
`activate` tinytext NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1 ;
Автор: andead
Дата сообщения: 18.12.2009 16:00

Цитата:
какой запрос будет работать быстрее и почему

если у вас не терабайт данных, то оба запроса отработают одинаково


Цитата:
Как можно самому узнать какой запрос быстрее?

запоминаете время до выполнения и после, вычитаете
Автор: DarkSmoke
Дата сообщения: 18.12.2009 16:41

Цитата:
запоминаете время до выполнения и после, вычитаете

так это меньше секунды, мне что с секундомером сидеть? Другие способы есть?


Цитата:
если у вас не терабайт данных, то оба запроса отработают одинаково

Ну пускай будут пару тысяч логинов или даже 10000
Автор: israel_rider
Дата сообщения: 18.12.2009 17:34
Удалено
Автор: andead
Дата сообщения: 18.12.2009 17:39

Цитата:
так это меньше секунды, мне что с секундомером сидеть?

надеюсь это шутка если нет то вам сюда


Цитата:
Другие способы есть?

phpMyAdmin
Автор: DarkSmoke
Дата сообщения: 19.12.2009 10:04

Цитата:
phpMyAdmin

а как через него смотреть?

Все разобрался. Спасибо!
Автор: DarkSmoke
Дата сообщения: 19.12.2009 15:07
Подскажите, пожалуйста, чего не работает:

Код: INSERT INTO `Users` SET `activate`='1' WHERE `login`=(SELECT `login` FROM `Users` WHERE `login`='dеее@ukr.net' LIMIT 1) LIMIT 1
Автор: derelict
Дата сообщения: 19.12.2009 15:16
DarkSmoke
Зачем ты выбираешь логин по значению логина? И скорее всего надо не INSERT, а UPDATE использовать:

Код:
UPDATE `Users` SET `activate`='1' WHERE `login`='dеее@ukr.net'
Автор: substrackto
Дата сообщения: 19.12.2009 15:24
DarkSmoke
1 вы выбираете и вставляете в одну и ту самую таблицу - одного и того самого юзера (может вам апдейт нужно сделать?)
2 в команде инсерт нету лимита
Автор: DarkSmoke
Дата сообщения: 19.12.2009 15:25
Все решил, для ИНСЕРТА ВХЕРЕ нет
Автор: UncoNNecteD
Дата сообщения: 20.12.2009 22:26
Зато есть REPLACE
Автор: israel_rider
Дата сообщения: 15.01.2010 19:58
Возникла следующая нелепая проблема. Вызвал шеф, и произнёс такую фразу:
"Такой то сайт зависает, из за неправильных запросов к БД. Необходимо решить проблему. Для этого используй LOAD" .
И теперь я ломаю голову, что он имел в виду!
Выполнить профилирование, выявить запрос, вызывающий зависание - это всё понятно и очевидно.
Но что он имел в виду, употребив слово "LOAD"? И какое это имеет отношение к профилированию??? Я страшно боюсь сесть в лужу, если потом вдруг воясниться, что действительно существует какой то метод профилирования или деббагинга, связанный со словом "LOAD", а я о нём ничего не знал.
Помогите, плиз! Что там может быть связано со словом "LOAD"?

Добавлено:
А может, это просто существует какой то профайлер, который запускается командой "LOAD"?
Автор: andead
Дата сообщения: 15.01.2010 20:44
шеф наверное сам не в курсе что это такое)
Автор: israel_rider
Дата сообщения: 15.01.2010 20:51
Правильно ли я Вас понял, что термин "LOAD" относится непонятно к чему, и к профилированию БД, во всяком случае, отношения не имеет точно?
Автор: APTEM
Дата сообщения: 15.01.2010 22:13
может, шеф имел в виду OLAP?

Страницы: 1234

Предыдущая тема: PHP: библиотека xAJAX


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.