Оптимизация индекса mysql для таблицы с несколькими индексами, которые индексируют одни и те же столбцы - PullRequest
5 голосов
/ 07 апреля 2010

У меня есть таблица, в которой хранятся некоторые основные данные о сессиях посетителей на сторонних веб-сайтах.Это его структура:

id, site_id, unixtime, unixtime_last, ip_address, uid

Существует четыре индекса: id, site_id/unixtime, site_id/ip_address и site_id/uid

Существует много различных способов, которыми мызапросите эту таблицу, и все они относятся к site_id.Индекс с unixtime используется для отображения списка посетителей за заданный диапазон дат или времени.Два других используются для поиска всех посещений с IP-адреса или «uid» (уникального значения cookie, созданного для каждого посетителя), а также для определения, является ли это новым посетителем или возвращающимся посетителем.

Очевидно, что хранение site_id в 3-х индексах неэффективно как для скорости записи, так и для хранения, но я не вижу никакого способа обойти это, поскольку мне нужно иметь возможность быстро запросить эти данные для определенного конкретного site_id.

Любые идеи по созданиюэто более эффективно?

Я действительно не понимаю B-деревья, кроме некоторых очень простых вещей, но более эффективно иметь самый левый столбец индекса, который будет иметь наименьшую дисперсию - правильно?Потому что я решил, что site_id будет вторым столбцом индекса для ip_address и uid, но я думаю, что это сделает индекс менее эффективным, так как IP и UID будут различаться больше, чем идентификатор сайта, потому что у нас всего около 8000уникальных сайтов на сервер базы данных, но миллионы уникальных посетителей на всех ~ 8000 сайтах ежедневно.

Я также рассмотрел возможность полного удаления site_id из индексов IP и UID, так как шансы того же посетителя возрастаютк нескольким сайтам, которые совместно используют один и тот же сервер базы данных, довольно мало, но в тех случаях, когда это происходит, я боюсь, что будет довольно медленно определить, является ли это новый посетитель этого site_id или нет.Запрос будет выглядеть примерно так:

select id from sessions where uid = 'value' and site_id = 123 limit 1

... поэтому, если этот посетитель посетил этот сайт раньше, ему нужно было бы найти только одну строку с этим site_id, прежде чем он остановился.Это не обязательно будет супер быстро, но приемлемо быстро.Но скажем, у нас есть сайт, который получает 500 000 посетителей в день, и конкретный посетитель любит этот сайт и посещает его 10 раз в день.Теперь они впервые попадают на другой сайт на том же сервере базы данных.Приведенный выше запрос может занять довольно много времени для поиска во всех потенциально тысячах строк этого UID, разбросанных по всему диску, поскольку он не найдет ни одного для этого идентификатора сайта.

Любое пониманиеза то, чтобы сделать это как можно более эффективным, было бы полезно:)

Обновление - это таблица MyISAM с MySQL 5.0.Мои опасения касаются как производительности, так и места для хранения.Эта таблица предназначена для чтения и записи.Если бы мне пришлось выбирать между производительностью и хранилищем, меня больше всего беспокоит производительность, но обе важны.

Мы интенсивно используем memcached во всех областях нашего сервиса, но это не повод, чтобы не заботиться о дизайне базы данных.,Я хочу, чтобы база данных была максимально эффективной.

Ответы [ 3 ]

4 голосов
/ 08 мая 2010
Я действительно не понимаю B-деревья, кроме некоторых очень простых вещей, но более эффективно иметь самый левый столбец индекса, который будет иметь наименьшую дисперсию - правильно?

Существует одно важное свойство индексов B-дерева, о котором вам необходимо знать: можно (эффективно) искать произвольный префикс полного ключа, но не суффикс . Если у вас есть индекс site_ip(site_id, ip) и вы запрашиваете where ip = 1.2.3.4, MySQL не будет использовать индекс site_ip. Если бы вместо этого у вас было ip_site(ip, site_id), MySQL мог бы использовать индекс ip_site.

Второе свойство индексов B-дерева, о котором вам также следует знать: они отсортированы. Индекс b-дерева можно использовать для запросов типа where site_id < 40.

Существует также важное свойство накопителей на дисках: последовательное чтение - это дешево, а поиск - нет. Если используются какие-либо столбцы, которых нет в индексе, MySQL должен прочитать строку из данных таблицы. Это обычно поиск, и медленно. Так что, если MySQL считает, что он прочитает даже небольшой процент таблицы, такой, как эта, он будет игнорировать индекс. Одно сканирование большой таблицы (последовательное чтение) обычно выполняется быстрее, чем случайное чтение даже нескольких процентов строк в таблице.

То же самое, кстати, относится и к поиску по индексу. Нахождение ключа в B-дереве на самом деле потенциально требует нескольких поисков, поэтому вы обнаружите, что WHERE site_id > 800 AND ip = '1.2.3.4' может не использовать индекс site_ip, потому что каждый site_id требует нескольких поисков индекса, чтобы найти начало записей 1.2.3.4. для этого сайта. Однако будет использоваться индекс ip_site.

В конечном счете, вам придется либерально использовать бенчмаркинг и EXPLAIN, чтобы определить лучшие показатели для вашей базы данных. Помните, что вы можете свободно добавлять и удалять индексы по мере необходимости. Неуникальные индексы не являются частью вашей модели данных; они просто оптимизация.

PS: сравнительный тест InnoDB, он часто имеет лучшую параллельную производительность. То же самое с PostgreSQL.

0 голосов
/ 04 мая 2010

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

То, что у тебя будет, будет работать. Если вы сталкиваетесь с узким местом, вам необходимо выяснить, есть ли у него процессор, оперативная память, диск и / или сеть, и соответственно отрегулировать его. Трудно и неправильно преждевременно оптимизировать.

Возможно, вы захотите переключиться на innodb, если у вас есть какие-либо обновления, в противном случае myisam хорош для вставки / выбора. Кроме того, так как ваш размер строки невелик, вы можете заглянуть в кластер mysql (nbd). Существует также механизм архивирования, который может помочь с требованиями к хранилищу, но лучше разбить разделы на 5.1.

Изменение порядка индекса не имеет смысла, если эти индексы уже используются во всех ваших запросах.

но эффективнее иметь самый левый столбец индекса, который будет иметь наименьшую дисперсию - правильно?

не уверен, но я не слышал этого раньше. Не кажется мне верным для этого приложения. Порядок индекса важен для сортировки и, имея несколько уникальных 1-ых самых больших полей индекса, позволяет большему количеству возможных запросов использовать индекс.

0 голосов
/ 07 апреля 2010

Прежде всего, если вы используете ip как строку, измените ее на столбец INT UNSIGNED и используйте для этого функции INET_ATON (expr) и INET_NTOA (expr). Индексирование по целочисленному значению более эффективно, чем индексирование по строкам переменной длины.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...