Простой выбор константы для первичного ключа в таблице с небольшой памятью очень медленно

#mysql #performance #memory-table

#mysql #Производительность #таблица памяти

Вопрос:

У меня есть таблица ПАМЯТИ с примерно 650 строками, длиной данных 5 МБ, длиной индекса 60 КБ (так что она довольно маленькая). Он имеет один первичный (хэш-ключ SMALLINT и около 90 других столбцов (целые числа, переменные, даты и времени, без больших двоичных объектов или текстов). (РЕДАКТИРОВАТЬ: в столбце BIGINT также есть хэш-ключ.)

Я выполняю этот запрос (из PHP) довольно часто (около 10 раз в секунду):

выберите * из userek, где id={CONST_ID} и kitiltva=0 и kitiltva_meddig<«{CONST_DATETIME}» и inaktiv=0

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

Моя проблема в том, что запрос регулярно становится ненормально медленным. Примерно 0.5s в среднем, 8s макс. В большинстве случаев это происходит очень быстро: 75% of выполняется быстрее 3ms , 85% быстрее, чем в среднем. Но 15% это медленнее, чем в среднем, 13% медленнее, чем 1s . Так что у него длинный хвост.

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

Комментарии:

1. В таблице нет других индексов, кроме PK ?

2. О, в столбце BIGINT есть еще один хэш-индекс. Вот и все.

3. Индекс BTREE on (id,kitiltva,inaktiv,kitiltva_meddig) был бы наиболее подходящим для этого запроса. Но я не работал с таблицами ПАМЯТИ, поэтому кто-то с большим опытом может посоветовать, будет ли это (добавление индекса) уместно в данном случае.

4. Или, если есть другие более вероятные проблемы с таблицами памяти.

5. ОБЪЯСНЕНИЕ показывает, что запрос использует первичный индекс с const , что, насколько я знаю, является самым быстрым возможным решением. Но вы дали мне идею: я попытаюсь извлечь другие условия из запроса (и в PHP), и мы увидим…

Ответ №1:

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

Поскольку это таблица ПАМЯТИ, я исключил проблемы ввода-вывода.

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

Следующим предположением была блокировка. В моем приложении есть / были некоторые очень медленные выборки в этой таблице. И это может быть проблемой: медленные выборки задерживают обновления, которые задерживают другие выборки, так что в конце концов этот очень простой и быстрый выбор может быть отложен.

Я проверил slow query log и нашел два частых и медленных выбора, которые использовали эту конкретную таблицу (и другие тоже). Причиной было плохо сформированное соединение в случае:

 A left join B on case
when A.x=1 then B.id=A.id2
when A.x=2 then B.id=A.id3
else B.id=0
end
  

вместо

 A left join B on B.id = case
when A.x=1 then A.id2
when A.x=2 then A.id3
else 0
end
  

Оба дают одинаковый результат, но последний может использовать индекс B.id , первый не может.

Как только я исправил эти запросы, производительность исходного запроса была значительно увеличена: 5ms вместо 500ms среднего. И 98% быстрее, чем в среднем.

Мораль:

  • используйте slow query log , анализируйте и улучшайте медленные запросы
  • если вы сталкиваетесь с необъяснимыми замедлениями, всегда проверяйте «пересекающиеся» запросы, которые замедляют ваш запрос, блокируя одну и ту же таблицу

Комментарии:

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

2. Спасибо за отзыв. Я не был уверен в принятии моего собственного ответа… Я получил сообщение «Вы можете принять свой собственный ответ через 2 дня», поэтому я немного подожду…