Совет должен был правильно проиндексировать таблицу с множеством полей для поиска - PullRequest
1 голос
/ 06 января 2011

У меня есть пользовательская таблица, которая имеет много столбцов, она выглядит примерно так:

dname:             { type: string(255), notnull: true }
email:             { type: string(255), notnull: true, unique: true }
email_code:        { type: string(255) }
email_confirmed:   { type: boolean, default: false }
profile_filled:    { type: boolean, default: false }
password:          { type: string(255), notnull: true }
image_id:          { type: integer }
gender:            { type: enum, values: [male, female] }
description:       { type: string }
dob:               { type: date }
height:            { type: integer(3) }
looks:             { type: enum, values: [thin, average, athletic, heavy] }
looking_for:       { type: enum, values: [marriage, dating, friends] }
looking_for_age1:  { type: integer }
looking_for_age2:  { type: integer }
color_hair:        { type: enum, values: [black, brown, blond, red] }
color_eyes:        { type: enum, values: [black, brown, blue, green, grey] }
marital_status:    { type: enum, values: [single, married, divorced, widowed] }
smokes:            { type: enum, values: [no, yes, sometimes] }
drinks:            { type: enum, values: [no, yes, sometimes] }
has_children:      { type: enum, values: [no, yes] }
wants_children:    { type: enum, values: [no, yes] }
education:         { type: enum, values: [school, college, university, masters, phd] }
occupation:        { type: enum, values: [no, yes] }
country_id:        { type: integer }
city_id:           { type: integer }
lastlogin_at:      { type: timestamp }
deleted_at:        { type: timestamp }

Я создал форму, которая содержит большинство полей (перечисления, страна, город), которая позволяет пользователю создавать оператор where на основе выбранных полей. Так что, если кто-то выбрал, курит: no и country_id: 7, тогда sql, где выражение может выглядеть так:

SELECT id 
FROM user u 
WHERE u.deleted_t IS NULL AND u.profile_filled IS NOT NULL AND smokes = 'no' AND country_id = 7;

Поскольку пользователь мог выбрать любую комбинацию полей для фильтрации, я не уверен, как мне поступить при индексировании этой таблицы, должен ли я просто создать индекс по одному столбцу для всех полей, которые можно фильтровать? Что бы вы посоветовали?

Ответы [ 2 ]

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

У меня есть таблица с такими же вещами, множество столбцов и 1000 разных способов выбора. Это кошмар. Однако я обнаружил, что существуют определенные комбинации фильтров, которые часто используются. Это те, для которых я бы создал индексы, а другие оставил, которые редко используются для медленной работы. В MSSQL я могу выполнить запрос, чтобы показать мне самые дорогие запросы, которые были выполнены с базой данных, у MySQL должна быть похожая вещь. Получив их, я создаю индекс, который охватывает столбцы, чтобы ускорить их. В конце концов, вы получите 90% покрытия. Лично я никогда не разработал бы такой стол снова, если бы на меня не направили AK47. (мои индексы в 3 раза больше, чем данные в таблице, что очень плохо, если вам нужно добавить группу или записи). Хотя я не уверен, как бы я изменил дизайн таблицы, моей первой мыслью было бы разделить таблицу на две части, но это привело бы к головным болям в других местах.

Таблица пользователей (идентификатор пользователя, имя)

1, Lisa
2, Jane
3, John

Таблица атрибутов пользователя (UserID, AttributeName, AttributeValue)

1, EYES, Brown
1, GENDER, Female
2, EYES, Blue
2, GENDER, Female
3  EYES, Blue
3, GENDER, Male

Это ускорит идентификацию атрибутов, но сделает ваши запросы не такими простыми для написания.

SELECT UserID, COUNT(*) as MatchingAttributes
FROM   UserAttributes 
WHERE  (UserAttributes.AttributeName = 'EYES' AND UserAttributes.AttributeValue = 'Blue') OR
       (UserAttributes.AttributeName = 'GENDER' AND UserAttributes.AttributeValue = 'Female') 

Это должно вернуть следующее

UserID, MatchingAttributes
1, 1
2, 2
3, 1

Все, что вам нужно сделать, это добавить HAVING COUNT (*) = 2 к запросу, чтобы выбрать только идентификаторы, которые соответствуют. Его немного сложнее выбирать, но он также предоставляет удобную функцию: скажем, вы фильтруете по 10 атрибутам и возвращаете все те, которые имеют 10 соответствий. Круто, но сказать, что ни один не соответствует 100%. Вы могли бы сказать, эй, я не нашел ни одного подходящего, но у них было 9 из 10 или 90% соответствия. (просто убедитесь, что, если я ищу голубоглазую блондинку, я не получаю сообщение о том, что нигде не найдено, но вот следующие самые близкие совпадающие, содержащие голубоглазых парней блондинки с соответствием 60%. быть очень не крутой)

Существуют и другие вещи, которые необходимо учитывать, если вы решили разделить таблицу, например, как хранить атрибуты в виде чисел, дат и текста в одном столбце? Или это отдельные таблицы или столбцы. Нелегко ответить ни в одну из таблиц, либо в обе стороны.

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

Каждому доступному для поиска полю требуется свой отдельный индекс одного столбца.Если ваша таблица большая и у вас нет индекса для условия поиска, тогда нужно будет сканировать каждую строку.

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

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