MySQL移行者向けのPostgreSQL機胜

先週の急なvaranioは 、MySQLを䜿甚しおPosgresに移行したが、ただ新しいデヌタベヌスを完党には䜿甚しおいないすべおの人のためのDevConfのボトムホヌルレポヌトを読みたした。 スピヌチに基づいお、この出版物が誕生したした。


PG Day'17 Russiaの準備が本栌化したこずをお知らせいたしたす。 今埌のむベントの完党なスケゞュヌルを公開したした。 アントンず䞀緒に個人的にリラックスしおください



DevConfのレポヌトは䞀般に奜意的なレビュヌを匕き起こしたため、䜕らかの理由で䌚議に参加できなかった人向けの蚘事ずしお発行するこずにしたした。


なぜこのようなレポヌトのアむデアを思い぀いたのですか 事実、PostgreSQLは明らかに誇倧広告テクノロゞヌであり、倚くがこのDBMSに切り替えおいたす。 時には-客芳的な理由で、時には-単にそれが流行しおいるからです。


しかし、条件付きプログラマヌの䞀郚のVasyaが昚日MySQLで曞いた今日、圌はPosgresで突然曞き始めたした。 圌はどう曞く はい、䞀般に、以前ず同様に、新しいベヌスの最小限の機胜セットのみを䜿甚したす。 実践では、DBMSがほが完党に䜿甚され始めるたでに幎が経過するこずが瀺されおいたす。


ホリバヌではない


すぐに免責事項これは筋肉察進行に぀いおの蚘事ではありたせん。 オンたたはオフに行くこずはあなたのビゞネスです。 たずえば、Uberは䜕らかの理由でMySQLに切り替えたした。


Oracleは称賛されなければなりたせん。圌らは明らかにMySQLを正しい方向に動かしおいたす。 5.7では、デフォルトで厳栌モヌドが䜜成されたした。 8番目のバヌゞョンでは、CTEずりィンドり関数を玄束し、システムテヌブルのMyISAM゚ンゞンを削陀したす。 ぀たり デヌタベヌスにリ゜ヌスが投資されおいるこずは明らかであり、りィッシュリストのナヌザヌは非垞に真剣に研究されおいたす。


ただし、PostgreSQLにはただ独自の機胜がたくさんありたす。 その結果、私は開発者のためにベヌスの機胜の簡単な抂芁を䜜成しようずしたした。


組み蟌みデヌタ型


通垞の数倀ず文字列に加えお、倚くのタむプのデヌタがデヌタベヌスに組み蟌たれおいたす。 同様に圌らの盞互䜜甚のための挔算子。


たずえば、ipアドレスを操䜜するためのcidr、inet、macaddrタむプがありたす。


-- ,   ip  '128.0.0.1'  cidr '127.0.0.0/24' --    && select '127.0.0.0/24'::cidr && '128.0.0.1'; --  false 

たたは、たずえば、タむムゟヌンタむムスタンプ、時間間隔などの時間


 --     -? SELECT NOW() AT TIME ZONE 'America/New_York'; --        -? SELECT NOW() AT TIME ZONE 'America/New_York' - NOW() AT TIME ZONE 'Europe/Moscow'; -- : -07:00:00 

このスラむドを準備しおいたずき、私は奜奇心から100幎前の1917幎にUTCず比范した時間のオフセットを確認しようず決めたした。


 select '1917-06-17 00:00:00 UTC' at time zone 'Europe/Moscow'; -- : 1917-06-17 02:31:19 

぀たり 癜雲母はUTC + 023119に䜏んでいた


䞊蚘に加えお、UUID、JSONB、XML、ビット文字列など、他の組み蟌みデヌタ型がありたす。


型配列


それずは別に、「配列」のタむプを考慮しおください。 配列は長く、PostgreSQLにうたく統合されおいたす。 倚次元配列、スラむス、亀差挔算子、結合など 配列を操䜜するための倚くの関数がありたす。


 ---     SELECT ARRAY [1, 2, 8, 10] && ARRAY [1, 2, 3, 4, 5]; ---      ? SELECT ARRAY [1, 2] <@ ARRAY [1, 2, 3, 4, 5] 

配列ず呌ばれる非垞に䟿利な関数がありたす。 匕数ずしお、出力でSELECTリク゚ストが提䟛されたす-リク゚ストはリク゚ストの結果を配列の圢で提䟛したす。


逆関数がありたすネスト解陀。 圌女は配列を受け取り、リク゚ストの結果ずしおそれを返したす。 これは、たずえば、異なるIDを持぀耇数の同䞀のレコヌドを手動で挿入する必芁があるが、コピヌず貌り付けを行いたくない堎合に䟿利です。


 INSERT INTO users (id, status, added_at) SELECT user_id, 5, '2010-03-03 10:56:40' FROM unnest(array[123, 1232, 534, 233, 100500]) as u(user_id) 

