Оптимизировать процесс поиска MySQL - PullRequest
0 голосов
/ 12 февраля 2009

Вот сценарий 1.

У меня есть таблица с именем "items", внутри таблицы есть 2 столбца, e. г. item_id и item_name. Я храню свои данные таким образом: item_id | item_name

Ss001   | Shirt1
Sb002   | Shirt2
Tb001   | TShirt1
Tm002   | TShirt2

... и т. Д., Я храню таким образом: первая буква - код для одежды, т.е. S для рубашки, T для футболки вторая буква - размер, т. е. для малого, м для среднего и б для большого Скажем, в моей таблице предметов я получил 10000 предметов. Я хочу сделать быстрый поиск, скажем, я хочу найти конкретную рубашку, могу ли я использовать:

Method1:

SELECT * from items WHERE item_id LIKE Sb99; 

или я должен сделать это так:

Method2:

SELECT * from items WHERE item_id LIKE S*; 

* Сохраните результат, затем выполните второй поиск по размеру, затем третий поиск по идентификатору. Как и концепция хеш-таблицы. Я хочу добиться того, чтобы вместо поиска по всем данным я хотел свести к минимуму поиск, сначала выполняя поиск по коду одежды, затем по коду размера, а затем по коду ID. Какой из них лучше с точки зрения скорости в MySQL. И какой из них лучше в долгосрочной перспективе. Я хочу уменьшить трафик и не беспокоить базу данных так часто.

Спасибо, ребята, за решение моего первого сценария. Но приходит другой сценарий:

Сценарий 2:

Я использую PHP и MySQL. Продолжите предыдущую историю. Если моя таблица пользователей имеет такую ​​структуру:

user_id | username | items_collected

U0001   | Alex     | Ss001;Tm002
U0002   | Daniel   | Tb001;Sb002
U0003   | Michael  | ...
U0004   | Thomas   | ...

Я храню items_collected в виде идентификатора, потому что однажды каждый пользователь может собрать до сотен предметов, если я храню в виде строки, т.е. Shirt1, брюк2, ..., это потребует очень большого количества пространства в базе данных у нас 1000 пользователей, а некоторые наименования предметов очень длинные).

Будет ли легче поддерживать, если я буду хранить в форме идентификатора?

А если скажем, я хочу отобразить изображение, а именем изображения является имя элемента + jpg. Как это сделать? Это что-то вроде этого:

$ result = Выбрать items_collected от пользователей, где userid = $ userid

Использование php explode:

$ itemsCollected = explode ($ result, ";");

После этого, сопоставляя каждый элемент в таблице предметов, нужно:

рубашка1, брюки2 и т. Д.

Ден с использованием функции цикла, зациклите каждое значение и добавьте ".jpg" для отображения изображения?

Ответы [ 5 ]

3 голосов
/ 12 февраля 2009

Первый метод будет быстрее - но IMO это не правильный способ сделать это. Я согласен с Теханом по этому поводу.

Я бы рекомендовал сохранить item_id как есть, но добавив два дополнительных поля, одно для кода и одно для размера, тогда вы можете сделать:

select * from items where item_code = 'S' and item_size = 'm' 

С индексами производительность будет значительно увеличена, и вы сможете легко подобрать диапазон размеров или кодов.

select * from items where item_code = 'S' and item_size IN ('m','s')

Миграция базы данных выполняется следующим образом:

alter table items add column item_code varchar(1) default '';
alter table items add column item_size varchar(1) default '';

update items set item_code = SUBSTRING(item_id, 1, 1);
update items set item_size = SUBSTRING(item_id, 2, 1);

Изменения в коде должны быть одинаково просты для добавления. Долгосрочная выгода будет стоить усилий.


Для сценария 2 - это не эффективный способ хранения и извлечения данных из базы данных. При таком использовании база данных действует только как механизм хранения, кодируя несколько данных в поля, вы исключаете возможность использования реляционной части базы данных.

В этих обстоятельствах вам следует иметь другую таблицу, назовите ее items_collected. Схема будет иметь вид

CREATE TABLE items_collected (
   id int(11) NOT NULL auto_increment KEY,
   userid int(11) NOT NULL,
   item_code varchar(10) NOT NULL,  
   FOREIGN KEY (`userid`) REFERENCES `user`(`id`),
   FOREIGN KEY (`itemcode`) REFERENCES `items`(`item_code`)
 );

