Репликация позволяет создать копию базы данных у географически удаленном пункте, например в другом центре обработки данных.
С помощью репликации можно распределить запросы на чтение между несколькими серверами. В приложениях с интенсивным чтением эта тактика работает очень хорошо.
Реализовать несложное балансирование нагрузки можно, внеся совсем немного изменений в код.
Репликация ― это ценное подспорье для резервного копирования. Однако подчиненный сервер все же не может использоваться в качестве резервной копии и не является заменой настоящему резервному копированию.
Репликация позволяет исправить ситуацию, при которой сервер является единственной точкой отказа приложения. Хорошая система аварийного переключения при отказе, имеющая в составе реплицированные подчиненные серверы, способна существенно сократить время простоя.
Очень часто на подчиненный сервер устанавливают новую версию СУБД и перед тем как ставить ее на промышленные серверы, проверяют, что все запросы работают нормально.
Все изменения данных могут передаваться для анализа в стороннее приложение непосредственно после фиксации в базе.
Slony использует триггеры PostgreSQL для привязки к событиям INSERT/DELETE/UPDATE и хранимые процедуры для выполнения действий.
В MySQL используется только логическая репликация.
В MySQL различные хранилища объектов реализованы в виде подключаемых модулей.
Это порождает конфликт интересов:
Данная особенность архитектуры MySQL проходит красной нитью через весь функционал.
В MySQL хранилище и лог транзакций существуют за пределами "движка" СУБД.
Как следствие, в MySQL вместо журнала транзакций для репликации используется отдельный журнал.
Сохраняются непосредственно запросы, которые информаци об изменениях записей.
Сохраняется информаци об изменениях записей.
В случае DDL-выражений сохраняются сами запросы.
Промежуточный формат, который старается использовать statement, когда возможно, а когда нет — row.
ALTER TABLE foo
ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY (id);
Кластер представляется как одна система (Single-System Image, SSI), то есть эквивалент операционной системы для кластера в целом.
В результате нет необходимости в модификации существующих приложений — все это осуществляется автоматически, прозрачно для приложений пообно SMP.
Узлы кластера используют единую файловую систему.
Операционная система берет на себя координацию работы с файловой системой и ряд сервисных функций.
Приложение должно явно поддерживать работу в кластере.
Функции кластера целиком реализуются внутри приложения.
Postgres-XL позволяет объединить несколько кластеров PostgreSQL таким образом, чтоб они работали как один инстанс БД.
Для клиента, который подключается в базе, нет никакой разницы, работает он с единственным инстансом PostgreSQL или с кластером Postgres-XL. Postgres-XL предлагает 2 режима распределения таблиц по кластеру: репликация и шардинг.
При репликации все узлы содержат одинаковую копию таблицы, а при шардинге данные равномерно распределяются среди членов кластера.
Pgpool II позволяет балансировать нагрузку на чтение между частями кластера.
Для клиента, который подключается в базе, нет никакой разницы, работает он с единственным инстансом PostgreSQL или с кластером Pgpool II.
Есть поддержка Failover.
Запрос: мыла раму
Текст: Мама мыла раму
Запрос: мыть раму
Текст: Мама мыла раму
Запрос: мягкая булка
Текст: Съешь ещё этих мягких французских булок и выпей чаю
Глагол, несовершенный вид, переходный, тип спряжения по классификации А. Зализняка — 2b.
Число | Лицо | Глагол |
---|---|---|
ед. | 1-е я (что делаю) | Крую |
2-е ты (что делаешь) | Круёшь | |
3-е он, она (что делает) | Круёт | |
мн. | 1-е мы (что делаем) | Круём |
2-е вы (что делаете) | Круёте | |
3-е они (что делают) | Круют |
Создавая словари, можно:
В PostgreSQL по-умолчанию нет словарей для Русского языка, но можно воспользоваться словарями из пакета myspell-ru:
# Устанавливаем словари
sudo apt install myspell-ru
cd /usr/share/postgresql/9.5/tsearch_data
DICT=/usr/share/hunspell/ru_RU
# Копируем словари с преобразованием в UTF-8
sudo iconv -f koi8-r -t utf-8 -o russian.affix $DICT.aff
sudo iconv -f koi8-r -t utf-8 -o russian.dict $DICT.dic
CREATE TEXT SEARCH DICTIONARY russian_ispell ( TEMPLATE = ispell, DictFile = russian, AffFile = russian, StopWords = russian );
CREATE TEXT SEARCH CONFIGURATION ru (COPY=russian);
ALTER TEXT SEARCH CONFIGURATION ru ALTER MAPPING FOR hword, hword_part, word WITH russian_ispell, russian_stem;
SELECT to_tsvector('russian', 'мама мыла раму'); to_tsvector ------------------------- 'мам':1 'мыл':2 'рам':3 (1 строка)
SELECT to_tsvector('ru', 'мама мыла раму'); to_tsvector ------------------------------------- 'мама':1 'мыло':2 'мыть':2 'рама':3 (1 строка)
SELECT to_tsvector('Съешь ещё этих мягких французских'); to_tsvector ------------------------------------------------ 'ещё':2 'мягк':4 'съеш':1 'французск':5 'эт':3 (1 строка)
SET default_text_search_config = 'ru';
SELECT to_tsvector('Съешь ещё этих мягких французских'); to_tsvector ------------------------------------------------------- 'ещё':2 'мягкий':4 'съешь':1 'французский':5 'этих':3 (1 строка)
SELECT plainto_tsquery('мягкая булка') @@ to_tsvector( 'Съешь ещё этих мягких французских булок и выпей чаю'); ?column? ---------- t (1 строка)
SELECT ts_headline('мама мыла милу', to_tsquery('мама')); ts_headline ----------------------- <b>мама</b> мыла милу (1 строка)
SELECT ts_rank(to_tsvector( 'Съешь ещё этих мягких французских булок и выпей чаю' ), to_tsquery('мягкая & булка')); ts_rank ----------- 0.0985009 (1 строка)
SELECT '(to_tsvector('мама'), 'A') || setweight(to_tsvector('мыла'), 'B') || setweight(to_tsvector('раму'), 'D') @@ to_tsquery('мама:AB'); ?column? ---------- t (1 строка)
SELECT setweight(to_tsvector('мама'), 'A') || setweight(to_tsvector('мыла'), 'B') || setweight(to_tsvector('раму'), 'D') @@ to_tsquery('мама:BC'); ?column? ---------- f (1 строка)
CREATE TABLE documents ( id SERIAL PRIMARY KEY, title TEXT, body TEXT, fts TSVECTOR );
CREATE INDEX documents_fts USING GIN ON documents (fts);
INSERT INTO documents (title, body) VALUES ('Хокку', E'Голос модема!\nКак он напоминает\nПенье цикады.');
UPDATE documents SET fts = setweight(to_tsvector(title), 'A') || setweight(to_tsvector(body), 'B');
SELECT * FROM documents WHERE fts @@ to_tsquery('модем');
apt install postgis postgresql-9.5-postgis-scripts
service postgresql restart
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
SELECT ST_Distance(
ST_GeomFromText('POINT(37.6726 55.7448)'), -- Moscow
ST_GeomFromText('POINT(30.3715 59.9401)')); -- St Petersburg
st_distance
------------------
8.42060587487623
(1 строка)
SELECT ST_Distance(
ST_GeogFromText('SRID=4326;POINT(37.6726 55.7448)'),
ST_GeogFromText('SRID=4326;POINT(30.3715 59.9401)'));
st_distance
-----------------
636751.38845948
(1 строка)
SELECT ST_Distance(
ST_GeogFromText('SRID=4326;POINT(37.6726 55.7448)'),
ST_GeogFromText('SRID=4326;POINT(30.3715 59.9401)'));
st_distance
-----------------
636751.38845948
(1 строка)
SELECT * FROM spatial_ref_sys;
EXPLAIN SELECT * FROM bookings.airports WHERE ST_DWithin(
Geography(ST_SetSRID(ST_POINT(longitude, latitude), 4326)),
ST_GeogFromText('SRID=4326;POINT(37.6726 55.7448)'),
100 * 1000);
Seq Scan on airports (cost=0.00..46.90 rows=1 width=101)
Filter: ((geography(st_setsrid(…)) && '0101…4B40'::geography)
AND ('0101…4B40'::geography && _st_expand(geography(st_setsrid(…)), 100000))
AND _st_dwithin(geography(st_setsrid(…)), '0101…4B40'::geography, 100000, true))
CREATE INDEX idx_airports ON bookings.airports USING GIST
(Geography(ST_SetSRID(ST_POINT(longitude, latitude), 4326)));
EXPLAIN SELECT * FROM bookings.airports WHERE ST_DWithin(
Geography(ST_SetSRID(ST_POINT(longitude, latitude), 4326)),
ST_GeogFromText('SRID=4326;POINT(37.6726 55.7448)'),
100 * 1000);
Bitmap Heap Scan on airports (cost=4.30..16.96 rows=1 width=101)
Recheck Cond: (geography(…) && '0101…4B40'::geography)
Filter: (('0101…4B40'::geography && _st_expand(geography(…)), 100000))
AND _st_dwithin(geography(st_setsrid(…), '0101…4B40'::geography, 100000, true))
-> Bitmap Index Scan on idx_airports (cost=0.00..4.29 rows=21 width=0)
Index Cond: (geography(st_setsrid(…)) && '0101…4B40'::geography)
Поиграться можно с базой: https://edu.postgrespro.ru/bookings.pdf
CREATE TABLE movies_json (
id INT PRIMARY KEY,
data JSONB
);
INSERT INTO movies_json (id, data)
SELECT m.id, json_build_object(
'title', title,
'year', year,
'genres', (
SELECT array_to_json(array_agg(name))
FROM movie_genres mg JOIN genres g ON (mg.genre_id = g.id)
WHERE mg.movie_id = m.id
),
'tags', (
SELECT array_to_json(COALESCE(array_agg(distinct name), array[]::text[]))
FROM movie_tags mt JOIN tags t ON (mt.tag_id = t.id)
WHERE mt.movie_id = m.id
)
)
FROM movies m;
SELECT data FROM movies_json
WHERE data->>'title' = 'Zombieland';
{
"tags": [
"Abigail Breslin",
"atlanta",
"awkward romance",
"banjo",
"Bill Murray",
"Woody Harrelson",
"zombies"
],
"year": 2009,
"title": "Zombieland",
"genres": [
"Horror",
"Action",
"Comedy"
]
}
SELECT data->>'title', data->>'year', data->'genres' FROM movies_json WHERE data @> '{"title": "Zombieland"}';
CREATE INDEX idx_movies_json ON movies_json USING GIN (data jsonb_path_ops);
SELECT data->>'title', data->>'year', data->'genres' FROM movies_json WHERE data ->> 'title' = 'Zombieland';
CREATE INDEX idx_movies_json_title ON movies_json ((data ->> 'title') text_pattern_ops);
SELECT data ->> 'title' FROM movies_json WHERE data @> '{"genres": ["Comedy"], "tags": ["zombie"]}';
SELECT data ->> 'title' FROM movies_json j WHERE data @> '{"genres": ["Comedy"]}' AND EXISTS ( SELECT value FROM jsonb_array_elements_text(j.data -> 'tags') WHERE value LIKE 'zombie%' );