Pull to refresh

Comments 67

Еще полезно выбрать правильный сервер баз данных. В зависимости от задач оптимальным по быстродействию может быть и MySQL, и PostgreSQL, и Oracle, и mSQL…
>> list ($usec, $sec) = explode (' ', microtime());

Господа, ей богу, аргумент у microtime() уже ввели хз сколько лет назад. Хватит жить в прошлом веке.

>> WHERE FIND_IN_SET(12,otherproductids);
Вы шутите?! Такое писать в статье про оптимизацию.

>> Есть также и другой способ записать эти запросы, но без JOIN:
Если ключевого слова JOIN не видно — это не значит, что его там нет.

В общем и целом — статья противопоказана к чтению новичками, которые могут сделать из всей этой кучи слов неверные выводы.
>> Столбцы, которые используются в JOIN (в примере — customerid), должны быть проиндексированы в первую очередь.
Любые столбцы, используемые для поиска должны быть проиндексированы.
Я согласен, некоторые приемы, описанные в статье, могут быть некорректными, но направление для поиска узких мест в производительности сайта эта статья даёт.
Библия может и врать про существование бога, но направление для праведной жизни она даёт…
Может всё же УК больше даёт направления к праведности?!
Вместе с очень хорошими методиками (вроде замены NOW() на дискретное значение времени) — в статье настолько много воды и всяких «странных» утверждений типа:

>> Перед запуском этой функции следует подключиться к базе данных. Большинство современных сайтов делают это автоматически

>> Если на странице выводится сразу информация о 100 заказах, нужно будет делать уже 101 запрос.
(IN придумали для слабаков, ага)

>> Но таблица с заказами, вероятно, будет постоянно меняться — в этом случае нужно быть осторожнее с индексацией.
Постоянно?! Эта статья для новичков же — откуда у вас нагрузки амазона и ебея?!

>> wget -O /dev/null -q www.mywebsite.co.uk/runhourly.php

Ну и скриншот «сложного» (запрос с 2 джоинами с объединением по FK это теперь сложный!) запроса из WP, который мало того, что написан не совсем логично (условия из WHERE нужно перенести в ON, и да — я знаю, что оптимизатор mysql это и так сделает, но я говорю о семантике), так ещё и индексы нужные не проставлены (или mysql их не использует по непонятно каким причинам).

Повторюсь, в статье материал излагается сумбурно, как будто автор вспоминал по ходу дела все знания, которые накопил за всю практику. Мечется с одного, на другое, не раскрыв мысли и давая сомнительного качества аналогии.

Лично я на эту статью (перевод или оригинал, не принципиально) ссылаться как на «пособие» по оптимизации не стал бы — благо в документации по mysql есть обширная глава, которая покрывает всё описанное (и, естественно, гораздо глубже и в большем объёме).
Это перевод статьи. Если она вам не нравится, ставьте минус за статью, зачем карму минусовать? Выкладывают ведь такие статьи на SM, да и почти 50 добавивших в избранное за час ничего не значит?
Сударь, а я-то при чём?! Я вам поставил +1, за перевод. А в профиль минусовать карму вообще не ходил.

Обсуждаю я не качество перевода, а качество переводимого материала.
Я промахнулся с комментарием) Говорил не лично вам)
Но вам за критику переводимого материала карму плюсанул.
>> да и почти 50 добавивших в избранное за час ничего не значит

Лично для меня — нет, не значит. Я как считал статью бесполезной и вредной, так и считаю до сих пор.

Не принимайте мою критику на личный счёт — я обсуждаю материал (автором которого является другой человек), а не конкретно ваш перевод.
не мог удержаться, чтобы не сказать
«миллионы мух не могут ошибаться»
> Любые столбцы, используемые для поиска должны быть проиндексированы.

Индексы бывают разными, в том же PostgreSQL есть возможность выбора между индексами на основе Хеша, B-дерева, R-дерева. Вопрос какой лучше?

B-дерево используется по умолчанию, но для поиска/выборок основанных на проверке равенства (WHERE… = ...) хеш-индекс должен быть быстрее, R-индекс в свою очередь должен быть быстрее при работе с геометрическими типами данных…

