Как лучше всего проиндексировать эту таблицу? - PullRequest
0 голосов
/ 09 мая 2020

У меня есть большая таблица в PostgreSQL (> 2000 M строк), которую нужно запросить как можно быстрее. Он представляет собой измерения экспрессии генов в биологических образцах. Дело в том, что иногда измерение производится непосредственно на гене («зонд» тогда NULL), а иногда измерение выполняется с помощью «зондов» для гена («ген» тогда все еще устанавливается). Один ген может иметь несколько зондов. Нет другой таблицы, содержащей взаимосвязь между геном и зондом.

CREATE TABLE "gene_measurements" (
  "gene" INTEGER NOT NULL REFERENCES "genes" ON DELETE CASCADE,
  "sample" INTEGER NOT NULL REFERENCES "samples" ON DELETE CASCADE,
  "probe" INTEGER REFERENCES "probes" ON DELETE CASCADE,
  "value" REAL NOT NULL
);

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

В настоящее время у меня есть следующие индексы покрытия. Он работает нормально, но занимает очень много места.

CREATE INDEX "gene_measurements_gene_sample_value_index" ON "gene_measurements" ("gene", "sample", "value");
CREATE INDEX "gene_measurements_sample_gene_value_index" ON "gene_measurements" ("sample", "gene", "value");
CREATE INDEX "gene_measurements_sample_probe_value_index" ON "gene_measurements" ("sample", "probe", "value");
CREATE INDEX "gene_measurements_probe_sample_value_index" ON "gene_measurements" ("probe", "sample", "value");

Есть ли что-то умное, что я могу сделать, чтобы получить более аккуратную и / или меньшую реализацию при сохранении скорости? Спасибо!

Ответы [ 2 ]

0 голосов
/ 09 мая 2020

Таблица SQL действительно требует первичного ключа. Теоретически таблица без ключа бессмысленна. (на практике таблица с 3G-строками без PK является катастрофой)

В вашем случае естественный ключ выглядит как комбинация столбцов (gene_id,sample_id,probe_id). Значения для этих трех столбцов необходимы, чтобы однозначно адресовал value.

Проблема заключается в вашем if probe is absent; measurement was directly on the gene антиограничении. Это запретит ключ из трех столбцов. Удаление этого исключения позволит использовать первичный ключ с несколькими столбцами. Теперь трюк с данными состоит в том, чтобы вставить одну фиктивную строку в зонд, например, с id = 0.

INSERT INTO probe(probe_id, probe_when, probe_name)
 VALUES( 0, '1901-01-01 00:00:00', 'Dummy probe');

А теперь ОБНОВЛЯЙТЕ gene_measurements, меняя probe IS NULL на probe=0.


CREATE TABLE gene_measurements (
  gene INTEGER NOT NULL REFERENCES genes(gene_id) ON DELETE CASCADE
  , sample INTEGER NOT NULL REFERENCES samples(sample_id) ON DELETE CASCADE
  , probe INTEGER NOT NULL REFERENCES probes (probe_id)
  , value REAL NOT NULL
        , PRIMARY KEY ( gene_id, sample_id,probe_id)
);

Возможно, добавьте еще несколько индексов с другим порядком, чтобы помочь определить c запросы, например:

CREATE UNIQUE INDEX ON gene_measurements (sample_id,gene_id,probe_id);

И вам понадобится вспомогательный индекс для зонда FK, подойдет любой индекс с зондом в качестве первого столбца:

CREATE INDEX ON gene_measurements (probe_id, ...);
0 голосов
/ 09 мая 2020

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

Вы можете избавиться от некоторых данных из индексов в обмен на более быстрое выполнение:

  • Например, вы можете удалить value из всех индексы. Но тогда поиск данных становится необходимым в дополнение к поиску в индексе.
  • Вы также можете полностью удалить некоторые индексы. Например, в зависимости от ваших данных вы можете удалить (sample, gene) или (sample, probe). Это удаляет одно полное покрытие данных, но при этом позволяет использовать часть sample для запросов с условиями на sample и удаленном столбце. Опять же, случай, который вы удалили, работает не так быстро, как раньше.

Если ваша цель - достичь минимального времени выполнения любой ценой , то все эти предложения не для вас. Я не думаю, что сейчас во вселенной PostgreSQL есть что-то, что могло бы решить вашу проблему.

Поскольку ваши данные просты, а ваши варианты использования ограничены, вы можете рассмотреть решения, отличные от PostgreSQL. В частности, вам нужна только структура данных B-Tree. (Или несколько.) Есть другие решения для построения такой структуры данных, например, QDBM . Тем не менее, вам нужно будет построить несколько таких структур для оптимизации для каждого из выбранных вами типов. Достижимая экономия места, которую я считаю не очень высокой - в принципе, вы можете избавиться от данных, но не от индексов. Таким образом, вы можете сэкономить примерно 1/5 вашего текущего размера хранилища за счет ограниченной функциональности и дополнительной сложности вашей программной экосистемы.

Вы должны решить, что вам нужно, что вы хотите и что вы хотите жертвовать ради этих целей. Учитывая то, что я здесь написал, я бы остановился на PostgreSQL.

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