MySQL возвращает ноль строк (пустой набор) без ограничений из-за неработающего / устаревшего индекса - PullRequest
1 голос
/ 07 февраля 2011

Я работаю с большой таблицей, содержащей около 1,5 тыс. Записей,

CREATE TABLE `crawler` (
`id` int(11) NOT NULL AUTO_INCREMENT,
...
`provider_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `crawler_provider_id` (`provider_id`),
...
) ENGINE=MyISAM ...

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

mysql> SELECT `crawler`.`id` FROM `crawler` WHERE `crawler`.`provider_id` > 1371;
Empty set (0.40 sec)

, но

mysql> SELECT COUNT(*) FROM `crawler` WHERE `crawler`.`provider_id` > 1371;
|   346999 |

и

mysql> SELECT `crawler`.`id` FROM `crawler` WHERE `crawler`.`provider_id` > 1371 LIMIT 10;
10 rows in set (0.01 sec)

Если я выберу некоторые данные из таблицы и проверим их самостоятельно, я смогу увидеть значения больше 1371.

Мне удалось исправить это, удалив индексы (и повторив позже), но я очень запутался.Я никогда не видел, чтобы индексы не синхронизировались с данными таблицы (и я не знал, что они могут повлиять на значения возвращаемых строк).К сожалению, я не выполнял «CHECK TABLE» перед удалением индексов, но сейчас он имеет «status = ok», я не вижу ничего плохого в журналах, и «REPAIR TABLE» не показывает проблем.

Итак, это общая проблема?В чем может быть причина?У этого сервера раньше были проблемы с нехваткой ОЗУ, может ли это быть проблемой и здесь?

Ответы [ 2 ]

1 голос
/ 18 марта 2011

Ваш запрос почти наверняка связан с повреждением таблицы в MyISAM.

Я сделал

root@localhost [kris]> create table crawler (
  id integer not null auto_increment primary key, 
  provider_id int(11) DEFAULT NULL, 
  PRIMARY KEY (id), 
  KEY crawler_provider_id (provider_id)
) engine = myisam;
root@localhost [kris]> insert into crawler ( id, provider_id ) values ( NULL, 1 );</code>

, а затем повторял

root@localhost [kris]> insert into crawler ( id, provider_id) 
  select NULL, rand() * 120000 from crawler;

, пока у меня не было

root@localhost [kris]> select count(*) from crawler;
+----------+
| count(*) |
+----------+
|   524288 |
+----------+
1 row in set (0.00 sec)

Теперь у меня есть

root@localhost [kris]> SELECT COUNT(*) FROM `crawler` WHERE `crawler`.`provider_id` > 1371;
+----------+
| COUNT(*) |
+----------+
|   518389 |
+----------+
1 row in set (0.27 sec)

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

Без предложения LIMIT я получаю полное сканирование таблицы (ALL) без индекса:

root@localhost [kris]> explain SELECT `crawler`.`id` FROM `crawler` WHERE `crawler`.`provider_id` > 1371\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: crawler
         type: ALL
possible_keys: crawler_provider_id
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 524288
        Extra: Using where
1 row in set (0.00 sec)

Спредложение LIMIT, INDEX используется для доступа RANGE

root@localhost [kris]> explain SELECT `crawler`.`id` FROM `crawler` WHERE `crawler`.`provider_id` > 1371 LIMIT 10\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: crawler
         type: range
possible_keys: crawler_provider_id
          key: crawler_provider_id
      key_len: 5
          ref: NULL
         rows: 518136
        Extra: Using where
1 row in set (0.00 sec)

В вашем примере, без предложения LIMIT (полное сканирование таблицы) вы не получите данных, но с предложением LIMIT (доступ к диапазону с использованием индекса)Вы получаете данные.Это указывает на поврежденный файл MYD.

ALTER TABLE, например REPAIR TABLE или OPTIMIZE TABLE, обычно копирует данные и сохраненные индексы из исходной таблицы в скрытую новую версию таблицы в новом формате.По завершении скрытая новая таблица заменит старую версию таблицы (которая будет переименована в скрытое имя, а затем отброшена).

То есть, удалив индексы, вы фактически восстановили таблицу.

0 голосов
/ 07 февраля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...