Можно ли оптимизировать эти SQL-запросы дальше? - PullRequest
0 голосов
/ 31 января 2011

У меня есть приложение Rails (работающее под учетной записью Heroku), которое собирает статистику для домашней страницы о количестве записей, которые соответствуют определенным критериям.Каждый счет отображается как число на странице.Моя таблица (списки) состоит из около 22 500 записей.На производстве загрузка страницы занимает около 350 мс (все еще ниже порогового значения, но не очень хорошо для домашней страницы).

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

SELECT COUNT(1) FROM listings WHERE (city in ('Syracuse'))
SELECT COUNT(1) FROM listings WHERE (city in ('Syracuse')) AND (created_at >= '2011-01-30 18:28:44.656702')
SELECT COUNT(1) FROM listings WHERE (city in ('Cicero', 'Clay', 'Lysander', 'VanBuren', 'Salina'))
SELECT COUNT(1) FROM listings WHERE (city in ('Cicero', 'Clay', 'Lysander', 'VanBuren', 'Salina')) AND (created_at >= '2011-01-30 18:28:44.811090')
SELECT COUNT(1) FROM listings WHERE (city in ('DeWitt', 'Manlius', 'Pompey'))
SELECT COUNT(1) FROM listings WHERE (city in ('DeWitt', 'Manlius', 'Pompey')) AND (created_at >= '2011-01-30 18:28:44.954442')
SELECT COUNT(1) FROM listings WHERE (city in ('Onondaga', 'Elbridge', 'Geddes', 'Camillus'))
SELECT COUNT(1) FROM listings WHERE (city in ('Onondaga', 'Elbridge', 'Geddes', 'Camillus')) AND (created_at >= '2011-01-30 18:28:45.105438')
SELECT COUNT(1) FROM listings WHERE (city in ('Fabius', 'Lafayette', 'Marcellus', 'Otisco', 'Skaneateles', 'Spafford', 'Tully'))
SELECT COUNT(1) FROM listings WHERE (city in ('Fabius', 'Lafayette', 'Marcellus', 'Otisco', 'Skaneateles', 'Spafford', 'Tully')) AND (created_at >= '2011-01-30 18:28:45.258860')
SELECT COUNT(1) FROM listings WHERE (city in ('West Monroe', 'Hastings', 'Constantia', 'Palermo', 'Mexico', 'Parish', 'Schroeppel'))
SELECT COUNT(1) FROM listings WHERE (city in ('West Monroe', 'Hastings', 'Constantia', 'Palermo', 'Mexico', 'Parish', 'Schroeppel')) AND (created_at >= '2011-01-30 18:28:45.411138') 

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

Спасибо!

Ответы [ 3 ]

4 голосов
/ 31 января 2011

Различные подходы, не все ориентированы на базы данных.

Вы можете объединить все выборки в один запрос следующим образом:

SELECT COUNT(CASE WHEN city = 'Syracuse' THEN 1 END) as syracuse,
       COUNT(CASE WHEN city = 'Syracuse' AND created_at >= '2011-01-30 18:28:44.656702' THEN 1 END) as syracuse_recent,
       /* etc... */
FROM listings

Это будет всего один просмотр таблицы, чтобы собрать всю статистику.

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

0 голосов
/ 31 января 2011

Лично я бы добавил две новые таблицы, одна из которых содержит группы городов, а другая таблица связей между многими между группами и городами.Вам понадобятся "city_group_id", "city_group_name", "dt_count_threshold".Вторая таблица будет "city_group_id", "city_id".Затем вы можете выполнить выборку по таблице ссылок «многие ко многим» и присоединиться к таблице города с вашим ограничением даты / времени.

-- unrestricted count
selec cg.city_group_name, count(*) as cnt
from dbo.city_group cg
join dbo.city_group_city cgc on cg.city_group_id = cgc.city_group_id
group by city_group_name

-- restricted
selec cg.city_group_name, count(*) as cnt
from dbo.city_group cg
join dbo.city_group_city cgc on cg.city_group_id = cgc.city_group_id
join dbo.city c on c.city_id = cgc.city_id
group by city_group_name
where c.created_at >= cg.dt_count_threshold

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

0 голосов
/ 31 января 2011

Сначала вы должны проверить, какие индексы у вас есть в таблицах (попробуйте добавить и удалить индексы для отдельных полей, а также составные индексы в обоих направлениях).

Также убедитесь, что вы точно проанализировали, из чего состоит 350 мс.(с firebug или чем-то вроде YSlow).

Наконец, если у вас действительно есть редкие обновления, и вы хотите поддерживать сводную таблицу, перехваты - не единственный способ - вы также можете написать триггер, который сделает эту работу за вас.

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