Выбор занимает много времени.Как решить эту проблему? - PullRequest
0 голосов
/ 08 апреля 2011

У меня большая база в MYSQL - 300 МБ, где 4 таблицы: первая около 200 МБ, вторая - 80. В первой таблице 150 000 записей, а во второй 200 000

В то же время я использую внутреннее соединение там.

Выбор занимает 3 секунды, когда я использую оптимизацию и инденды (до этого требовалось около 20-30 секунд). Это достаточно хороший результат. Но мне нужно больше, потому что страница загружается в течение 7-8 секунд (3-4 для выбора, 1 для подсчета, другие небольшие запросы 1 секунда и 1-2 для генерации страницы).

Итак, что мне тогда делать? Может быть, Postgres занимает меньше времени, чем MySQL? Или может быть лучше использовать memcache, но в этом случае это может занять много памяти (слишком много вариантов сортировки).

Может быть, у кого-нибудь есть другая идея? Я был бы рад услышать новый:)


OK. Я вижу, нам нужны запросы :) Я переименовал поля для table_1.

     CREATE TABLE  `table_1` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `field` varchar(2048) DEFAULT NULL,
      `field` varchar(2048) DEFAULT NULL,
      `field` int(10) unsigned DEFAULT NULL,
      `field` text,
      `field` text,
      `field` text,
      `field` varchar(128) DEFAULT NULL,
      `field` text,
      `field` text,
      `field` text,
      `field` text,
      `field` text,
      `field` varchar(128) DEFAULT NULL,
      `field` text,
      `field` varchar(4000) DEFAULT NULL,
      `field` varchar(4000) DEFAULT NULL,
      `field` int(10) unsigned DEFAULT '1',
      `field` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      `field` text,
      `new` tinyint(1) NOT NULL DEFAULT '0',
      `applications` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `indexNA` (`new`,`applications`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=153235 DEFAULT CHARSET=utf8;

CREATE TABLE  `table_2` (
  `id_record` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `catalog_name` varchar(512) NOT NULL,
  `catalog_url` varchar(4000) NOT NULL,
  `parent_id` int(10) unsigned NOT NULL DEFAULT '0',
  `checked` tinyint(1) NOT NULL DEFAULT '0',
  `level` int(10) unsigned NOT NULL DEFAULT '0',
  `work` int(10) unsigned NOT NULL DEFAULT '0',
  `update` int(10) unsigned NOT NULL DEFAULT '1',
  `type` int(10) unsigned NOT NULL DEFAULT '0',
  `hierarchy` varchar(512) DEFAULT NULL,
  `synt` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id_record`,`type`) USING BTREE,
  KEY `rec` (`id_record`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=14504 DEFAULT CHARSET=utf8;

CREATE TABLE  `table_3` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_table_1` int(10) unsigned NOT NULL,
  `id_category` int(10) unsigned NOT NULL,
  `work` int(10) unsigned NOT NULL DEFAULT '1',
  `update` int(10) unsigned NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `site` (`id_table_1`,`id_category`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=203844 DEFAULT CHARSET=utf8;

Есть вопросы: 1) получить общий счет (занимает менее 1 секунды):

SELECT count(table_1.id) FROM table_1
 INNER JOIN table_3 ON table_3.id_table_id = table_1.id
 INNER JOIN table_2 ON table_2.id_record = table_3.id_category
WHERE ((table_2.type = 0)
AND (table_3.work = 1 AND table_2.work = 1)
 AND (table_1.new = 1))AND 1 IN (table_1.applications)

2) получить список для страницы с лимитом (от 3 до 7 секунд, зависит от количества):

SELECT table_1.field, table_1.field, table_1.field, table_1.field, table_2.catalog_name FROM table_1
 INNER JOIN table_3 ON table_3.id_table_id = table_1.id
 INNER JOIN table_2 ON table_2.id_record = table_3.id_category
WHERE ((table_2.type = 0)
AND (table_3.work = 1 AND table_2.work = 1)
 AND (table_1.new = 1))AND 1 IN (table_1.applications) LIMIT 10 OFFSET 10

Ответы [ 6 ]

3 голосов
/ 08 апреля 2011

Не изменять СУБД

Я бы не советовал менять вашу СУБД, это может быть очень разрушительным.Если вы использовали специфичные для MySQL запросы, которые не совместимы с Postgres;вам может потребоваться повторить полное индексирование и т. д. Даже в этом случае это может не гарантировать повышения производительности.

Кэширование - это хороший вариант

Кэширование - это действительно хорошая идея.Он снимает нагрузку с вашей СУБД.Это лучше всего подходит, если у вас есть тяжелое чтение, легкое письмо.Таким образом, объекты будут оставаться в кэше больше времени.MemcacheD - действительно хороший механизм кэширования, и он действительно прост.Быстро масштабируемые сайты (такие как Facebook и тому подобное) активно используют MemcacheD для облегчения загрузки из базы данных.

Как масштабировать действительно большое время

Хотя,у вас нет очень тяжелых данных .. поэтому, скорее всего, кеширование поможет вам.Но следующий шаг перед кэшированием - это решения на основе noSQL, такие как Cassandra .Мы используем cassandra в одном из наших приложений, где у нас много операций чтения и записи (50:50), а база данных очень большая и быстро растет.Кассандра дает хорошие показатели.Но, я думаю, в вашем случае, Кассандра - это излишнее убийство .

Но ...

Раньше вы погружались в любые серьезные изменения,Я бы предложил по-настоящему заглянуть в индексы.Попробуйте масштабировать по вертикали.Посмотрите на медленные запросы.(Найдите директиву медленное ведение журнала запросов ).Надеемся, что после оптимизации MySQL будет быстрее, и вам не понадобятся дополнительные инструменты.

2 голосов
/ 08 апреля 2011

Вам следует обратить внимание на индексацию, относящуюся к наиболее частым / трудоемким запросам, которые вы используете.Проверьте этот пост на предмет индексации для MySQL.

1 голос
/ 08 апреля 2011

Помимо всех других предложений, предложенных другими, я немного изменил и не уверен в влиянии на производительность под MySQL. Однако я добавил STRAIGHT_JOIN, чтобы оптимизатор не пытался определить, к какому заказу или таблице присоединиться.

Затем я переместил условия «И» в соответствующие предложения JOIN для таблиц 2 и 3.

Наконец, объединение из таблицы с 1 по 3 (в вашем сообщении)

   table_3.id_table_id = table_1.id

вместо

   table_3.id_table_1 = table_1.id

Кроме того, я не могу определить производительность, но, возможно, у меня есть отдельный индекс только для «нового» столбца для точного соответствия в первую очередь без учета столбца «приложения». Я не знаю, является ли составной индекс причиной проблемы, поскольку вы используете «IN» для приложений, а не индексируемую базу поиска.

Вот измененные результаты

SELECT STRAIGHT_JOIN 
        count(table_1.id) 
    FROM 
        table_1
            JOIN table_3 
                ON table_1.id = table_3.id_table_1
                   AND table_3.work = 1
                JOIN table_2 
                    ON table_3.id_category = table_2.id_record
                    AND table_2.type = 0
                    AND table_2.work = 1
    WHERE 
            table_1.new = 1
        AND 1 IN table_1.applications


SELECT STRAIGHT_JOIN 
        table_1.field, 
        table_1.field, 
        table_1.field, 
        table_1.field, 
        table_2.catalog_name 
    FROM 
        table_1
            JOIN table_3 
                ON table_1.id = table_3.id_table_1
                AND table_3.work = 1
                JOIN table_2 
                    ON table_3.id_category = table_2.id_record
                    AND table_2.type = 0
                    AND table_2.work = 1
    WHERE 
            table_1.new = 1
        AND 1 IN table_1.applications
    LIMIT 10 OFFSET 10
0 голосов
/ 08 апреля 2011

Это на самом деле не такая большая база данных, конечно, не слишком много для вашей системы баз данных. Для сравнения, база данных, которую мы используем, в настоящее время составляет около 40 ГБ. Однако это MS SQL Server, поэтому он не может быть напрямую сопоставим, но между системами баз данных нет существенной разницы.

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

0 голосов
/ 08 апреля 2011

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

Оператор SELECT ...

Прежде всего, убедитесь, что ваш запрос "хороший"как это может быть.Есть ли какие-то индусы, которые вы могли пропустить?Это одинаковые типы полей и т. Д.?Не могли бы вы сузить запрос, чтобы у базы данных было меньше работы?

Кеш запросов ...

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

Аппаратное обеспечение ...

Конечно, разные СУБД работают медленнее или быстрее других, в зависимости от их прочности или слабости, но если ваш запрос оптимизирован до забвения, вы сможете получить его быстрее только при масштабировании сервера базы данных (лучше процессор, лучше ввод-вывод и т. Д.).в зависимости от того, где находится узкое место).

Другие факторы ...

Если все это исчерпано, возможно, попробуйте ускорить другие компоненты (1-2 секунды для генерации страницы выглядят довольно медленно для меня).

Ко всем перечисленным факторам в stackoverflow.com .

имеется огромное количество идей и сообщений.
0 голосов
/ 08 апреля 2011

Вам также следует оптимизировать свой запрос.

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