Слишком много столбцов для индексации - используйте разделы MySQL? - PullRequest
5 голосов
/ 13 декабря 2010

У нас есть приложение с таблицей с 20+ столбцами, которые доступны для поиска.Построение индексов для всех этих столбцов сделает запросы записи очень медленными;и любой действительно полезный индекс часто приходится размещать в нескольких столбцах, увеличивая количество необходимых индексов.

Однако для 95% этих поисков нужно искать только небольшое подмножество этих строк, и довольнонебольшое число - скажем, 50 000 строк.

Итак, мы рассмотрели использование таблиц разделов mySQL - имеющих столбец, который в основном равен isActive, на который мы делим два раздела.Большинство поисковых запросов будут выполняться с isActive=1.После этого большинство запросов будет выполняться для небольшого раздела строк в 50 000 и выполняться быстро без других индексов.

Единственная проблема - строки, в которых isActive=1 не является фиксированным;то есть он не основан на дате строки или чем-либо подобном;нам нужно будет обновить isActive в зависимости от использования данных в этой строке.Как я понимаю, это не проблема, хотя;данные просто будут перемещены из одного раздела в другой во время запроса UPDATE.

У нас есть PK на id для строки;и я не уверен, если это проблема;Руководство, похоже, предполагало, что раздел должен основываться на любых первичных ключах.Это было бы огромной проблемой для нас, потому что идентификатор первичного ключа не зависит от того, является ли строка isActive.

Ответы [ 4 ]

7 голосов
/ 06 января 2011

Я не эксперт по MySQL.Мой фокус - Oracle, но я уже много лет работаю с Partitioning, и я обнаружил, что предложенное вами использование очень уместно, но не соответствует общему пониманию разделов.

Индекс по столбцам с низким количеством элементов

Отложим слияние индекса на данный момент.Допустим, ваши активные строки несколько разбросаны и имеют соотношение 1:20 к числу неактивных строк.Скажем, размер вашей страницы составляет 8 КБ, и вы получите около 20 строк на блок.Если вы получаете очень равномерное распределение неактивных записей, у вас будет почти 1 на блок.Полное сканирование таблицы будет намного, намного, намного быстрее читать КАЖДЫЙ блок / страницу в таблице, чем использование индекса для поиска тех же строк.

Итак, предположим, что они сосредоточены, а не разбросаны равномерно.Даже если они сосредоточены в 20% страниц или даже в 10% страниц, полное сканирование таблицы может не выполнить индексирование даже в этих случаях.

Теперь добавьте индексное слияние.Если после сканирования индекса ISactive вы НЕ посещаете таблицу, а объединяете эти результаты с результатами ДРУГОГО индекса, и этот конечный набор результатов даст, скажем, менее 5% ваших блоков.Тогда да, и индекс по isactive и слияние индекса может быть решением.

Предостережение заключается в том, что существует много ограничений на реализацию соединений индекса в MySQL.Убедитесь, что это работает в вашей ситуации.Но вы сказали, что у вас есть еще 20 полей, которые можно искать.Поэтому, если вы не индексируете их все, так что есть второй доступный индекс для присоединения к индексу IsActive, вы не будете использовать слияние / объединение индексов.

Разделение столбца с низким количеством элементов

Теперь, если вы разделите этот столбец, у вас будет 5% блоков с IsActive = True, и они будут плотно упакованы.Полное сканирование разделов быстро выдаст список активных записей и позволит использовать любой другой предикат в качестве фильтра вместо поиска по индексу.

Но этот флаг меняется, верно.

ВOracle у нас есть команда, которая позволяет нам включить Row Migration.Это означает, что когда Is_Active изменится с True на False, переместите раздел, в который попадает строка. Это довольно дорого, но только немного больше, чем обслуживание индекса, которое могло бы произойти, если бы вы индексировали этот столбец вместо того, чтобы разделить его.В разбитом примере.Oracle сначала изменяет строку с обновлением, затем выполняет удаление, а затем вставку.Если вы проиндексировали этот столбец, вы бы обновили строку, а затем была бы удалена запись индекса для TRUE, а затем была бы создана запись индекса для False.

Если MySQL не имеет миграции строктогда вам придется запрограммировать свой пакет crud для этого.UPDATE_ROW_ISACTIVE (номер pk IN) <---- что-то вроде этого) сделает удаление и вставку для вас. </p>

Относительно ответа Конерака

Хотя я согласен с тем, чтопараллельный доступ - это ОДНО использование разметки, но не исключительное.Но если вы перейдете по ссылке, которую он предоставляет, пользовательский комментарий в самом низу страницы будет выглядеть так:

