Mysql select при замедлении индексированного столбца на больших таблицах - PullRequest
5 голосов
/ 06 июня 2011

У меня есть две таблицы: A - 301 столбец (1-й с именем a1 int (11) Primary Key, 2-й до 301-й - double (15,11)) & B - 33 столбца (1-й - b1 int (11) Уникальный Ключ, 2-й - b2 varchar (100) Первичный ключ, ..., 33-й - b33 int (11) MUL).

Оба A & B имеют ~ 13 500 000 записей.

Мой запрос MySQL: для каждого значения pos с pos в множестве (1, 1000, 2000, ..., 13500000), кратном 1000:

выберите A. *, b2, b5, b7, b8, b10, b13, b33 из соединения A с B на a1 = b1, где b33> = pos и b33

Запрос занимает 1-5 секунд для значений b33 <= 600 000. После этого запрос начинает занимать 20-30 секунд. Когда b33> = 8 000 000, запрос начинает занимать 60-70 с. Я не могу понять, почему происходит замедление. b33 индексируется, и соединение происходит по ключу, который определен как первичный в одной таблице и уникален в другой. Есть ли обходной путь для этого? Это действительно ограничивает скорость кода, и мне придется разделить таблицы A и B на несколько меньших, если ничего не работает. Я действительно надеюсь, что мне не нужно этого делать! Пожалуйста, помогите!

РЕДАКТИРОВАТЬ: Вот о / п EXPLAIN -

************* 1. ряд *************
id: 1
select_type: SIMPLE
стол: B
тип: диапазон
возможные ключи: b1, b33
ключ: b33
key_len: 4
ref: NULL
ряды: 981
Дополнительно: Использование где
************* 2 ряд *************
id: 1
select_type: SIMPLE
стол: A
тип: eq_ref
Возможные ключи: ПЕРВИЧНЫЕ
ключ: ПЕРВИЧНЫЙ
key_len: 4
ref: DBName.B.b1
ряды: 1
Дополнительно:
2 ряда в наборе (0,00 с)

Ответы [ 7 ]

1 голос
/ 10 августа 2011

Поскольку в вашей базе данных несколько миллионов записей, вы что-нибудь делаете для поддержания здоровья вашей БД?

Выполнение следующей команды по ночам может помочь с общей отзывчивостью, если ваши данные часто изменяются (может быть, много вставок?):

mysqlcheck --check --analyze --auto-repair --all-databases --silent

Хотя я бы предложил немного прочитать о mysqlcheck перед запуском команды, просто чтобы вы знали, что она делает.

Вам также следует взглянуть на , оптимизирующую конфигурацию InnoDB , особенно innodb_buffer_pool_size (чем больше памяти вы можете выделить, тем лучше). Я испытывал похожую медлительность для поля на основе даты (которое, конечно, мы сразу же проиндексировали) в таблице с аналогичным размером, и увеличение размера пула буферов с 8 мегабайт по умолчанию до нескольких гигабайт имело очень заметную разницу.

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

0 голосов
/ 28 июля 2011

ayesha129p,

попробуйте переместить ограничения b33 в предложение join.Похоже, оптимизатор применяет только одно из ограничений b33 перед созданием набора соединений.

select A.*, b2, b5, b7, b8, b10, b13, b33 from A join B
  on a1=b1 and b33 >= pos and b33 < pos+1000;

Таким образом, оптимизатор должен использовать индекс b33 и уменьшить строку B, установленную до 1000, прежде чем пытатьсяприсоединиться.

0 голосов
/ 13 июля 2011

ВАМ НЕОБХОДИМО ОТРАЖАТЬ ЭТОТ ЗАПРОС !!!

Вот ваш старый запрос:

select A.*, b2, b5, b7, b8, b10, b13, b33
from A join B on a1=b1 where b33 >= pos and b33 < pos+1000;

Вот новый:

SELECT
    AAA.*,b2,b5,b7,b8,b10,b13,b33
FROM
    A AAA INNER JOIN
    (
        select
            A.a1,b2,b5,b7,b8,b10,b13,b33
        from
            A INNER JOIN
            (
               SELECT
                   b1,b2,b5,b7,b8,b10,b13,b33
               FROM B
               WHERE
                    b33 >= pos and
                    b33 < pos+1000
            ) BB
            ON A.a1=B.b1
    ) BBB
    USING (a1)
;

CAVEAT

Цель этого реорганизованного запроса - сделать временные таблицы в плане запроса как можно меньшими. Фактически, подзапрос BBB никогда не должен иметь более 1000 строк в любой момент времени .

Дай попробовать !!!

0 голосов
/ 13 июля 2011

Объясните план и индексы вроде нормально.

Я предлагаю вам сравнить профили и посмотреть, куда на самом деле уходит время:

SET profiling=1;

select A.*, b2, b5, b7, b8, b10, b13, b33 from A join B on a1=b1 where b33 >= 0 and b33 < 1000;
SHOW PROFILE;

select A.*, b2, b5, b7, b8, b10, b13, b33 from A join B on a1=b1 where b33 >= 1000000 and b33 < 1001000;
SHOW PROFILE;


SET profiling=0;

но я думаю, что это может быть медленно из-за того, что индексный пост 600k больше не помещается в память и выполняется больше операций поиска диска

0 голосов
/ 13 июля 2011

Можете ли вы показать нам индексы, которые вы настроили на B? (интересует, как определяется индекс на b33 и определяется ли он для одного или нескольких столбцов):

SHOW INDEXES FROM B;

Видите ли вы то же снижение скорости, когда вы выбираете только из B?

е

select b2, b5, b7, b8, b10, b13, b33 from B where b33 >= pos and b33 < pos+1000;

Можете ли вы показать нам часть из SHOW CREATE TABLE, которая включает в себя поле b33 (заинтересованы в NULL разрешено)

Используете ли вы MyISAM или InnoDB в качестве движка базы данных? (Вы можете увидеть это в результате SHOW CREATE TABLE).

0 голосов
/ 06 июня 2011

Просто выстрел в темноте ...

select A.*, b2, b5, b7, b8, b10, b13, b33 
  from A join B 
  on a1=b1 
  where b33 BETWEEN pos AND pos+999;
0 голосов
/ 06 июня 2011

Я не гуру MySQL (или что-то еще!), Но некоторые вещи я бы рассмотрел. Во-первых, равномерно ли распределен b33? Может быть, это медленнее, потому что эффективно извлекает больше строк? Во-вторых, рассматриваете ли вы сделать всю работу в одном запросе вместо 13500? Что-то вроде:

select A.*, b2, b5, b7, b8, b10, b13, b33, (b33 - 1 DIV 1000) the_group
from A join B on a1=b1 

В-третьих, дикая догадка, если ваша версия MySQL поддерживает это, сначала используйте фильтрацию inlinew, чтобы выполнить фильтрацию:

select A.*, b2, b5, b7, b8, b10, b13, b33 
from A join (select b1,b2, b5, b7, b8, b10, b13, b33 
             from B b33 >= pos and b33 < pos+1000) B_NEW 
     on a1=b1 ;

В-четвертых (должен быть первым), составьте план объяснения и попытайтесь выяснить, почему запрос медленный, сравнивая быстрые запросы с медленными.

Удачи !!

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