Внешние ключи гарантируют, что существует Ссылочная целостность , важно иметь ссылочную целостность .

Тогда для приведенного вами примера у вас будет несколько записей.

 user_id | username | items_collected
 U0001   | Alex     | Ss001
 U0001   | Alex     | Tm002
 U0002   | Daniel   | Sb002
 U0002   | Daniel   | Tb001
 U0003   | Michael  | ...
 U0004   | Thomas   | ...
1 голос
/ 12 февраля 2009

Вам нужно иметь три столбца для model, size и id и индексировать их следующим образом:

CREATE INDEX ix_1 ON (model, size, id)
CREATE INDEX ix_2 ON (size, id)
CREATE INDEX ix_3 ON (id, model)

Тогда вы сможете эффективно выполнять поиск по любому подмножеству параметров:

  • model-size-id, model-size и model запросы будут использовать ix_1;
  • size-id и size запросы будут использовать ix_2;
  • model-id и id запросы будут использовать ix_3

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

На самом деле, существует определенный путь доступа, называемый INDEX SKIN SCAN, который можно использовать для поиска по не первым столбцам составного индекса, но MySQL не поддерживает его AFAIK.


Если вам нужно придерживаться текущего дизайна, вам нужно проиндексировать поле и использовать такие запросы, как:

WHERE item_id LIKE @model || '%'
WHERE item_id LIKE @model || @size || '%'
WHERE item_id = @model || @size || @id

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

Нет необходимости вводить несколько запросов.

1 голос
/ 12 февраля 2009

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

Шаг 2 - создать индекс для каждого столбца. Помните, что mysql использует только один индекс на таблицу для каждого запроса. Поэтому, если вам действительно нужны быстрые запросы и ваши запросы сильно различаются в зависимости от этих свойств, вы можете создать индекс (тип, размер, окончание), (тип, окончание, размер) и т. Д.

Например, запрос с

select * from items where type = s and size = s and ending = 001

Может извлечь выгоду из индекса (тип, размер, окончание), но:

select * from items where  size = s and ending = 001

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

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

1 голос
/ 12 февраля 2009

Первая оптимизация будет разделять идентификатор на три разных поля: один для типа, один для размера, один для текущего окончания идентификатора (независимо от значения окончания) Если вы действительно хотите сохранить текущую структуру, сразу переходите к результату (вариант 1).

0 голосов
/ 16 февраля 2009

Мне удобно, что вы создали свой item_id для поиска с помощью теста "Начинается с". Индексы решат это быстро для вас.

Я не знаю MySQL, но в MSSQL, имеющем индекс для столбца «Размер», который имеет выбор только S, M, L, скорее всего, ничего не получится, индекс не будет использоваться, потому что значения он содержит недостаточно выборочные данные, т. е. он быстрее просматривает все данные, а не «находит первую запись S в индексе, а теперь извлекает страницу данных для этой строки ...»

Исключением является случай, когда запрос покрывается индексом, то есть несколько частей предложения WHERE (и действительно, все они, а также столбцы SELECT) включены в индекс. В этом случае, однако, первое поле в индексе (в MSSQL) должно быть выборочным. Поэтому сначала поместите столбец с наиболее различимыми значениями в индексе.

Сказав, что если ваше приложение имеет список выбора для размера, цвета и т. Д., Вы должны иметь эти атрибуты данных в отдельных столбцах записи - и отдельные таблицы со списками всех доступных цветов и размеров, а затем вы можете проверить что Цвет / Размер, заданный для Продукта, фактически определен в таблицах Цвет / Размер. Сокращает проблему «Вывоз мусора»!

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

Таким образом, ваша таблица USERS будет содержать user_id & username

Ваша новая таблица items_collected будет содержать user_id & item_id (и, возможно, также Дата покупки или номер счета)

Затем вы можете сказать: «Что купил Алекс» (у вашего дизайна это есть), а также «Кто купил Ss001» (что, в вашем дизайне, потребовало бы пролистать все строки в вашей таблице USERS и разбить items_collected на найти, какие из них содержали Ss001 [1])

[1] Обратите внимание, что использование LIKE на самом деле небезопасно, поскольку у вас может быть item_id "Ss001XXX", который будет соответствовать WHERE items_collected LIKE '% Ss001%'

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