Я сказал «должен быть», потому что это теория, а на практике часто оказывается, что B-деревья быстрее (по крайней мере так было в старых версиях PostgreSQL. возможно в 9.* изменилось).

Что же касается выборок со сложными запросами, то есть еще Функциональные индексы (индекс не по значению данных, а по значению некоторой функции от них). Вот о них в первую очередь надо рассказывать новичкам, в разделе о построении индекса. Например, когда вы используете поиск по текстовым полям без учета регистра (а я обычно ищу без учета регистра), то можно построить такой индекс:

CREATE mytable_upper_text_key ON mytable (upper(mytext));

после этого наслаждаться ускорением запроса

SELECT id FROM mytable WHERE upper(mytext) = 'ИВАНОВ';
Естественно. А в оракле ещё бывают битмапы. А ещё в оракле есть компрессия столбцов индексов. А ещё (в куче субд) есть function-based индексы (вы про них сказали, угу). Я не говорил, что индексы — простой инструмент. Это сложный инструмент, и как любой инструмент он должен применяться контекстно, в зависимости от решаемой проблемы.

Но я-то говорил о том, что фраза из статьи про джоин и индексы натянута, ибо индексировать нужно всё.
Статья мутная, я согласен. Похожа на причесанные заметки начинающего вебмастера, у которого сложилась полная начальная картина работы сайтов на основе бд.
А еще… каждый индекс будет замедлять изменения значений и советовать создание индексов на все поисковые поля — это чересчур категорично. Особенно битмапы.
Про битмапы — отличный аргумент :-) Буквально недавно на блокировку при обновлении битмапов наступал.

Но всё равно — это мало касается целевой аудитории статьи — новичков. У них и объёмов и нагрузок нет.
А по поводу «на все поисковые поля» — ну вот давайте представим, что у нас есть таблица хотя бы на 100М записей.

Какие категории запросов есть смысл не покрывать индексами? Навскидку могу придумать рабочие запросы из ПО и редкие запросы на аналитику. Для обоих типов я бы покрыл индексами всё что нужно.

Приведёте пример типов, когда этого делать не стоит?
В таблице возможно, что необходимо искать по всем полям — для всех полей создавать индексы? Это тема вообще слишком большая, чтобы хоть что-нибудь категорично утверждать. Не говоря уже о том, что не так уж редко что фулскан быстрее беготни по индексам.
Для тех, кто не знает о NoSQL и для тех, у кого понятия «динамический контент» и «PHP» являются синонимами.
«Сокращаем количество запросов, используя JOIN»
— Выпал в осадок. Благодаря таким как Вы, мы имеем тысячи быдлокодеров, которые не умеют правильно использовать JOIN. Ни слова о том, что не следует применять JOIN на большие таблицы.

К тому же phpMiniAdmin — медленный, небезопасный и ограниченный по функциональности. Я лично советую использовать HeidiSQL.
>> Ни слова о том, что не следует применять JOIN на большие таблицы.

Слишком безапелляционно :-) Что не так с джоином и большими таблицами?
Попробуйте JOIN-ом бездумно соединить пару таблиц, в которых по несколько миллионов записей — это может занять очень много времени, т.к. при этом создаётся ещё более огромная таблица.
JOIN — хороший и удобный инструмент, но он всё таки имеет некоторые ограничения в применении.
ну в принципе любой бездумный запрос может занять очень много времени :)
это может занять очень много времени, т.к. при этом создаётся ещё более огромная таблица.

кто вам такую глупость сказал? О.о
попробуйте так же бездумно сделать select по этим же таблицам. выяснится, что join ничем не хуже select'ов.
Все просто. Если не накладывать на выборку никаких ограничений, то действительно результатом запроса будет здоровая временная таблица. Но, если гармотно наложить условия выборки, то нормальный оптимизатор запросов сначала отфильтрует входящие в запрос таблицы и лишь потом будет джойнить то что от них осталось, таким образом в результате джойна десятка многомиллионных таблиц можно получить вменяемое количество строк почти мгновенно. Просто нужно понимать как себя ведет оптимизатор и грамотно накладывать условия выборки. А для этого нужно либо знать, либо анализировать execution plan/explain/etc.

