Сортировка SQL, разбиение по страницам, фильтрация лучших практик в ASP.NET - PullRequest
4 голосов
/ 13 сентября 2010

Мне интересно, как Google это делает.У меня много медленных запросов, когда дело доходит до количества страниц и общего количества результатов.Google возвращает значение счетчика 250 000,00 за доли секунды.

Я имею дело с видами сетки.Я построил пользовательский пейджер для gridview, который требует SQL-запроса для возврата количества страниц на основе фильтров, установленных пользователем.Фильтров не менее 5, которые включают ключевое слово, категорию и подкатегорию, фильтр диапазона дат и фильтр выражения сортировки для сортировки.Запрос содержит около 10 массивных таблиц, оставленных объединениями.

Этот запрос выполняется каждый раз, когда выполняется поиск, а выполнение запроса длится в среднем 30 секунд - будь то счет или выбор.Я полагаю, что это замедляет мою строку запросов включающих и исключающих фильтров диапазона дат.Я заменил (<=,> =) на МЕЖДУ и AND, но все еще испытываю ту же проблему.

См. Запрос здесь: http://friendpaste.com/4G2uZexRfhd3sSVROqjZEc

У меня проблемы с длинным диапазоном датпараметр.

Проверьте мою таблицу, содержащую даты: http://friendpaste.com/1HrC0L62hFR4DghE6ypIRp

ОБНОВЛЕНИЕ [17.09.2010] Я свернул запрос даты и удалил время.Я попытался уменьшить количество соединений для моего запроса на подсчет (на самом деле у меня проблема с счетчиком фильтров, который занимает много времени, чтобы вернуть результат из 60 тыс. Строк).

      SELECT COUNT(DISTINCT esched.course_id)
        FROM courses c
           LEFT JOIN events_schedule esched
              ON c.course_id = esched.course_id
           LEFT JOIN course_categories cc
              ON cc.course_id = c.course_id
           LEFT JOIN categories cat
              ON cat.category_id = cc.category_id
     WHERE     1 = 1
           AND c.course_type = 1
           AND active = 1
           AND c.country_id = 52
           AND c.course_title LIKE '%cook%'
           AND cat.main_category_id = 40
           AND cat.category_id = 360
 AND (

    (2010-09-01' <= esched.date_start OR 2010-09-01' <= esched.date_end) 
    AND

    ('2010-09-25' >= esched.date_start OR '2010-09-25' >= esched.date_end)     
   )

Я только что заметил, что мой запрос выполняется довольно быстро, когда у меня есть фильтр в полях основной или подкатегории.Однако, когда у меня есть только фильтр даты, а диапазон - месяц или неделя, необходимо подсчитать много строк и сделать это в среднем за 30 секунд.

Это статические поля:

AND c.course_type = 1
AND active = 1
AND c.country_id = 52

ОБНОВЛЕНИЕ [17.09.2010] Если создать хеш для этих трех полей и сохранить его на одном поле, будет ли изменяться скорость?

Это моидинамические поля:

AND c.course_title LIKE '%cook%'
AND cat.main_category_id = 40
AND cat.category_id = 360
// ?DateStart and ?DateEnd

ОБНОВЛЕНИЕ [17.09.2010].Теперь моя проблема - лидирующий% в LIKE-запросе

Будет опубликовано обновленное объяснение

Ответы [ 2 ]

3 голосов
/ 13 сентября 2010

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

Рассмотрим следующие поиски в Google:

custom : 542 million google hits
pager : 10.8 m
custom pager 1.26 m

По сути, они создали запись для слова custom, и в этой записи они поместили 1 для каждой страницы, которая ее содержит, и0 для каждой страницы, которая не содержит его.Затем они застегивают его, потому что их намного больше, чем единиц.Они делают то же самое для пейджера.

Когда приходит поиск custom pager, они распаковывают обе записи, выполняют битовую операцию И над ними, и это приводит к массиву битов, где длина - это общее количество страниц, которыеони проиндексированы, а число 1 представляет количество совпадений для поиска.Позиция каждого бита соответствует конкретному результату, который известен заранее, и им нужно только просмотреть все подробности первых 10, чтобы отобразить на первой странице.

Это слишком упрощено, но этоосновной принцип.

О, да, у них также есть огромные банки серверов, выполняющих индексацию, и огромные банки серверов, отвечающих на поисковые запросы.ОГРОМНЫЕ банки серверов!

Это делает их намного быстрее, чем все, что можно сделать в реляционной базе данных.

