обработка большого количества записей в базе данных с подкачкой со временем замедляется - PullRequest
7 голосов
/ 13 сентября 2011

Я пытаюсь обработать миллионы записей из моей таблицы (размер около 30 ГБ), и в настоящее время я делаю это с помощью подкачки страниц (mysql 5.1.36).Запрос, который я использую в цикле for:

select blobCol from large_table 
where name= 'someKey' and city= 'otherKey' 
order by name
LIMIT <pageNumber*pageSize>, <pageSize>

Это прекрасно работает для примерно 500K записей.У меня размер страницы 5000, который я использую, и после 100 страницы запросы начинают сильно замедляться.Первые ~ 80 страниц извлекаются за 2-3 секунды, но после примерно страницы 130 каждая страница занимает около 30 секунд для извлечения, по крайней мере, до страницы 200. Один из моих запросов имеет около 900 страниц, и это займет слишком много времени.

The table structure is (type is MyISAM)
    name char(11)
    id int // col1 & col2 is a composite key
    city varchar(80) // indexed
    blobCol longblob

Что я могу сделать, чтобы ускорить его?Объяснение для запроса показывает это

select_type: SIMPLE
possible_keys: city
key : city
type: ref
key_len: 242
ref: const
rows: 4293720
Extra: using where; using filesort

В случае, если это помогает, my.cnf для моего сервера (оперативная память 24 ГБ, 2 четырехъядерных процессора) содержит эти записи

  key_buffer_size = 6144M
  max_connections = 20
  max_allowed_packet = 32M
  table_open_cache = 1024
  sort_buffer_size = 256M
  read_buffer_size = 128M
  read_rnd_buffer_size = 512M
  myisam_sort_buffer_size = 128M
  thread_cache_size = 16
  tmp_table_size = 128M
  max_heap_table_size = 64M

Ответы [ 3 ]

2 голосов
/ 13 сентября 2011

Вот что я сделал, и сократил общее время выполнения в 10 раз.

Что я понял из плана выполнения моего исходного запроса, так это то, что он использовал сортировку файлов для сортировки всех результатов и игнорирования индексов. Это пустая трата.

Моя тестовая база данных: 5 млн записей, размер 20 ГБ. структура таблицы такая же, как в вопросе

Вместо того, чтобы получать blobCol непосредственно в первом запросе, я сначала получаю значение 'name' для начала каждой страницы. Запускайте этот запрос бесконечно, пока он не вернет 0 результатов Каждый раз добавлять результат в список

SELECT name
FROM my_table
where id = <anyId> // I use the id column for partitioning so I need this here
order by name
limit <pageSize * pageNumber>, 1

Номер страницы синуса ранее не известен, начинайте со значения 0 и продолжайте увеличивать, пока запрос не вернет значение NULL. Вы также можете сделать счетчик выбора (*), но это само по себе может занять много времени и не поможет ничего оптимизировать На выполнение каждого запроса уходило около 2 секунд, если номер страницы превышал ~ 60.

Для меня размер страницы был 5000, поэтому я получил список строк с именами в позициях 0, 5001, 10001, 15001 и так далее. Число страниц оказалось равным 1000, а сохранение списка из 1000 результатов в памяти не является дорогостоящим.

Теперь, переберите список и выполните этот запрос

SELECT blobCol
FROM my_table
where name >= <pageHeader>
and name < <nextPageHeader>
and city="<any string>"
and id= 1

Это будет выполнено N раз, где N = размер списка, полученного ранее. Поскольку «имя» является первичным ключом col, а «город» также индексируется, EXPLAIN показывает, что это вычисление выполняется в памяти с использованием индекса.

Теперь на выполнение каждого запроса уходит 1 секунда, а не 30-40. Таким образом, объединяя время предварительной обработки 2 секунды на страницу, общее время на страницу составляет 3-4 секунды вместо 30-40.

Если у кого-то есть лучшее решение или если с этим что-то явно не так, пожалуйста, дайте мне знать

0 голосов
/ 13 сентября 2011

В прошлом я пробовал то же самое с базой данных Oracle 10g и получил тот же результат (в моей таблице было 60 миллионов строк). Первые страницы были получены быстро, но по мере увеличения номера страницы запрос становился слишком медленным. С индексами вы мало что можете сделать, так как они выглядят правильно, и я не уверен, чего вы можете добиться, настроив конфигурацию базы данных. Я предполагаю, что у меня были другие требования, но единственное решение, которое я нашел, - сбросить данные в файлы. Если у вас есть ограниченный набор значений для col1, вы можете избавиться от col1 и сгенерировать n таблиц, по одной на каждое известное значение col1. Если col1 неизвестно, то я не знаю решение этой проблемы. Вы можете извлечь небольшие наборы данных из очень больших таблиц, но получение больших наборов данных занимает много времени, а разбивка на страницы вам совсем не помогает. Вы должны выполнить предварительную обработку, создав дамп в файлы или создав другие таблицы для разделения данных.

0 голосов
/ 13 сентября 2011

Вы можете сделать свой запрос более точным, чтобы ограничение было ниже.

SELECT col1,col2, col4 
FROM large_table
WHERE col1>"SomeKey" OR 
(col1="SomeKey" AND col2>="OtherKey")
ORDER BY col1,col2
LIMIT PageSize

, но обновляйте «SomeKey» и «OtherKey» после каждого вызова базы данных.

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