独自のタむプを䜜成する


カスタムタむプは3぀の方法で䜜成できたす。 たず、C蚀語を知っおいる堎合は、intたたはvarcharずずもに基本型を䜜成できたす。 マニュアルの䟋


 CREATE TYPE box ( INTERNALLENGTH = 16, INPUT = my_box_in_function, OUTPUT = my_box_out_function ); 

぀たり cstringから型を䜜成できる関数ず、その逆の関数を䜜成したす。 次に、この型を、たずえばテヌブル宣蚀で䜿甚できたす。


 CREATE TABLE myboxes ( id integer, description box ); 

2番目の方法は耇合型です。 たずえば、耇玠数を保存するには


 CREATE TYPE complex AS ( r double precision, i double precision ); 

そしお、これを䜿甚したす


 CREATE TABLE math ( result complex ); INSERT INTO math (result) VALUES ((0.5, -0.6)::complex); SELECT (result).i FROM math; -- : -0.6 

䜜成できる3番目の皮類のタむプは、ドメむンタむプです。 ドメむンタむプは、異なる名前を持぀既存のタむプの単なる゚むリアスです。 ビゞネスロゞックに䞀臎する名前。


 CREATE DOMAIN us_postal_code AS TEXT; 

us_postal_codeは、いく぀かの抜象的なテキストやvarcharよりもセマンティックです。


独自のオペレヌタヌを䜜成する


独自の挔算子を実行できたす。 たずえば、耇玠数の远加䞊蚘の耇玠数型を定矩したした


 --   , ,   SQL CREATE OR REPLACE FUNCTION sum_complex(x COMPLEX, y COMPLEX) RETURNS COMPLEX AS $$ SELECT xr + yr, xi + yi; $$ language sql; --   ""    CREATE OPERATOR + ( PROCEDURE = sum_complex, LEFTARG = COMPLEX, RIGHTARG = COMPLEX ); 

型倉換のカスタムルヌルを䜜成する


真空の䟋で球状にしたしょう。 タむプRURずUSD、および1぀のタむプを別のタむプに倉換するルヌルを䜜成したす。 私はsiをよく知らないので、たずえば単玔な耇合型を䜜成したす。


 CREATE TYPE USD AS ( sum FLOAT ); CREATE TYPE RUR AS ( sum FLOAT ); --      (  60,    ) CREATE FUNCTION usd2rur(value USD) RETURNS RUR AS $$ SELECT value.sum * 60.0; $$ LANGUAGE SQL; --    ,    "". CREATE CAST ( USD AS RUR ) WITH FUNCTION usd2rur(USD) AS ASSIGNMENT; 

実際、これですべおです。䜿甚できるようになりたした。 ルヌブルには100ドルがいくらありたすか


 select '(100.0)'::usd::rur; 

結果は次のようになりたす。


 rur -------- (6000) (1 row) 

PostgreSQL拡匵機胜のタむプ


デヌタ型ずそれらに必芁なすべおが蚘述されおいる拡匵機胜がありたす。 たずえば、IPアドレスのタむプずその範囲を蚘述するip4r拡匵。


゜ヌスhttps://github.com/RhodiumToad/ip4r/blob/master/ip4r--2.2.sqlを芋るず、実際には、拡匵機胜はCREATE TYPE 、 CREATE OPERATOR 、 CREATE CAST䞀連の呜什であるこずがわかりたす。など


むンデックス付けルヌルに぀いお説明したす。 たずえば、 ip4rタむプIPアドレス範囲は、 &&挔算子およびその他のGISTむンデックスでむンデックス付けできたす。 したがっお、IPで郜垂を怜玢するためのテヌブルを䜜成できたす。


たたは、たずえば、 uri拡匵機胜がありたす。これにより、リンクを保存できるタむプになり、回線たたはホストを簡単に匕き出すこずができたすただ運甚環境で詊しおいないので、予定しおいたす。


指数


暙準のbtree加えお、 GIN jsonb、党文怜玢などの配列の䞀郚の操䜜に䜿甚可胜、 GIST 、 brinなどがありたす。


郚分むンデックス


テヌブルに1,000䞇行ある状況があり、そのうち100個だけがステヌタス「支払凊理䞭」などである堎合がありたす。 そしお、あなたは垞にこのような「凊理䞭」ステヌタスを匕き出したす select ... where status = 2 。


ここにむンデックスが必芁であるこずは明らかです。 しかし、このようなむンデックスは倚くのスペヌスを占有したすが、実際には非垞に小さな郚分が必芁です。


進行䞭、テヌブル党䜓ではなく、特定の条件で定矩された行に察しおむンデックスを䜜成できたす。


 CREATE INDEX my_money_status_idx on my_money(status) WHERE status = 2; 

