MySQL медленный запрос с объединением, хотя EXPLAIN показывает хороший план - PullRequest
5 голосов
/ 17 августа 2010

У меня есть следующий сценарий: В базе данных MySQL у меня есть 2 таблицы MyISAM, одна с 4,2 миллиона строк, а другая с 320 миллионами строк.Ниже приведена схема для таблиц:

Table1 (4,2M строк)

F1 INTEGER UNSIGNED NOT NULL PRIMARY KEY
f2 varchar(40)
f3 varchar(40)
f4 varchar(40)
f5 varchar(40)
f6 smallint(6)
f7 smallint(6)
f8 varchar(40)
f9 varchar(40)
f10 smallint(6)
f11 varchar(10)
f12 tinyint(4)
f13 smallint(6)
f14 text

Table2 (320M строк)

F1 INTEGER UNSIGNED NOT NULL PRIMARY KEY
f2 INTEGER UNSIGNED NOT NULL

Table2 находится в другой базе данныхно я использую хранимую процедуру, которая запрашивает две таблицы.Соотношение между двумя таблицами таково, что для Table1.F1 может быть до прибл.100 строк в Table2.F1 (внешний ключ), которые совпадают, и значение для Table2.f2 будет возвращено для этих соответствующих ключей.У меня есть индекс IX1 (f2 (15), f3 (10)) в таблице 1 и индекс IX2 (F1, f2) и IX3 (f2) в таблице 2

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

SELECT g.F1
FROM DB1.Table1 g 
INNER JOIN DB2.Table2 gp ON g.F1 = gp.F1 
WHERE (gp.f2 = 452677825) AND
(g.f2 = 'A string value') LIMIT 0,56

Этот запрос иногда выполняется очень быстро (<1 с), но изменение строкового значения, с которым сравнивается g.F2, приводит к запросам, которые занимают даже более 11, а иногда даже 30 секунд.Я не могу понять, почему это так.Ниже приведен вывод EXPLAIN для SELECT, который выполняется. </p>

1, 'SIMPLE', 'g', 'ref', 'PRIMARY,IX1', 'IX1', '17', 'const', 901, 'Using where'
1, 'SIMPLE', 'gp', 'ref', 'IX3,IX2', 'IX2', '8', 'DB1.g.F1,const', 1, 'Using index'

, который представляется довольно хорошим планом выполнения.Число строк в верхнем ряду объяснения не превышает 2000, но я не понимаю, почему для возврата результатов это может занять не более доли секунды.Я также запустил профилировщик для запроса и заметил, что запросы тратят 99,9% времени на этапе «Отправка данных».Кто-нибудь может объяснить, почему это так, и что можно сделать для оптимизации запроса?

Заранее спасибо, Тим

Ответы [ 3 ]

1 голос
/ 17 августа 2010

Я не эксперт в этой области, но вот несколько соображений:

Скорость запроса, занимающая больше времени при изменении g.F2, связана с кэшированием.MySQL будет сохранять результаты для каждого запроса (до тех пор, пока кэш не заполнится), но новые запросы выполняются в пустом кеше, поэтому они занимают больше времени.Вы не должны оптимизировать, основываясь на этом.(См. Как точно измерить )

По вашей информации я не могу сказать, обладает ли таблица g или gp большей специфичностью (похоже, gp?) Вwhere, но вы можете попробовать вместо этого подзапрос.(См. Как принудительно выполнить внутренний запрос вначале )

Что касается профилирования, возможно, вы достигли физического порога, такого как превышение оперативной памяти (использование swap губительно для производительности), чтоНепонятно из explain, или из-за того, что explain просто неправильный в этом случае.

0 голосов
/ 09 декабря 2010

Соотношение между двумя таблицами таково, что для Table1.F1 может быть до прибл.100 строк в Table2.F1

Чтобы уточнить, взаимосвязь между Table1.F1 и Table2.F1 один к одному или один ко многим?Для меня это утверждение подразумевает один ко многим, но из схемы каждое из полей является первичным (то есть уникальным) ключом.

В любом случае, я подозреваю, что униформа g.f2(15)единообразно, и что при попадании статистических выбросов соответственно снижается производительность.

Показывают ли результаты

SELECT f2(15) AS f2_15, COUNT(*) AS cnt
FROM Table1
GROUP BY f2(15) 
ORDER BY cnt DESC

некоторые существенные выбросы?

0 голосов
/ 18 августа 2010

Если вы в состоянии, вы можете попробовать настроить my.cnf, свойство, с которым вы хотите играть, это key_buffer_size . Индексы MyISAM хранятся в файлах .MYI, если вы их найдете и суммируете размеры файлов (например, ls -lh /var/lib/mysql/dbname/*.MYI), вы можете приблизительно оценить, насколько большим должен быть размер буфера ключа. все ваши индексы. Документация MySQL рекомендует не превышать 25% системной памяти.

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