Непоследовательные результаты запроса от 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", в этом случае вам не нужно проверять это.