このむンデックスはselect * from my_money where status = 2ク゚リであるず同時に、スペヌスをほずんど占有したせん。


匏むンデックス


進行䞭、むンデックスは1぀の列ではなく、任意の匏で䜜成できたす。 たずえば、姓ず名のむンデックスを䜜成できたす。


 CREATE INDEX people_names ON people ((first_name || ' ' || last_name)); 

そしお、そのようなク゚リはすぐに動䜜したす


 SELECT * FROM people WHERE (first_name || ' ' || last_name) = 'John Smith'; 

制玄


暙準のUNIQUEおよびNOT NULLに加えお、他の敎合性チェックもデヌタベヌスで実行できたす。 ドメむンタむプでは、チェックを曞くこずができたす


 CREATE DOMAIN us_postal_code AS TEXT CHECK( VALUE ~ '^\d{5}$' OR VALUE ~ '^\d{5}-\d{4}$' ); 

5桁たたは5桁、ハむフン、4桁のみがus_postal_codeのような列に分類されるこずを確認したす。 もちろん、ここではレギュラヌだけでなく、他の条件も䜜成できたす。


たた、衚にチェックを曞くこずができたす。


 CREATE TABLE users ( id integer, name text, email text, CHECK (length(name) >= 1 AND length(name) <= 300) ); 

぀たり 名前には少なくずも1文字、300文字以䞋が必芁です。


䞀般的に、型自䜓も特定の制限であり、デヌタベヌスが行う远加のチェックです。 たずえば、本質的に2぀の数倀で構成される耇合型䞊蚘を参照がある堎合、そこに誀っお文字列を挿入するこずはありたせん。


 INSERT INTO math (result) VALUES ((0.5, '')::complex); ERROR: invalid input syntax for type double precision: "" 

そのため、jsonでは䜕でも詰め蟌むこずができるため、jsonbよりも耇合型の方が望たしい堎合がありたす。


衚珟の郚分的な䞀意性ず䞀意性


UNIQUEキヌたたはPRIMARY KEYの単玔な䞀意性ずは異なり、条件で指定された特定の文字列セット間で進行を䞀意にするこずができたす。 たずえば、電子メヌルは非リモヌトナヌザヌ間で䞀意である必芁がありたす。


 CREATE UNIQUE INDEX users_unique_idx ON users(email) WHERE deleted = false; 

もう1぀の面癜いこずは、1぀のフィヌルドではなく、任意の衚珟によっお䞀意性を実珟できるこずです。 たずえば、テヌブル内で2぀の列の合蚈が繰り返されないようにするこずができたす。


 CREATE TABLE test_summ ( a INT, b INT ); CREATE UNIQUE INDEX test_summ_unique_idx ON test_summ ((a + b)); INSERT INTO test_summ VALUES (1, 2); INSERT INTO test_summ VALUES (3, 0); --    

制玄陀倖


EXCLUDEキヌワヌドを䜿甚するず、行を挿入たたは曎新するずきに、指定した挔算子によっおこの行が他の行ず比范されるようにできたす。 たずえば、互いに玠なIP範囲を含むテヌブル &&亀差挔算子によっおチェックされたす


 CREATE TABLE ip_ranges ( ip_range ip4r, EXCLUDE USING gist (ip_range WITH &&) ); 

䞀般に、通垞のUNIQUEは、 =挔算子を含むEXCLUDEです。


ストアドプロシヌゞャ


ストアドプロシヌゞャは、SQL、pl / pgsql、javascript、pl / v8、pythonなどで蚘述できたす。 たずえば、R蚀語でいく぀かの統蚈を蚈算し、その結果のグラフを返すこずができたす。
これは別の倧きなトピックです。このテヌマに関するIvan Panchenkoのレポヌトを探すこずをお勧めしたす。


CTE共通テヌブル匏


これはMySQL 8に含たれたすが、それでも簡単に説明したす。


CTEは簡単です。 リク゚ストの䞀郚を取り出しお、名前を付けお個別に取り出したす。


 WITH subquery1 AS ( SELECT ... --      . ), subquery2 AS ( SELECT ... --    ,  ) SELECT * --    FROM subquery1 JOIN subquery 2 ON ... 

ク゚リ最適化の芳点から、このような各CTEサブク゚リは個別に実行されるこずに留意する必芁がありたす。 これはプラスずマむナスの䞡方にするこずができたす。


たずえば、サブク゚リずグルヌプ化による20の結合がある堎合、ク゚リプランナヌは意図を理解できない可胜性があり、ク゚リプランは最適ではありたせん。 その埌、リク゚ストの䞀郚をcteサブク゚リに配眮し、残りをメむンリク゚ストでフィルタリングできたす。


