Если у вас нет миллионов слов, хранение только их префикса кажется плохим планом.
Для добавления новых данных в таблицу вы можете просто написать временную таблицу, полную входящих слов, а затем просто объединить и объединить их за один раз в конце цикла импорта. То есть что-то вроде:
BEGIN;
CREATE TEMP TABLE word_stage(word text) ON COMMIT DROP;
COPY word_stage FROM stdin;
-- use pgputcopydata to send all the words to the db...
SET work_mem = 256MB; -- use lots of memory for this aggregate..
CREATE TEMP TABLE word_count_stage AS
SELECT word, count(*) as occurrences
FROM word_stage
GROUP BY word;
-- word should be unique, check that and maybe use this index for merging
ALTER TABLE word_count_stage ADD PRIMARY KEY(word);
-- this UPDATE/INSERT pair is not comodification-safe
LOCK TABLE word_count IN SHARE ROW EXCLUSIVE MODE;
-- now update the existing words in the main table
UPDATE word_count
SET word_count.occurrences = word_count.occurrences + word_count_stage.occurrences,
word_count.min_occurrences = least(word_count.occurrences, word_count_stage.occurrences),
word_count.max_occurrences = greatest(word_count.occurrences, word_count_stage.occurrences)
FROM word_count_stage
WHERE word_count_stage.word = word_count.word;
-- and add the new words, if any
INSERT INTO word_count(word, occurrences, min_occurrences, max_occurrences)
SELECT word, occurrences, occurrences, occurrences
FROM word_count_stage
WHERE NOT EXISTS (SELECT 1 FROM word_count WHERE word_count.word = word_count_stage.word);
END;
Таким образом, это агрегирует пакетное количество слов, а затем применяет их к таблице подсчета слов. Наличие индексов для word_stage(word)
и word_count(word)
открывает такие возможности, как использование слияния, если обе таблицы большие, что вы не могли бы легко сделать, пытаясь обновлять каждую строку в основной таблице по одной. Не говоря уже о снижении количества мусора, потенциально генерируемого в word_count
. (Хотя указание низкого коэффициента заполнения, например 60 или около того, word_count
было бы хорошей идеей, поскольку вы знаете, что он все еще будет несколько избит для обновлений).
Если вы на самом деле вводите пары слово / вхождение, а не просто слова (ваш текст не очень четкий), тогда вы можете извлечь исходную таблицу word_stage
и просто скопировать в word_count_stage
, или, возможно, вам понадобится начальная таблицу и хотите скопировать значения DISTINCT из этой исходной таблицы в word_count_stage
.
Серьезно, я бы попробовал использовать все слово в качестве ключа хотя бы на начальном этапе - числа, которые вы цитируете, находятся в пределах юзабилити. Также обратите внимание, что описанный выше подход к загрузке может быть легко изменен, чтобы довольно просто усечь слово до первых двух символов (или преобразовать его в ключ памяти любым произвольным образом), либо путем преобразования по мере перемещения данных в word_count_stage
или даже в самом конце, поместив преобразование в операторы обновления / вставки (хотя вы потенциально потеряете преимущество, если таким способом будет иметь индекс для временной таблицы).