Индексирование и альтернативы для колонок с низкой селективностью - PullRequest
8 голосов
/ 15 ноября 2010

Какой диапазон тактик доступен для выбора записей в столбцах с низкой избирательностью?

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

Похожие вопросы по индексированию
MySQL: столбцы с низкой кардинальностью / селективностью = как индексировать?
Сосут ли индексы в SQL?
Что такое индексы и как их использовать для оптимизации запросов в моей базе данных?
Определение индексов: какие столбцы и влияние на производительность?
и многие другие, все менее родственные.

Подходы, о которых я читал (в stackoverflow и в других местах), включают

  • Использовать индекс растрового изображения
  • Использовать частичный индекс (create index x on t(c2) where c1='a')
  • Использовать кластерный индекс?
  • Не индексировать столбцы с низкой селективностью, используйте последовательное чтение
  • Разделение данных (например, на несколько таблиц с одинаковой схемой)
  • Используйте дополнительную таблицу (например, active_customers(customer_id)

Моя текущая СУБД не поддерживает первые три варианта, перечисленных выше, а остальные кажутся проблематичными - есть ли другие часто используемые подходы?

Обновление: я видел - индексировать столбец с низкой селективностью, но выбирать только значения высокой селективности.

Ответы [ 3 ]

3 голосов
/ 18 ноября 2010

Я согласен с веткой Unreason Однако .Но есть кое-что, что нужно знать об этом случае.

Это называется перекосом и перекосом.Это идеальное использование для частичного индекса, когда вы исключаете 95% оплаченных счетов и индексируете только более интересные и выборочные статистические данные.Но у тебя этого нет.Вы можете разделить все строки по горизонтали на отдельные таблицы / разделы, но тогда вам необходимо учитывать перенос строк (переход из одного состояния в другое), и это дорого.СУБД должна выполнить обновление, удаление и вставку, чтобы изменить статус.Если у вас система с большим объемом, это будет больно.

Забудьте, что вы сказали о том, индексировать или нет на основе селективности, потому что размещение индекса в быстро меняющемся столбце также обычно является плохой идеей.В вашем индексе будут горячие блоки, в которых удаляются все шаги 1, а в другом - вставляются все шаги 2, и, кстати, некоторые шаги 2 удаляются одновременно в шаги 3.Это не будет хорошо масштабироваться.

Я бы порекомендовал разделить ваш статус по вертикали на отдельные таблицы.

Ваша таблица счетов-фактур будет иметь PK и все столбцы, кроме статуса.

С вашим статусом вы можете справиться двумя способами.Эта таблица будет иметь значение PK в виде FK для таблицы счетов, статус и временную метку, когда вы ввели этот статус.Лучшей является горизонтально разделенная таблица по статусу.У вас будет раздел для каждого возможного статуса.Таким образом, обнаружение всего или одного состояния «Помещено» приведет к удалению раздела и чтению только того раздела, который ему необходим, а это очень небольшое количество блоков.Поскольку строка очень узкая, вы можете получить 400 статусов счетов за один блок.Просмотреть этот статус любого счета легко, поскольку на ПК имеется глобальный индекс.

Если ваша СУБД не поддерживает разбиение с переносом строк, вам нужно управлять этими разделами как таблицами и удалять изодин и вставить в другой.Вы будете инкапсулировать эти движения в транзакции в процедуре, чтобы поддерживать чистоту данных.Каждый счет находится в одной и только одной таблице состояния.Более сложная часть запроса по идентификатору счета-фактуры, вам придется проверять каждую таблицу, чтобы увидеть, где она находится.

У вас есть другой выбор Вы можете написать платные статусы или нет.Если это многораздельная таблица, вы можете просто удалить накладную из таблицы состояния накладной, когда она переходит на платную.(Конечно, вы запишете платную запись в таблицу истории, упомянутую в бонусном материале).Затем вы выполните внешнее объединение с таблицей состояния, а значение null означает оплаченныйЕсли вы почти никогда не запрашиваете платный статус, на самом деле нет причин делать этот быстрый запрос.

Бонусный материал

в любом случае вы захотите отслеживать эти движения в отчетеТаблица.Каждый раз, когда вы обновляете статус, вы хотите записать его в таблицу истории.В конце концов, вы захотите проанализировать то, что я называю временем транзита.Какое среднее время от заполненного до платного по месяцам?Это увеличивается в результате плохой экономики?какое время транзита от размещенного до заполненного, по месяцам.Летние месяцы занимают больше времени из-за отсутствия тел в отпуске?Вы поняли.Обновляя этот столбец, вы теряете эти ответы, поэтому вам нужно встроить этот журнал в свои процедуры.

3 голосов
/ 15 ноября 2010

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

Если у вас низкая селективность настолбец это означает, что сканирование будет работать лучше, чем поиск.

Индекс может использоваться для

  • поиска индекса - проверить указатель индекса, получить запись, повторить
  • сканирование индекса - сканирование индекса и получение значений непосредственно из индекса

, в противном случае это не очень полезно.

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

Так что, если селективность низкая, вы ничего не можете сделать (кластеризация может помочь).

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

Итак, вы, возможно, бьетесь головой без проблем.

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

1 голос
/ 15 ноября 2010

Секционирование - это подход, при котором таблица с одинаковыми хранится в отдельных областях на основе данных - разработчикам SQL не требуется доступ к отдельным таблицам.

Я думаю, что это идеально подходит для описанной проблемы - вы можете найти больше об этом на Informix здесь: http://www.dbmag.intelligententerprise.com/blog/main/archives/2008/09/data_partitioni.html

...