Остерегайтесь низких индексов селективности в вашей таблице.Сложное предложение AND / OR WHERE, безусловно, сделает ваш запрос очень очень медленным, если оптимизация Index_Merge используется с алгоритмом intersect ().

Это, кажется, говорит о вашей ситуации, так что вы можете принять этокомментарий FWIW.

1 голос
/ 08 января 2011

Если вы собираетесь индексировать такое количество «столбцов», вы можете переосмыслить структуру данных. Например, сделайте каждый столбец строкой / записью. Затем укажите «идентификатор группы», чтобы связать отдельные записи, и поле «имя», чтобы указать, какой это элемент данных. Тогда вам нужен только 1 индекс для всех ваших данных.

Эта настройка пары имя / значение на самом деле довольно распространена в настоящее время и является основой для некоторых баз данных noSQL. Что-то еще, что вы можете захотеть посмотреть. Что-то вроде MongoDB отлично подходит для индексации «всех» фрагментов данных.

0 голосов
/ 08 января 2011

Ваше описание «таблицы» и «базы данных» является классическим признаком отсутствия нормализации.«Таблица» с 20 доступными для поиска столбцами не 3NF и, вероятно, даже не 1NF.Лучший совет - вернуться к первым принципам и нормализовать данные, что приведет к гораздо более узким таблицам, а также к меньшему количеству строк в таблице, но, конечно же, к нескольким таблицам.Однако результат также имеет меньше индексов, по таблице и в целом.

И гораздо более быстрая база данных.«Жирные» таблицы - это катастрофа для производительности на каждом уровне.

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

id PK - это дополнительный столбец и индекс , суррогат, замена (но не замена) реального первичного ключа.Если вы использовали методы реляционного моделирования, это может быть устранено, по крайней мере, до 19 доступных для поиска индексов.Любая серьезная работа за «столом» будет сосредоточена вокруг реального ПК, а не суррогата, например, как вы видели из ограничений на разделы.

Если вы хотите это обсудить, пожалуйста, опубликуйте свой DDLдля «таблицы» плюс все подключенные «таблицы».

Ответ на комментарии

Таблица лучше всего воспринимается как «электронная почта»но с большим количеством дополнительных полей (категория / отдел / приоритет / рабочий процесс / владелец), которые все должным образом нормализованы.Существует также ряд других переменных, в том числе довольно много временных отметок.

Это само определение плоского файла, в 0NF .Если вы не используете какое-то неписаное определение «нормализации», оно, по вашему собственному описанию, вообще не нормализовано .Это статья, с которой начинается до начала любой нормализации.

  • Нет сомнений, что индексы также будут широкими, чтобы быть полезными для запросов.

  • и вы, возможно, не понялитем не менее, в этом файле имеется большое дублирование данных и аномалии обновления (когда вы обновляете столбец в одной строке, вы должны обновить дублированное значение в других строках), что делает ваше приложение излишне сложным.

Необходимо понимать, что все поставщики реляционных СУБД пишут реляционные механизмы баз данных, оптимизированные для обработки реляционных баз данных.Это означает, что они оптимизированы для Нормализованных, а не Ненормализованных или Денормализованных структур.

Я не буду втягиваться в академические аргументы, и SO - это сайт вопросов и ответов, а не дискуссионный сайт.По запросу опубликуйте свой DDL для файла и всех подключенных файлов, и мы определенно можем (а) дать ему некоторую скорость и (б) избежать более 20 индексов (что является еще одним распространенным симптомом состояния).Это решит конкретную проблему реального мира, решит ее и позволит избежать дебатов.

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

Также из наших тестов, имея множество таблиц, к которым можно присоединиться.мы должны включить в предложение WHERE только замедление запроса.

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

Вас также может заинтересовать этот вопрос / ответ , который привел к тому же спору, к которому вы приближаетесь.

Объединения ничего не стоят. файлы , к которым вы присоединяетесь;и количество записей , соединенных с обеих сторон; полезность индексов, в этом и заключается стоимость.Если это другой ненормализованный файл (толстый, широкий, много необязательных столбцов), обязательно он будет медленным.

В любом случае, если вы действительно заинтересованы в устранении указанной проблемы, опубликуйте все свои DDL, и мы сможем сделать это быстрее для вас.Если все, что вам нужно, это ответ да / нет на разделы (и чтобы не решить причинную проблему), это тоже хорошо;у вас уже есть это.

0 голосов
/ 13 декабря 2010

Для этого вам не нужны разделы - достаточно индекса для вашего столбца isActive.Обратите внимание, что MySQL может использовать операцию Index Merge для использования обоих индексов.

Разделы могут быть полезны, когда они позволяют выполнять поиск параллельно: например, если вы разбиваете на части по дате, вы можетеПоиск 5 разделов одновременно, чтобы найти результаты, охватывающие 5 лет.

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