0

У меня есть MySQL V5.6.23, работающий на Amazon RDS. В ней находится таблица InnoDB с именем product_details, которая содержит около 10 столбцов, которые все индексируются для точных совпадений (даты, числа, текст и т. Д.). Затем у меня есть одно поле product_name, на которое я положил индекс FULLTEXT. У меня также есть много других полей, которые мы не ищем.Как правильно согреть индекс MySQL FULLTEXT?

В таблице в настоящее время есть 150M строк, и мы добавляем около 3-5M каждую ночь, а также обновляем еще 10-20M каждую ночь. После запуска этих вставок/обновлений в ночное время индекс FULLTEXT, кажется, выпал из памяти (не уверен, что это именно то, что происходит).

Когда я впервые запустил запрос для слова «синий форд-телец», запрос может занять до нескольких минут. Во второй раз, когда я запускаю его, это несколько секунд, если не несколько сотен миллисекунд. Если я запустил OPTIMIZE TABLE product_details; после завершения обработки новых данных, то почти каждый поиск, который я тестирую, выполняется так быстро, как может быть. Это занимает несколько часов, чтобы запустить OPTIMIZE TABLE (как я думаю, он переписывает всю таблицу (и индексы?)?!?!

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

ВОПРОСЫ

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

  2. Как узнать, какие требования к памяти мне нужны для хранения моих индексов?

Комментарии

  1. Я планирую переместить все это в Elasticsearch (или аналогичный), где у меня много опыта делает поиск. Я не знаком с MySQL как поисковая система FULLTEXT, но на данный момент я застрял в этом.

Common Query

SELECT * FROM product_details as pd 
WHERE 
    MATCH (pd.product_name) AGAINST ('+ipod +nano' IN BOOLEAN MODE) 
    and pd.city_id IN (577,528,567,614,615,616,618) 
ORDER BY(pd.timestamp) DESC 
LIMIT 1000; 

Таблица

CREATE TABLE `product_details` (
    `product_name` text NOT NULL, 
    `category_name` varchar(100) NOT NULL, 
    `product_description` text NOT NULL, 
    `price` int(11) NOT NULL, 
    `address` varchar(200) NOT NULL, 
    `zip_code` varchar(30) NOT NULL DEFAULT '', 
    `phone` bigint(10) DEFAULT NULL, 
    `email` varchar(50) NOT NULL, 
    `state` varchar(20) NOT NULL, 
    `city` varchar(30) NOT NULL, 
    `post_id` bigint(11) NOT NULL, 
    `post_date` date DEFAULT NULL, 
    `post_time` time NOT NULL, 
    `updated_date` varchar(10) NOT NULL, 
    `updated_time` time NOT NULL, 
    `status` tinyint(4) NOT NULL, 
    `timestamp` date NOT NULL, 
    `new_field` tinyint(4) DEFAULT NULL, 
    `multiple_items` tinyint(1) NOT NULL, 
    `city_id` int(4) NOT NULL, 
    `date_changed` date DEFAULT NULL, 
    `latlong` varchar(100) NOT NULL, 
    PRIMARY KEY (`post_id`), 
    KEY `city_id` (`city_id`), 
    KEY `post_date` (`post_date`), 
    KEY `price` (`price`), 
    KEY `category_name` (`category_name`), 
    KEY `state` (`state`), 
    KEY `multiple_items` (`multiple_items`), 
    KEY `new_field` (`new_field`), 
    KEY `phone` (`phone`), 
    KEY `timestamp` (`timestamp`), 
    KEY `date_changed` (`date_changed`), 
    FULLTEXT KEY `product_name` (`product_name`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Таблица Статус enter image description here

Данные о состоянии таблицы, приведенные выше, действительно для моей таблицы dev, в которой есть только 18M строк. Когда я загружу все производственные данные, он будет иметь ~ 8x количество данных, то есть data_length будет ~ 70 ГБ, а index_length будет ~ 32 ГБ.

ответ

2

Оптимизируйте (или нет). Да OPTIMIZE TABLE копирует за стол и восстанавливает все индексы, поэтому требуется много времени. Не запускать OPTIMIZE; это почти никогда не помогает. (Или вы видите значительное изменение?)

Тюнинг. Сколько у вас RAM? Насколько велики индексы? SHOW TABLE STATUS.

innodb_buffer_pool_size должно быть около 70% от доступно Оперативная память.

Сжатие схемы поможет немного:

  • Это редко бывает хорошо разделить DATE и TIME на два поля
  • Почему оба city и city_id в этой таблице. Возможно, вы должны нормализовать city и state и, возможно, zip_code в другую таблицу (одну, а не две другие таблицы).
  • Ид должен быть соответствующим образом определен - city_id может быть SMALLINT UNSIGNED (2 байта: 0..65535) вместо INT SIGNED (4 байта).
  • Нормализовать category_name и каких-либо других повторяющихся граней?
  • updated_date является VARCHAR ??

Шаги в запросе

  1. Найдите все идентификаторы для продуктов как с IPad и нано. Допустим, таких строк было 5555.
  2. Идите все 5555 строк, соберите нужную информацию, которая является всеми столбцами из-за *. Похоже, что таблица намного больше, чем оперативная память, поэтому это означает что-то вроде чтения 5555 дисков - вероятно, это самая медленная часть.
  3. Отфильтровать нежелательные строки на основе city_id. Допустим, мы дострок.
  4. Запишите все столбцы всехстрок в таблицу tmp. Поскольку есть столбец TEXT, это будет таблица MyISAM, а не более быстрая таблица MEMORY.
  5. Сортировать по timestamp
  6. избавляйте первое 1000.

Как я надеюсь, что вы можете увидеть, громоздкие строки означают громоздкие вещи в таблице TMP. Уменьшите * и/или уменьшите столбцы.

Вот трюк урезать размер TMP таблицы (шаги 4,5,6):

SELECT ... 
    FROM product_details as pd 
    JOIN 
     (SELECT post_id 
      FROM product_details 
      WHERE MATCH (product_name) AGAINST ('+ipod +nano' IN BOOLEAN MODE) 
       and city_id IN (577,528,567,614,615,616,618) 
      ORDER BY timestamp DESC 
      LIMIT 1000 
    ) x USING (post_id) 
    ORDER BY pd.timestamp; 

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

Обратите внимание, что при запуске теста, который может быть связан с I/O, выполните его дважды. Второй прогон будет более справедливым, потому что он, по-видимому, не будет иметь ввода-вывода.

Другой слой должен быть быстрее:

SELECT pd... 
    FROM 
     (SELECT post_id 
      FROM product_details 
      WHERE MATCH (product_name) AGAINST ('+ipod +nano' IN BOOLEAN MODE) 
    ) AS a 
    JOIN product_details AS b ON b.post_id = a.post_id 
    WHERE b.city_id IN (577,528,567,614,615,616,618) 
    ORDER BY b.timestamp DESC 
    LIMIT 1000) x 
    JOIN product_details as pd ON pd.post_id = b.post_id 
    ORDER BY pd.timestamp; 

INDEX(post_id, city_id, timestamp) -- also required for this formulation 

Надежда с такой постановке

  • Вторичная фильтрация (city_id) делается на гораздо меньшем BTree (т.е. индекс), следовательно, более вероятно, будет жить в ОЗУ, тем самым избегая ввода-вывода.
  • В большой стол необходимо всего 1000 зондов. Это должно быть большой победой.

шаги:

  1. Получить 5555 идентификаторами из индекса FULLTEXT.
  2. Отфильтруйте доидентификаторов, используя то, что будет надеюсь, что будет операцией в памяти.
  3. Сортировка«узких» строк (всего 3 столбца, не все). На этот раз это может быть таблица tmp MEMORY.
  4. JOIN возвращение в исходную таблицу только 1000 раз. (Большая победа.) (Я могу ошибаться здесь, это может быть, но это все же лучше, чем 5555.)
  5. Доставить результаты.
+0

Я добавил данные о состоянии таблицы на свой вопрос. Как это влияет на мои требования к оперативной памяти для быстрых запросов? У вас есть мысли о потеплении индекса FREETEXT в ночное время, прежде чем пользователи будут в системе? Много шума в этой системе является наследием, и я пытаюсь восстановить работу сломанного сайта в течение нескольких месяцев, пока мы перестраиваем всю систему. Отличные предложения. Благодаря!! –

+0

Если вы не перезагружаете систему и не выполняете большие запросы в одночасье, вам не нужно «заполнять кеш». Да, это может помочь выполнить некоторые репрезентативные запросы. Но это поможет только таким запросам. Мои предложения пытаются помочь всем запросам. –

+0

Если у вас 16 ГБ ОЗУ, у вас, вероятно, много операций ввода-вывода. (И ваши комментарии подразумевают, что у вас небольшая оперативная память.) Если у вас более 100 ГБ ОЗУ, то я озадачен замедлением. У вас есть другие огромные таблицы, которые «заняты»? –

Смежные вопросы