Теперь к вашему вопросу: не могли бы вы вставить образец SQL, чтобы мы посмотрелиat?

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

Пример из реального мира.Скажем, вы хотели найти все записи в телефонной книге под именем «Джонсон», с номером, начинающимся с «7».Один из способов - найти все числа, начинающиеся с 7, а затем соединить их с числами, принадлежащими людям по имени Джонсон.На самом деле фильтрацию можно было бы выполнить намного быстрее, даже если у вас была индексация как по именам, так и по номерам.Это связано с тем, что имя «Джонсон» является более ограничительным, чем число 7.

Таким образом, порядок имеет значение, и программное обеспечение базы данных не всегда хорошо определяет заранее, какие объединения выполняются первыми.Я не уверен насчет MySQL, так как мой опыт в основном связан с SQL Server, который использует статистику индекса для расчета порядка выполнения соединений.Эти статистические данные устаревают после ряда вставок, обновлений и удалений, поэтому их необходимо периодически пересчитывать.Если в MySQL есть что-то похожее, вы можете попробовать это.

ОБНОВЛЕНИЕ Я посмотрел на ваш запрос, который вы разместили.Десять левых объединений не являются чем-то необычным и должны работать хорошо, если у вас есть нужные индексы.Ваш не сложный запрос.

Что вам нужно сделать, это разбить этот запрос до его основ.Закомментируйте соединения поиска, например, для валюты, course_stats, стран, штатов и городов вместе с соответствующими полями в операторе select.Это все еще работает так медленно?Возможно нет.Но это, вероятно, все еще не идеально.

Так что комментируйте все остальное, пока у вас не будут только курсы и группа по идентификатору курса и порядок по Courseid.Затем поэкспериментируйте с добавлением левых объединений, чтобы увидеть, какое из них оказывает наибольшее влияние.Затем, сосредоточив внимание на тех из них, которые оказывают наибольшее влияние на производительность, измените порядок запросов.Это метод проб и ошибок.Было бы намного лучше взглянуть на индексы столбцов, к которым вы присоединяетесь.

Например, для строки cm.method_id = c.method_id потребуется первичный ключ для course_methodologies.method_id и индекс внешнего ключа для courses.method_id и так далее. Кроме того, все поля в предложениях where, group by и order by нуждаются в индексах.

Удачи

ОБНОВЛЕНИЕ 2 Вы серьезно должны посмотреть на фильтрацию даты по этому запросу. Что ты пытаешься сделать?

   AND ((('2010-09-01 00:00:00' <= esched.date_start
          AND esched.date_start <= '2010-09-25 00:00:00')
         OR ('2010-09-01 00:00:00' <= esched.date_end
             AND esched.date_end <= '2010-09-25 00:00:00'))
        OR ((esched.date_start <= '2010-09-01 00:00:00'
             AND '2010-09-01 00:00:00' <= esched.date_end)
            OR (esched.date_start <= '2010-09-25 00:00:00'
                AND '2010-09-25 00:00:00' <= esched.date_end)))

Может быть переписано как:

AND (

    //date_start is between range - fine
    (esched.date_start BETWEEN '2010-09-01 00:00:00' AND '2010-09-25 00:00:00') 

    //date_end is between range - fine
    OR (esched.date_end BETWEEN '2010-09-01 00:00:00' AND '2010-09-25 00:00:00')       

    OR (esched.date_start <= '2010-09-01 00:00:00' AND esched.date_end >= '2010-09-01 00:00:00' ) 

    OR (esched.date_start <= '2010-09-25 00:00:00' AND esched.date_end > = '2010-09-25 00:00:00')
  )
2 голосов
/ 14 сентября 2010

в вашем обновлении вы упоминаете, что вы подозреваете, что проблема в фильтрах даты.

Все эти проверки даты могут быть суммированы в одной проверке:

esched.date_ends >= '2010-09-01 00:00:00' and esched.date_start <= '2010-09-25 00:00:00'

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

SELECT COUNT (DISTINCT esched.course_id) FROM events_schedule esched WHERE esched.date_ends> = '2010-09-01 00:00:00' и esched.date_start <= '2010-09-25 00:00:00 '</p>

ps Я думаю , что при использовании объединения можно выполнить команду SELECT COUNT ( c.course_id ) для непосредственного подсчета основных записей курсов в запросе, т.е.в этом случае может не потребоваться отчетливый.


обновлять сейчас чаще всего после перехода на поиск по шаблону:

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

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

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

...