逆に、読みやすくするためだけにCTEでリク゚ストの䞀郚を䜜成するこずにした堎合は、暪向きになるこずがありたす。


CTEでは、SELECTク゚リだけでなく、UPDATEも䜿甚できたす。


䟋幎霢が20歳以䞊のナヌザヌを曎新し、同じリク゚ストで、曎新されたナヌザヌの名前ずその囜を返したす。


 with users_updated AS ( UPDATE users SET status = 4 WHERE age > 20 RETURNING id ) SELECT name, country FROM users JOIN countries ON users.country_id = countries.id WHERE id IN ( SELECT id FROM users_updated ); 

しかし、ここでは、CTEの助けを借りお、時には自分の足でうたく撃぀こずができるこずを理解する必芁がありたす。
そのようなク゚リは構文的に正しいですが、意味は完党にナンセンスです


 WITH update1 AS ( UPDATE test SET money = money + 1 ), update2 AS ( UPDATE test SET money = money - 1 ) SELECT money FROM test; 

ルヌブルを远加しおからルヌブルを取り陀いたようで、すべおがそのたた残っおいるはずです。


しかし、実際には、update1ずupdate2を実行するず、テヌブルの初期バヌゞョン、぀たり 実際、1぀の曎新が他の曎新を䞊曞きするこずがわかりたした。 そのため、CTE内での曎新では、䜕をしおいお、なぜなのかを正確に知る必芁がありたす。


りィンドり関数


りィンドり関数に぀いおは、 https  //habrahabr.ru/post/268983/に詳现を曞きたした。 りィンドり関数はMySQL 8でも玄束されおいたす。


雑倚


フィルタヌ


関数COUNTやSUMなどを集玄するには、FILTER条件を远加できたす。 すべおの行を集玄するのではなく、特定の匏のみに制限したす。


 SELECT count(*) FILTER (WHERE age > 20) AS old, count(*) FILTER (WHERE age <= 20) AS young FROM users; 

぀たり 20歳以䞊の人ず20歳未満の人をカりントしたした。


\芋る


psqlには、さたざたなオブゞェクトを衚瀺するためのコマンド \d 、 \dt+などがあるこずは誰もが知っおいたす。
\watchず呌ばれる特別なコマンドがありたす。 ぀たり リク゚ストを実行しおから、曞き蟌みたす
\watch 5で、キャンセルされるたでリク゚ストは5秒ごずに実行されたす。
これはselectだけでなく、たずえばupdateのような他のすべおの堎合にも機胜したすたずえば、倧きなテヌブルを少しだけ曎新する必芁がある堎合。


マテリアラむズドビュヌ


これはビュヌのようなもので、キャッシュされた実䜓化されただけです。 キャッシュは、REFRESH MATERIALIZED VIEWコマンドを䜿甚しお曎新できたす。 曎新時にPostgresがSELECTク゚リを曎新しないようにするCONCURRENTLYキヌワヌドもありたす。


聞く/通知する


私はただ本番環境でこれを詊しおいないので、これが実際に適甚可胜かどうかはわかりたせん誰かが䜿甚した堎合、コメントで経隓を共有しおください。 䞀番䞋の行は、ある皮のむベントをサブスクラむブできるこずです。たた、extを䜿甚しお行を送信しながら、むベントが発生したこずをサブスクラむバヌに通知するこずもできたす。 情報。


Fdw


倖郚デヌタラッパヌメカニズムを䜿甚するず、単玔なテヌブルなどの倖郚デヌタを䜿甚できたす。 ぀たり たずえば、postgresテヌブル、muscleテヌブル、csvファむルを結合できたす。


シヌケンス


SEQUENCEは、MySQL AUTO_INCREMENTのポストゎヌストアナログです。 MySQLずは異なり、シヌケンスはテヌブルずは別個に、たたはその逆に、䞀床に耇数のテヌブルを「ティック」するこずができたす。 増分サむズ、ルヌプなど、さたざたなパラメヌタヌを蚭定できたす。


結論の代わりに


これは、実際には氷山の䞀角です。 すべおの蚘事が䞍足しおいるため、ただ蚘事には蚘茉されおいないニュアンスがたくさんありたす。 ストアドプロシヌゞャだけで本を曞くこずができたす。 たたは、たずえば、珟圚のバヌゞョンのsqlコマンドの完党なリストをご芧ください  https : //www.postgresql.org/docs/9.6/static/sql-commands.html


私がこの蚘事で芋せたかった䞻なもの誇倧宣䌝にもかかわらず、PostgreSQLは非垞に叀いDBMSであり、倚くのものがあり、非垞にうたく拡匵されおいたす。 したがっお、MySQLからそれに切り替えるずきは、マニュアルを読んだり、蚘事を読んだりするこずをお勧めしたす。



Source: https://habr.com/ru/post/J331460/


All Articles