Есть ли что-то быстрее, чем "рассчитывать" для больших таблиц? - PullRequest
3 голосов
/ 04 мая 2009

Вот мой запрос:

select word_id, count(sentence_id) 
from sentence_word 
group by word_id 
having count(sentence_id) > 100;

Слово предложения таблицы содержит 3 поля: слово, идентификатор предложения и идентификатор первичного ключа. Он имеет 350 тыс. Строк. Этот запрос занимает колоссальные 85 секунд, и мне интересно (надеюсь, молиться?), Есть более быстрый способ найти все словаидные слова, содержащие более 100 предложений.

Я пытался убрать часть счетчика select и просто выполнял 'count (1)', но ни один не ускоряет его.

Буду признателен за любую помощь, которую вы можете оказать. Спасибо!

Ответы [ 5 ]

6 голосов
/ 04 мая 2009

Если у вас его еще нет, создайте составной указатель по фразе: слово_ид.

3 голосов
/ 04 мая 2009

с количеством (предложений)> 100;

Есть проблема с этим ... Либо в таблице есть повторяющиеся пары слово / предложение, либо нет.

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

HAVING COUNT(DISTINCT Sentence_ID) > 100

Если в таблице нет повторяющихся пар слово / предложение ... тогда вы не должны считать предложение, просто нужно считать строки.

HAVING COUNT(*) > 100

В этом случае вы можете создать индекс только для word_id для оптимальной производительности.

1 голос
/ 04 мая 2009

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

У меня нет своих ресурсов (или доступа к SQL), но я постараюсь помочь вам из памяти.

Концептуально, единственный способ ответить на этот запрос - подсчитать все записи с одинаковым идентификатором word_id. Это означает, что движку запросов необходим быстрый способ найти эти записи. Без индекса для word_id единственная вещь, которую может сделать база данных, - это просматривать таблицу по одной записи за раз и продолжать получать итоговые значения для каждого отдельного отдельного слова word_id, которое она находит. Обычно для этого требуется временная таблица, и результаты не могут быть отправлены до тех пор, пока вся таблица не будет отсканирована. Не хорошо.

С индексом word_id он все еще должен проходить таблицу, поэтому вы бы подумали, это не сильно поможет. Однако механизм SQL теперь может вычислять счетчик для каждого word_id, не дожидаясь конца таблицы: он может отправить строку и счетчик для этого значения word_id (если оно проходит предложение where), или отбросить строку (если это не так); это приведет к снижению нагрузки на сервер, возможно, к частичным ответам, и временная таблица больше не нужна. Второй аспект - параллелизм; с индексом word_id SQL может разделить задание на куски и использовать отдельные ядра процессора для параллельного выполнения запроса (в зависимости от возможностей оборудования и существующей рабочей нагрузки).

Этого может быть достаточно, чтобы помочь вашему запросу; но вы должны попытаться увидеть:

CREATE INDEX someindexname ON sentence_word (word_id)

(синтаксис T-SQL; вы не указали, какой продукт SQL вы используете)

Если этого недостаточно (или не помогает вообще), есть два других решения.

Во-первых, SQL позволяет вам предварительно вычислить COUNT (*), используя индексированные представления и другие механизмы. У меня нет деталей под рукой (и я делаю это не часто). Если ваши данные меняются не часто, это даст вам более быстрые результаты, но с затратами на сложность и небольшим объемом хранилища.

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

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

1 голос
/ 04 мая 2009

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

0 голосов
/ 05 октября 2010

На удивление, есть еще более быстрый способ сделать это на больших наборах данных:

SELECT totals.word_id, totals.num 
  FROM (SELECT word_id, COUNT(*) AS num FROM sentence_word GROUP BY word_id) AS totals
 WHERE num > 1000;
...