2013-09-17 6 views
1

Я мало что знаю о оптимизации БД/управлении памятью.Лучше ли хранить результаты запроса в памяти или запускать один и тот же запрос несколько раз?

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

SELECT Value 
FROM ValueTable 
WHERE SomeConstraint > 4 

Мне нужно, чтобы получить результаты этого запроса, а также результаты от этого запроса с одним дополнительным ИНЕКЕМ. Какой из этих двух подходов лучше?

1) Выберите результаты этого запроса в переменной. Тогда есть два дополнительных запросов

SELECT COUNT(DISTINCT(VALUES)) 
FROM @SavedQuery 

SELECT COUNT(DISTINCT(VALUES)) 
FROM @SavedQuery 
WHERE otherConstraintColumn < 30 

2)

SELECT COUNT(DISTINCT(Value)) 
    FROM ValueTable 
    WHERE SomeConstraint > 4 

    SELECT COUNT(DISTINCT(Value)) 
    FROM ValueTable 
    WHERE SomeConstraint > 4 
    AND otherConstraintColumn < 30 

Это потенциально может быть написано в LINQ, так что может быть, как мы храним результаты запроса.

+0

Как вы будете использовать кешированный querey для выполнения счета, счет в базе данных довольно эффективен, чем получение результатов и подсчет в памяти. Я бы выбрал вариант 2 точно. –

+0

Этот вопрос почти невозможно ответить, поскольку он будет сильно зависеть от ваших конкретных потребностей и настройки. Сколько строк вы возвращаетесь? Насколько медленна латентность между БД и веб-сервером? Сколько памяти/скорости у вас есть на веб-сервере? Каковы конкретные требования к отзывчивости для веб-страницы? Сколько других запросов выполняется одновременно? Сколько пользователей одновременно попадает на эту страницу? Я мог бы спросить гораздо больше, но я думаю, вы поняли. – JDB

+0

Процитировать Brent Ozar: «Самый быстрый запрос - тот, который вы никогда не делаете». Хотя я согласен с киборгом, все зависит от вашего сценария. – DaveShaw

ответ

2

Для вашего конкретного примера подход # 1 более масштабируемый (получить исходные результаты, нефильтровать и повторно фильтровать их на стороне клиента с помощью LINQ), но он менее эффективен. Имейте в виду, что серверы баз данных обычно намного лучше/быстрее/эффективнее при запросе и фильтрации данных.

Правило № 1 всегда: не злоупотребляйте своей БД. Итак, поставите этот совет впереди всего, что я говорю.

Когда я смотрю на ваш пример, вы только, кажется, запрашиваете базу данных 2 раза. Это не оскорбительно. Итак, я бы сказал, подойдите к подходу № 2 (два отдельных запроса). Однако позвольте мне также квалифицировать этот совет: если вы используете этот блок в цикле или этот код выполняется сотни раз в день, я бы изменил свой совет. 2 повторных запроса довольно легкие и несущественные, но есть много условий, где это может быть ужасно.


Вообще говоря, в отношении оптимизации, если вы используете ASP.NET, он имеет некоторые действительно хорошие механизмы кэширования встроенный. Они лучше, чем сохранение результатов запроса в сеансе или в представлении. http://msdn.microsoft.com/en-us/library/6hbbsfk6(v=vs.90).aspx

Если вы используете winforms и т. Д., Сохранение результатов в памяти будет полезно, если вы не плотно запомните память.

Вот является статья SO идет о нескольких других популярных подходах: Best way to cache data

+0

Связанный вопрос - плохой пример вопроса SO, поскольку он слишком основан на мнениях. Статья в одном из ответов была бы гораздо лучшей ссылкой: http://www.25hoursaday.com/weblog/2007/07/05/ASPNETCachingVsMemcachedSeekingEfficientDataPartitioningLookupAndRetrieval.aspx – JDB

2

Наиболее эффективный подход был бы получить оба счетчик с помощью одного запроса, например:

SELECT COUNT(DISTINCT(t.Value)) AS count1 
    , COUNT(DISTINCT(CASE WHEN t.otherConstraintColumn<30 THEN t.Value END))) AS count2 
    FROM ValueTable t 
WHERE t.SomeConstraint > 4 

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

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

Первый запрос, который вы показываете, не будет иметь достаточных данных для удовлетворения последующих запросов, вам также необходимо вывести индикатор для состояния otherConstraintColumn<30, чтобы он использовался для удовлетворения результата. И в дальнейшем уменьшить количество строк, которые должны быть переданы клиенту (или материализованные в качестве временной таблицы) на сервере:

Было бы более эффективным, чтобы получить этот набор результатов:

SELECT t.Value 
    , MAX(CASE WHEN t.otherConstraintColumn < 30 THEN 1 ELSE 0 END) AS occlt30 
    FROM ValueTable t 
WHERE t.SomeConstraint > 4 
GROUP BY t.Value 

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

Смежные вопросы