Возможно ли более быстрый способ выполнить этот запрос SELECT? - PullRequest
4 голосов
/ 12 февраля 2011

ОБНОВЛЕНИЕ (на основе ответов каждого):

Я думаю об изменении своей структуры, чтобы у меня была новая таблица с именем prx_tags_sportsitems. Я буду полностью удалять prx_lists. prx_tags_sportsitems будет действовать как ссылка на таблицу идентификаторов, заменяя prx_lists.ListString, которая использовалась для хранения идентификаторов тегов, принадлежащих каждому prx_sportsitem.

Новое отношение будет выглядеть так:

  • prx_tags_sportsitems.TagID <-> prx_tags.ID
  • prx_sportsitems.ID <-> prx_tags_sportsitems.OwnerID

prx_tags будет содержать TagName. Это так, что я все еще могу поддерживать каждый «тег» как отдельный уникальный объект.

Мой новый запрос для поиска всех спортивных элементов с тегом «аэробика» будет выглядеть примерно так:

SELECT prx_sportsitems.* FROM prx_sportsitems, prx_tags_sportsitems
WHERE prx_tags_sportsitems.OwnerID = prx_sportsitems.ID 
AND prx_tags_sportsitems.TagID = (SELECT ID FROM prx_tags WHERE TagName = 'aerobic')
ORDER BY prx_sportsitems.DateAdded DESC LIMIT 0,30;

Или, возможно, я могу что-то сделать с предложением «IN», но я пока не уверен в этом.

Прежде чем я продолжу эту огромную модификацию моих сценариев, все одобряют? Комментарии? Большое спасибо!

ОРИГИНАЛЬНЫЙ ПОЧТА:

Что касается запросов MYSQL, я довольно новичок. Когда я изначально проектировал свою базу данных, я делал что-то довольно глупое, потому что это было единственное решение, которое я мог найти. Теперь я обнаружил, что это, кажется, вызывает слишком большую нагрузку на мой сервер MYSQL, поскольку для выполнения каждого из этих запросов требуется 0,2 секунды, и я считаю, что это может быть больше, чем 0,02 секунды, если это был лучший запрос (или дизайн таблицы, если он доходит до этого!). Я хочу избежать необходимости перестраивать всю структуру моего сайта, так как он глубоко спроектирован таким, какой он есть в настоящее время, поэтому я надеюсь, что возможен более быстрый запрос mysql.

В моей базе данных три таблицы:

  1. Таблица спортивных товаров
  2. Таблица тегов
  3. Таблица списков

Каждому спортивному предмету присвоено несколько имен тегов (категорий). Каждый «тег» сохраняется как отдельный результат в prx_tags. Я создаю «список» в prx_lists для спортивного элемента в prx_sportsitems и связываю их через prx_lists.OwnerID, который ссылается на prx_sportsitems.ID

Это мой текущий запрос (который находит все спортивные товары, имеющие тег 'aerobic'):

SELECT  prx_sportsitems.* 
FROM    prx_sportsitems, prx_lists 
WHERE   prx_lists.ListString LIKE (CONCAT('%',(SELECT prx_tags.ID 
                                               FROM prx_tags
                                               WHERE prx_tags.TagName = 'aerobic'
                                               limit 0,1),'#%')) 
 AND    prx_lists.ListType = 'Tags-SportsItems' 
 AND    prx_lists.OwnerID = prx_sportsitems.ID
 ORDER BY prx_sportsitems.DateAdded
 DESC LIMIT 0,30

Чтобы пояснить больше, список, содержащий все идентификаторы тегов, находится внутри одного поля с именем ListString, и я структурирую его так: "# 1 # 2 # 3 # 4 # 5" ... и из этого, Приведенный выше запрос «concats» prx_tags.ID, тэг которого «aerobic».