ну в принципе любой бездумный запрос может занять очень много времени :)

ППКС
Всё так. Правда, работают медленно. Еще и лочат таблицы, создавая очередь запросов.
Для среднего магазина может быть и не критично, а вот для какой-дь онлайн-игры — очень даже.
Откуда вы взяли про локи? JOINы работают нормально, и никого не лочат.
>HeidiSQL
А мне вот нравится EMS MySQL Manager, или DevArt dbforge for Mysql, на худой конец.

И про джойны на больших таблицах хотелось бы услышать. Если кв какой-нибудь реализации SQL они работают отвратно то это еще не значит что так везде. Опять же джойн джойну рознь, и без проверки планов выполнения говорить о том что «это зло» рановато, имхо.
Переименуйте в «как чуток соптимизировать сайт, сделанный быдлокодером».
Не относится к личной БД, но все же обратите внимание на скорость загрузки внешних дополнений (если они у вас есть): «оставьте отзыв», «одна кнопка» и т.п. которые встраиваются в html.
Мой «site performance» они просадили с 0,5сек до 2,7сек.
Аналогично. Яндексовые счётчик и реклама загружаются медленнее, чем сайт.
Тогда добавлю ещё «google-analytics.com» (300мс), накинул мне 50% времени.
Но он очень хорош.
А вы их после загрузки встраивайте. Без них пользователь как-нибудь перекантуется пару секунд.
Разумеется они асинхронно грузятся после загрузки собственно контента и пользователь никак не страдает от моих желаний посчитать его, показать ему контекстной рекламки…

Только гуглеизмерялке оптимизированности сайта до этого нет дела.
Даешь инновационные идеи на хабре!
Наткнувшись в статье про оптимизацию БД на SELECT * FROM сразу бросил читать это…
Сейчас изучаю как устроен небольшой интернет магазин, 50% кода по объему это инсерты и селекты в таблицах с десятками полей, которые естественно перегоняются в обычные ассоциативные массивы.

Возникает вопрос а нафига козе боян, т.е. все эти SQL базы, навороты поверх в виде кеширования мемкешед? Не проще ли хранить массивы в нативном формате прямо в оперативной памяти? Только за счет неиспользуемых полей экономим разы в объемах.

В конце концов небольшая БД пусть со 100.000 объектов по килобайту это всего 100Мбайт оперативной памяти, т.е. SQL еще не нужен.

А БД с миллиардом записей и десятками тысяч подключений уже для SQL уже слишком тяжелый процесс, там уже отказ от единого сервера и переход к noSQL.

Не пора ли уже что то придумать, чем заниматься оптимизацией архаизмов?
«Не проще ли хранить массивы в нативном формате прямо в оперативной памяти?»

Есть такое — Oracle TimesTen, но там свои проблемы.
В нормальных проектах надежность важнее скорости.
На этом все.
Простите, нормальные проекты используют MySQL?

Хороший SQL код это прежде всего хранимые процедуры — Oracle, Postgres. Почти все хорошие биллинги построены на хранимых процедурах и молотят терабайты данных в реалтайме. Вот там надежность.

И кстати, такая штука про которую я говорил есть и активно развивается, называется Redis. C надежностью там все хорошо, можно настроить запись на диск тремя способами.
Спасибо тем, кто видя отличное от своего мнение не утруждает себя написанием обоснованных комментариев, а молча бежит минусовать карму.

Благодаря вам я стараюсь прикладывать больше сил чтобы писать более интересные посты для хабра (чтобы иметь возможность иногда свободно писать что думаю). Надеюсь что голос потраченный на меня спасет другого парня, который разозлит вас еще больше.

Однако если повернутся лицом к реальности, когда разрабатывали SQL, то 1 Габайт был недостижимым размером для винчестеров. Сегодня невозможно купить планку оперативной памяти меньше 1Гб, а noSQL стремительно развиваются в сторону повышения надежности и удобства (с производительностью и масштабируемостью там изначально хорошо).
Автор не указал элементарные вещи. Например, то, что запрос
SELECT * FROM orders
выполняется медленнее, чем
SELECT столбец1, столбец2, все остальные столбцы FROM orders
Более того — его результат не предсказуем для приложения при изменении структуры таблицы.
В двух конкретно приведённых запросах — не могли бы вы привести конкретный пример, когда эта «непредсказуемость» может привести к чему-то плохому?

