Непоследовательные результаты запроса от MySQL

Сегодня мы заметили странное поведение в SQL-запросах (мы используем MySQL v5.6.36 и InnoDB).

Возьмите этот запрос:

mysql> SELECT count(*)  FROM `inventory` WHERE `user_id` = 12345;

Он возвращает следующий результат:

+----------+
| count(*) |
+----------+
|      495 |
+----------+

Но тогда, когда выполняется следующий запрос:

mysql> SELECT count(*)  FROM `inventory` WHERE `user_id` = 12345 AND list_type = 3;

Получаем:

+----------+
| count(*) |
+----------+
|     1263 |
+----------+

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

Любые другие условия, кроме list_type, возвращают недопустимые (слишком высокие) значения.

Ответ 1

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

SELECT count(*)  FROM `inventory` USE INDEX () WHERE `user_id` = 12345;
SELECT count(*)  FROM `inventory` USE INDEX () WHERE `user_id` = 12345 AND list_type = 3;

Если это только индекс, вы можете попробовать

OPTIMIZE TABLE `inventory`;

Что воссоздает таблицы и индексы, а затем на нем ANALYZE. Это потому, что InnoDB не поддерживает REPAIR TABLE. Другим вариантом может быть попытка добавить идентичный индекс, а затем удалить исходный индекс.

Для выполнения проверок в таблице вы также можете использовать ПРОВЕРИТЬ ТАБЛИЦУ, но если вы хотите проверить всю базу данных, вы можете попробовать

mysqlcheck --login-path=credentials --databases db_name

и оптимизировать все таблицы

mysqlcheck --login-path=credentials --optimize --databases db_name

Просмотр журналов ошибок сервера может дать вам подсказку о том, была ли это проблема с оборудованием или ошибка MySQL, с которой вы столкнулись.

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

Ответ 2

Иногда SQL не может корректно обрабатывать значение "null". Попробуйте следующее:

mysql> SELECT count(*)  FROM inventory WHERE (user_id = 12345 AND user_id is not null) AND (list_type = 3 AND list_type is not null);

Если это не сработает, попробуйте заменить "*" на первичный ключ. Например:

mysql> SELECT count(user_id)  FROM inventory WHERE (user_id = 12345 AND user_id is not null) AND (list_type = 3 AND list_type is not null);

Хотя если user_id не может быть "null", в этом случае вам не нужно проверять это.