Простой константный выбор по первичному ключу в маленькой таблице MEMORY очень медленный
У меня есть таблица MEMORY с примерно 650 строками, длиной 5 МБ и длиной индекса 60 КБ (так что она довольно мала). Он имеет один SMALLINT первичный (хэш) ключ и около 90 других столбцов (целые, varchars, datetime, без BLOB-объектов или текстов). (РЕДАКТИРОВАТЬ: есть также ключ хеша в столбце BIGINT.)
Я выполняю этот запрос (из PHP) довольно часто (около 10 раз в секунду):
выберите * из userek, где id={CONST_ID} и kitiltva=0 и kitiltva_meddig<"{CONST_DATETIME}" и inaktiv = 0
Замечания: id
является первичным ключом. мне нужно *
потому что результат используется во многих разных местах, и в основном все столбцы используются здесь или там.
Моя проблема: запрос становится ненормально медленным на регулярной основе. Около 0.5s
в среднем, 8s
Максимум. В большинстве случаев это очень быстро: 75%
работает быстрее, чем 3ms
, 85%
быстрее, чем в среднем. Но 15%
это медленнее, чем в среднем, 13%
медленнее чем 1s
, Так что у него длинный хвост.
И я абсолютно не знаю, что может быть причиной этого. Есть какие-нибудь мысли?
1 ответ
Извините за ответ на мой вопрос, но, по крайней мере, у меня есть ответ. Я стараюсь писать так, чтобы это помогало другим.
Так как это таблица MEMORY, я исключил проблемы ввода-вывода.
Далее, запрос является простым (постоянным) выбором по первичному ключу, поэтому он также не может быть проблемой индексации.
Следующее предположение было блокировкой. В моей заявке на эту таблицу есть / были очень медленные выборки. И это может быть проблемой: медленные выборки задерживают обновления, которые задерживают другие выборки, так что в итоге этот очень простой и быстрый выбор может быть отложен.
Я проверил 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
, проанализируйте его и улучшите медленные запросы - если вы сталкиваетесь с необъяснимым замедлением, всегда проверяйте "перекрестные" запросы, которые замедляют ваш запрос, блокируя ту же таблицу