Для определённости представим, что код был написан не последним идиотом и в коде мы обращаемся к столбцам по имени, а не по порядковому номеру.

Приведёте?
Я же попросил конкретный пример для конкретных двух запросов, когда результат будет «непредсказуем».
Изменение плана — достаточно непредсказуемо? Или исчезновение строк при использовании VPD и появлении в таблицы колонки, где прав не хватает? И еще куча примеров, которые там обозначены.
Изменение плана — это не изменение результата. Результат выполнения запроса — выборка. План — процесс его выполнения.

Про VPD — такого в оракле (?) не знаю, а мы говорим о mysql вообще.
То есть если запрос стал работать неожиданно медленно, то это нормально?
Появление лишних столбцов в запросе тоже?
мы говорим о mysql вообще
То есть в mysql надо писать как попало? Странно…
VPD — citforum.ru/database/oracle/vpd/
Про VPD — очень клёво, спасибо! (недавно такую задачу решал костылём через вьюху + контекст).

Про остальное:
лично я привык писать код, который работает корректно при наличии необходимого набора столбцов, вне зависимости от наличия новых (которые я не использую так и так). Так что — нет, для меня появление лишних столбцов в коде не неожиданно, потому как поведение кода не изменится.

Про «неожиданно медленно» — вот из-за таких фраз новички потом на каждом углу и орут, что * это плохо (всегда). Опять же — перечисление столбцов не гарантирует быстрых выборок. Более того — перечисление столбцов быстрее только в ряде случаев (когда все они уже есть в индексе, например). Это частные случаи. Они должны оптимизироваться адресно, опытным ДБАшником (потому что часто программисты в деталях работы CBO не разбираются).
С другой стороны — бывают «широкие» таблицы по 20 столбцов, из которых нужно выбрать 10. В этом случае перечисление столбцов только ухудшит читабельность, не привнеся (почти наверняка) ничего к производительности (да, данных больше передаётся по сети, но их не всегда же настолько больше, что мы это заметим).

Дополнительно хочу отметить: я не защищаю * и не говорю, что select * нужно писать всегда, но я придерживаюсь мнения, что до тех пор, пока нет явной и очевидной причины перечислять столбцы — лично я оставлю *, для того чтобы запрос оставался более читабельным, как результат — более простым в поддержке.
Так что — нет, для меня появление лишних столбцов в коде не неожиданно, потому как поведение кода не изменится.

Про клопов по ссылке не прочитали значит? Допустим, в коде вам нужно 5 полей, а в таблице их 10-20-30, да еще и row-chaining… Поведение кода-то не изменится, но замедление будет фантастическим, кэш забьется ненужным мусором, да еще и таскать между базой и клиентом лишние мега/гигабайты ненужных данных…
Я предпочитаю кешировать результаты работы отдельных функций, которые напрямую от числа столбцов не зависят.
В этом случае перечисление столбцов только ухудшит читабельность
напротив, улучшит ясность — что и откуда берем. особенно в серьезных больших запросах.
Про большие запросы я согласен, но там это как-то получается само собой.

Я всегда начинаю любой запрос с SELECT *, и уже потом уточняю, если нужно.
Хорошая статья. Еще в 2000ом году такое читал.
А почему вы используете PHP-модуль mysql а не более современный и быстрый mysqli?
Не то чтобы плохая статья, но процент шизы (типа оптимизации таблиц после коннекта к базе) слишком высок, чтобы рекомендовать её новичку.
Такое ощущение, что автор неделю назад узнал, что бывает такая база данных — mysql, и именно она стоит на его блоге.
Не ту статью вы выбрали для перевода.
Это тот случай, когда комментарии несут больше полезной информации, чем сама статья.
так вот чего меня директор чуть не скушал, когда сайт начал загружаться за 3-4 секунды…
А почему про SphinxSearch никто ничего не сказал? Memcached упомянули, а сфинкс забыли.
Думаю не один я буду признателен, если автор перезальёт картинки. спасибо=)
Sign up to leave a comment.

Articles