Получите верхний ряд my MySQL как можно быстрее (также на больших столах) - PullRequest
0 голосов
/ 04 мая 2020

У меня есть простое программное обеспечение для промышленного оборудования, которое использует MySQL в качестве хранилища данных. В данный момент в базе данных только одно соединение и один пользователь.

Моя таблица проста:

id   data            fetched 
int  varchar         boolean

1     KDINNALSKDGJ     0
2     F34LNALNLIJA     0

et c. Идентификатор всегда последовательный и имеет индекс.

Что мне нужно, так это чтобы всегда получать первые «данные» (с наименьшим идентификатором), где выборка равна 0. Затем обновите «выборка», чтобы она стала «1», потому что Я получил данные.

Я использую что-то вроде

SELECT id, data FROM mytable WHERE fetched=0 LIMIT 0,1

Это работает, но становится последовательно медленнее для каждого вызова. Это моя настоящая проблема. Я могу жить с приблизительными 0,005 секундами для первых 100 или около того, но при 50,000+ я против 0,3 секунд.

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

Ограничение индекса по номеру намного быстрее:

SELECT id, data FROM mytable WHERE id> :myLastID  and fetched=0 LIMIT 0,1

.. но это также замедляется после 40.000 или около того, при 80.000 я около 20 мсек c (первый около 6 мсек c)

Моя окончательная база данных может быть в миллионах, но обычно может быть около 2-500.000

Есть ли способ сделать MySQL возврат " следующая запись "быстрее? Используя КУРСОР из MySQL?

Я буду использовать Delphi для взаимодействия с MySQL. Я попробовал и хранимую процедуру и используя 2 запроса для выбора / обновления. Почти такой же результат.

Ответы [ 2 ]

3 голосов
/ 04 мая 2020

Как стартер: вашему запросу нужно предложение order by, в противном случае фактически не определено, какая строка будет возвращена первой (нет гарантии, что это будет строка с наименьшим id).

Так что вы должны сформулировать это следующим образом:

select id, data 
from mytable 
where fetched = 0 
order by id
limit 1

Тогда для производительности я бы рекомендовал добавить следующий индекс:

create index myindex on mytable(fetched, id, data)

Лог c:

  • первый столбец индекса, fetched, соответствует предикатам в предложении where

  • , второй столбец - столбец порядка (id)

  • третий столбец - оставшийся столбец в предложении select (data)

Это дает охватывающий индекс : MySQL должен иметь возможность выполнить весь запрос, просматривая только индекс (ie без просмотра самих данных).

1 голос
/ 04 мая 2020

ЕСЛИ есть только одно соединение, можем ли мы также предположить, что есть только один «пользователь»? Если так, то почему бы просто не сохранить значение id в памяти программы и запросить первый следующий номер, просто запросив «следующую» запись. Например, SELECT data FROM table WHERE id = @x AND fetched = 0? Если ничего не возвращается, то вы знаете, что значение уже было извлечено ранее и что-то вышло из-под контроля c (или в таблице закончились записи). Это должно быть исключительным, и вам придется вернуться к старому запросу, чтобы вернуться в нужное русло, я думаю, но опять же, оно должно быть исключительным.

Не потребует никаких других изменений (я предполагаю, id - это PK, когда вы говорите «index»)

PS: поскольку вы не упоминаете об этом, имеет ли значение InnoDB против MyISAM? (Я бы предпочел первое из того, что я прочитал, но у меня нет практически никакого практического опыта)

И, да, как уже упоминалось, LIMIT 1 без ORDR BY будет довольно многое даст вам "случайные результаты". Это может быть сделано специально, но это редко, и в большинстве ситуаций при повторном запуске предпочитают получать те же результаты.

...