Я прочитал статьи об FORCE
индексе, но как я могу заставить MySQL IGNORE ALL
индексировать?
Я пытался SELECT * FROM tbl IGNORE INDEX(*)
, но мне не удалось.
Что касается того, почему я (и другие) должны сделать это: например, мне нужно было суммировать статистику рефереров по tld следующим образом:
SELECT
count(*) as c,
SUBSTRING
(
domain_name,
LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
) as tld
FROM `domains_import`
IGNORE INDEX(domain_name)
GROUP BY tld
ORDER BY c desc
LIMIT 100
... но я всегда должен смотреть, какие индексы определены, или определить, какой индекс будет использоваться с помощью объяснения. Было бы очень удобно просто написать IGNORE INDEX ALL
и просто пофиг.
Кто-нибудь знает синтаксис или хак? (Десятки строк через таблицы определений MySQL на самом деле не являются ярлыком).
Добавлено из чата :
Bechmark:
без индекса = 148,5 с
с индексом = 180 секунд и все еще работает с отправкой данных Массив SSD настолько мощен, что вам почти нет дела до кеша данных ...
Определение для эталона:
CREATE TABLE IF NOT EXISTS `domains_import` (
`domain_id` bigint(20) unsigned NOT NULL,
`domain_name` varchar(253) CHARACTER SET ascii COLLATE ascii_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `domains_import`
ADD PRIMARY KEY (`domain_id`),
ADD UNIQUE KEY `domain_name` (`domain_name`);
ALTER TABLE `domains_import`
MODIFY `domain_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT;
InnoDB, тест с индексом (без USE INDEX () или аналогичным) все еще выполняется, 250 секунд, я просто убил его.
LEFT JOIN
них. `USE INDEX ()` заставил MySQL выполнить сканирование таблицы в таблице строк по 20 КБ и 1 к 1JOIN
с вместо пересечения 500 строк между двумя индексами. Получил в 20 раз быстрее.Вы также можете вставлять
WHERE 1=1
ypercube только что спросил меня
Да, но вы дали MySQL действительно тупой запрос.
1=1
вернется к кластерному индексу. Несмотря на это, есть еще один способ, но он требует, чтобы оптимизатор был немного вредоносным.Это будет отбрасывать каждый индекс под шиной наверняка, потому что значение каждой строки для
domain_name
многих будет проверено. Еслиdomain_name
индексирован, вы должны выбрать столбец для того,WHERE column_name=column_name
который вообще не индексируется.Я только что попробовал это на большом столе в промежуточном сервере
Индексы не выбраны
источник
WHERE id+0 = id*1
индекс все равно будет использоваться, и появится дополнительныйUsing where
.Предполагая, что у вас есть эти два индекса:
Тогда не имеет значения, что делает оптимизатор; он должен сканировать по существу одинаковое количество материала.
Случай 1: он выполняет сканирование таблицы (или использует domain_id): он сканирует пары (id, name), находит все имена, выполняет SUBSTRING..LOCATE, GROUP BY и, наконец, ORDER BY. Каждому из GROUP BY и ORDER BY, вероятно, нужны таблица tmp и файловая сортировка. Проверьте,
EXPLAIN SELECT ...
если это так.Случай 2: он выполняет сканирование индекса (имя_домена): этот индекс фактически содержит пары (имя, идентификатор) - потому что InnoDB неявно помещает PK в конец любого вторичного ключа. Остальные параллели обработки Случай 1.
Одна вещь может отличаться - размер двух BTrees. Есть ,
SHOW TABLE STATUS LIKE domains_import
чтобы увидеть Data_length (для случая 1) и Index_length (для случая 2). Чем больше BTree будет медленнее.Другое дело может быть иначе - кеширование. Какова стоимость
innodb_buffer_pool_size
? Сколько у вас оперативной памяти? Могут ли Данные (или Индекс) содержаться в пуле буферов. (Или это будет 37% из-за того, что это сканирование таблицы / индекса?) Если оно подходит, тогда выполните запрос дважды. Второй раз будет примерно в 10 раз , как быстро из - за не ударять диск (кэширование).Если это разовая задача, SSD поможет. Если нет, и вы можете кэшировать всю таблицу, то это не поможет после загрузки buffer_pool.
источник