Я думаю, что, вероятно, не существует более быстрого запроса, и что мне нужно просто принять, что мне нужно сделать что-то более простое, например, поместить все теги в список, прямо в prx_sportsitems в новом поле с именем " TagsList ", а затем я могу просто выполнить запрос, который выбирает Select * из prx_sportsitems, где TagsList LIKE"% aerobic% "- однако, я хочу избежать необходимости перепроектировать весь мой сайт. Я очень сожалею, что не смотрю на оптимизацию заранее: (

Ответы [ 4 ]

7 голосов
/ 12 февраля 2011

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

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

prx_lists должно иметь три столбца: OwnerID, ListType и TagName. Тогда у вас будет по одной строке для каждого тега, который имеет OwnerID. Ваш запрос выше будет выглядеть примерно так:

SELECT prx_sportsitems.*
FROM prx_sportsitems, prx_lists
where prx_lists.TagName = 'aerobic'
      AND prx_lists.OwnerID = prx_sportsitems.ID

Это НАМНОГО более эффективный запрос. Возможно, ListType также не входит в эту таблицу, но трудно сказать, не имея дополнительной информации о том, для чего используется этот столбец.

Не забудьте также создать соответствующие индексы ! Это улучшит производительность.

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

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

список, который содержит все идентификаторы тегов, находится внутри одного поля с именем ListString, и я структурирую его так: «# 1 # 2 # 3 # 4 # 5» ... и отсюда вышеупомянутый запрос "prx_tags.ID, тэг которого 'aerobic'.

Не только плохо хранятся денормализованные данные, но и символ разделителя встречается редко.

Временное улучшение

Самый быстрый способ улучшить ситуацию - это заменить символ разделителя, который вы используете («#»), на запятую:

UPDATE PRX_LISTS
   SET liststring = REPLACE(liststring, '#', ',')

Затем вы можете использовать Функция MySQL FIND_IN_SET :

  SELECT si.* 
    FROM PRX_SPORTSITEMS si
    JOIN PRX_LISTS l ON l.ownerid = si.id
    JOIN PRX_TAGS t ON FIND_IN_SET(t.id, l.liststring) > 0 
   WHERE t.tagname = 'aerobic'
     AND l.listtype = 'Tags-SportsItems' 
ORDER BY si.DateAdded DESC 
   LIMIT 0, 30

Долгосрочное решение

Как вы уже знаете, поиск специфики в денормализованных данных неэффективен и делает запросы слишком сложными. Вам необходимо изменить таблицу PRX_LISTS, чтобы одна строка содержала уникальную комбинацию SPORTSITEM.ownerid и PRX_TAGS.id и любые другие столбцы, которые могут вам понадобиться. Я бы тоже порекомендовал переименовать - списки чего именно? Название слишком общее:

CREATE TABLE SPORTSITEM_TAGS_XREF (
   sportsitem_ownerid INT,
   tag_id INT,
   PRIMARY KEY (sportsitem_ownerid INT, tag_id)
)
1 голос
/ 12 февраля 2011
  1. Не вносите никаких изменений, не глядя на план выполнения .(И опубликуйте это здесь, отредактировав свой исходный вопрос.)
  2. При создании предложения LIKE MySQL не может использовать индекс.
  3. Предложение LIKE является симптомом.Ваша структура таблиц, скорее всего, является проблемой.

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

Я действительно сожалею, чтоЗаглядывая в оптимизацию заранее

Это не то, что вызвало вашу проблему.Незнание основ проектирования базы данных вызвало вашу проблему.(Это наблюдение, а не критика. Вы можете исправить невежество. Вы не можете исправить глупость.)

Позже :

Опубликовать существующую структуру таблицы и предложенные вами изменения.Вы будете намного счастливее с нашей способностью предсказать, что будет делать ваш код, чем с нашей способностью предсказать, что будет делать ваше описание фрагмента кода.

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

Чтобы уточнить, список, который содержит все идентификаторы тегов находится внутри одно поле с именем ListString и я структурировать это так: "# 1 # 2 # 3 # 4 # 5" ... и из этого вышеприведенный запрос "concats" prx_tags.ID, который тэг "аэробный".

Вот твоя проблема. Не храните данные с разделителями в поле БД (ListString). Таким образом, моделирование данных сделает чрезвычайно трудным / невозможным написание сложных запросов к ним.

Предложение: Разбить содержимое ListString на связанную таблицу с одной строкой для каждого элемента.

...