2016-03-14 3 views
-1

у меня есть эта таблица:очень медленно простой MySql запрос с индексом

CREATE TABLE `messenger_contacts` (
    `number` varchar(15) NOT NULL, 
    `has_telegram` tinyint(1) NOT NULL DEFAULT '0', 
    `geo_state` int(11) NOT NULL DEFAULT '0', 
    `geo_city` int(11) NOT NULL DEFAULT '0', 
    `geo_postal` int(11) NOT NULL DEFAULT '0', 
    `operator` tinyint(1) NOT NULL DEFAULT '0', 
    `type` tinyint(1) NOT NULL DEFAULT '0' 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

ALTER TABLE `messenger_contacts` 
    ADD PRIMARY KEY (`number`), 
    ADD KEY `geo_city` (`geo_city`), 
    ADD KEY `geo_postal` (`geo_postal`), 
    ADD KEY `type` (`type`), 
    ADD KEY `type1` (`operator`), 
    ADD KEY `has_telegram` (`has_telegram`), 
    ADD KEY `geo_state` (`geo_state`); 

около 11 миллионов записей.

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

select count(number) from messenger_contacts where geo_state=1 

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

UPDATE:

ОК, я сделал некоторые изменения типа и размера столбцов:

CREATE TABLE IF NOT EXISTS `messenger_contacts` (
    `number` bigint(13) unsigned NOT NULL, 
    `has_telegram` tinyint(1) NOT NULL DEFAULT '0' , 
    `geo_state` int(2) NOT NULL DEFAULT '0', 
    `geo_city` int(4) NOT NULL DEFAULT '0', 
    `geo_postal` int(10) NOT NULL DEFAULT '0', 
    `operator` tinyint(1) NOT NULL DEFAULT '0' , 
    `type` tinyint(1) NOT NULL DEFAULT '0' , 
    PRIMARY KEY (`number`), 
    KEY `has_telegram` (`has_telegram`,`geo_state`), 
    KEY `geo_city` (`geo_city`), 
    KEY `geo_postal` (`geo_postal`), 
    KEY `type` (`type`), 
    KEY `type1` (`operator`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

Теперь запрос занимает всего 4 до 5 секунд с * и number

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

+0

сколько своего рода состояние делает geo_state есть? и какой процент состояния = 1 во всех типах состояний? –

+2

Каков результат 'explain extended select count (number) из messenger_contacts, где geo_state = 1'? Я бы добавил это к вашему вопросу, поскольку это одна из полезных вещей, помогающая отлаживать. –

+0

Ошибка в вашем mysql: '\' type \ 'tinyint (1) NOT NULL DEFAULT '0'''. На линии есть двойные одинарные кавычки. – maxhb

ответ

0

Может

select count(geo_state) from messenger_contacts where geo_state=1 

как это даст тот же результат, но не будет использовать номер столбца из кластерного индекса?

Если это не помогает, я попытаюсь изменить номер столбца на тип INT, который должен уменьшить размер индекса или попытаться увеличить объем памяти, который MySQL может использовать для кеширования индексов.

0

Вы не изменили типы данных. INT(11) == INT(2) == INT(100) - каждый представляет собой 4-байтовое целое число со знаком. Вероятно, вам понадобится 1-байтовый неподписанный TINYINT UNSIGNED или 2-байтовый SMALLINT UNSIGNED.

Это отходы для индексации «флагов», которые я принимаю type и has_telegram. Оптимизатор никогда не будет использовать их, потому что он будет менее эффективен, чем просто сканирование таблицы.

Стандартная модель кодирования:

select count(*) 
    from messenger_contacts 
    where geo_state=1 

, если вам нужно не сосчитать NULLs, что и COUNT(geo_state) подразумевает.

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

Причина 30-60 секунд в сравнении с 4-5 секундами, скорее всего, будет кешировать. Первому пришлось читать вещи с диска; последний этого не сделал. Выполните запрос дважды.

Использование индекса geo_state будет быстрее этого запроса, чем при использовании PRIMARY KEYесли не кэшируем различия.

INDEX(number,geo_state) фактически бесполезен для любого упомянутого SELECTs - geo_state должен быть первым. Это пример индекса «покрытия» для случая select count(number)....

More on building indexes.

Смежные вопросы