0

У нас есть таблица базы данных, в которой хранятся данные браузера для посетителей, разбитые на несколько разных подтипов. Для простоты воспользуемся приведенной ниже схемой таблиц. Запрос будет в основном состоять из любого столбца id, столбца метрики, столбца временной метки (хранится как секунды с эпохи) и одного из столбцов устройства, браузера или os.Стратегия индексации MySql с несколькими общими столбцами

Мы собираемся проверить производительность схемы звезды против снежинок (где все Иды входят в один столбец, но затем добавляется дополнительный столбец id_type, чтобы определить, какой тип идентификатора он есть) для этой таблицы, но как поскольку звездная схема (как это сейчас) находится в пределах 80% от производительности снежинки, мы будем ее поддерживать, так как это облегчит процесс загрузки. Прежде чем я это сделаю, я хочу убедиться, что индексы оптимизированы по схеме звезд.

create table browser_data (
id_1 int, 
id_2 int, 
id_3 int, 
id_4 int, 
metric varchar(20), 
browser varchar(20), 
device varchar(20), 
os varchar(20), 
timestamp bigint 
) 

Было бы лучше создать отдельные индексы только столбцы идентификаторов, или же включать metric и timestamp столбцов в этих индексах, а?

+0

Неужели это очень сложно иметь отдельный столбец для каждого подтипа? Способность поддерживать правильные отношения с внешним ключом представляется желательной для схемы таблицы фактов. Я понимаю, что стандартный столбец размером 4 байта может в конечном итоге потерять пространство. –

+0

@ GordonLinoff это не конец света, но это еще больше усложнит процесс ETL, чтобы получить данные. Вот почему, пока производительность похожа, стоит компромисс с тем, чтобы поддерживать процесс одинаковым. – aarbor

ответ

1

ли не Нормализовать "непрерывного" значение, такие как DATETIME, FLOAT, INT. Do оставить значения в основной таблице.

При переносе значения в другие таблицы, особенно «снежинка», он делает запрос на основе значений где-то между немного медленнее и много медленнее. Это особенно важно, когда вам нужно отфильтровать более одного показателя, который не находится в главной таблице. Любой из них выполняют очень плохо из-за «снежинкой» или «по-нормализации»:

WHERE a.x = 123 AND b.y = 345 

ORDER BY a.x, b.y 

Как для того, что индексы создавать - это целиком зависит от запросов, которые необходимо выполнить. Итак, я настоятельно рекомендую вам набросать вероятный SELECTs на основе вашего предварительного CREATE TABLEs.

INT - 4 байт. TIMESTAMP - 5, FLOAT - 4 и т. Д. То есть нормализация таких вещей также неэффективна в пространстве.

Больше

При выполнении JOINs, оптимизатор почти всегда будет начинаться с одной таблицей, а затем перейти к другой таблице, и т.д. (см «вложенный цикл».)

Например (на основе вышеуказанного «кода»), когда 2 столбца нормированы, и вы тестируете значения, у вас нет двух ids в руке, у вас есть только два значения. Это делает выполнение запроса очень неэффективным. Для

SELECT ... 
    FROM main 
    JOIN a USING(a_id) 
    JOIN b USING(b_id) 
    WHERE a.x = 123 AND b.y = 345 

Ниже очень вероятно, будет «план выполнения»:

  1. достичь в a, чтобы найти строку (ы) с х = 123; получите id(s) для этих строк. Это может включать в себя множество строк, которые еще не фильтруются b.y. aINDEX(x)
  2. Возврат к таблице main, поиск строк с этими идентификаторами. mainINDEX(a_id).Опять же, может быть перемещено больше строк, чем необходимо.
  3. Только сейчас, вы добираетесь до b (с использованием b_id) для проверки на y=345; бросить ненужные строки, которые вы вытаскивали. b нуждается в INDEX(b_id)

Запомните мой комментарий о "haul around". Слепо с помощью *SELECT *) добавляется проблема - все столбцы перемещаются во время выполнения шагов.

С другой стороны ... Если x и y были в main таблице, то код работает как:

WHERE main.x = 123 
    AND main.y = 345 

нуждается только INDEX(x,y) (в любом порядке). И он быстро находит нужные строки.

В случае ORDER BY a.x, b.y, он не может использовать любой индекс на любой таблицы. Поэтому запрос должен создать таблицу tmp, отсортировать ее, а затем доставить строки в нужном порядке.

Но если x и y находятся в одной таблице, то INDEX(x,y) (в таком порядке) может быть полезным для ORDER BY x,y и избежать таблицы TMP и сортировки.

С помощью одной таблицы Оптимизатор может использовать индекс для WHERE, или он может использовать индекс для ORDER BY, в зависимости от фазы луны. В некоторых случаях один индекс может использоваться для обоих - это оптимально.

Другое примечание: Если у вас также есть LIMIT 10, ... Если избежать sort, необходимо просмотреть только 10 строк, а не весь набор из WHERE.

+0

Каждый запрос будет использовать _at наименьший_ один из столбцов идентификатора, определенно столбца метрики и, безусловно, столбец временной метки. Я предполагаю, что мой реальный вопрос состоял в том, была ли плохая практика, если бы у меня был другой составной индекс для каждого из столбцов идентификатора, с той лишь разницей, что это столбец ведущего индекса. Было бы лучше иметь один индекс столбца для каждого из столбцов id, а затем один составной индекс для остальных столбцов? – aarbor

+0

Вы отжимаете мою диссертацию; см. мой добавленный текст. –

+0

Еще одно замечание: MySQL редко использует более одного индекса для 'SELECT'. (Это просто неэффективно.) –