RE:NODE

ბაზები10 წუთის საკითხავი

MySQL თუ PostgreSQL: პატიოსანი შედარება აპლიკაციის დეველოპერებისთვის

MySQL თუ PostgreSQL შენი აპლიკაციისთვის: SQL ფუნქციები, ტიპები, DDL, კონკურენცია, კავშირები, JSON, ეკოსისტემა და ოპერირება, არჩევის მკაფიო გზით.

0 მკითხველი

ვებ აპლიკაციების უმეტესობისთვის ნებისმიერი ბაზა გაართმევს თავს საქმეს, და არჩევანს ნაკლები მნიშვნელობა აქვს, ვიდრე სქემას, index-ებსა და query-ებს, რომლებსაც წერ. ამის მიუხედავად, ისინი ურთიერთშემცვლელი არ არის. PostgreSQL-ს უფრო მდიდარი SQL აქვს: ტრანზაქციული DDL, RETURNING, ნაწილობრივი index-ები, ნამდვილი BOOLEAN და UUID ტიპები, მასივები, დიაპაზონის ტიპები, JSON-ის უფრო ღრმა მხარდაჭერა GIN index-ებით, და extension-ების სისტემა, რომელიც ისეთ რამეებს ამატებს, როგორიცაა PostGIS. MySQL-ის გაშვება უფრო მარტივია, კავშირზე უფრო იაფია, და სწორედ მას ელის PHP-ის სამყაროს დიდი ნაწილი - WordPress მას მოითხოვს. თუ შენი framework ორივეს უჭერს მხარს და არაფერი გიბიძგებს რომელიმე მხარეს, ახალი პროექტებისთვის PostgreSQL უფრო ძლიერი ნაგულისხმევია. თუ WordPress-ს ან სხვა MySQL-ზე ორიენტირებულ აპლიკაციას უშვებ, ან გინდა, რომ ბაზა შენი stack-ის ყველაზე მოსაწყენი ნაწილი იყოს, MySQL სრულიად კარგი არჩევანია და არავინ უნდა გადაგაფიქრებინოს.

ამ პოსტის დანარჩენი ნაწილი გადის იმ განსხვავებებზე, რომლებიც აპლიკაციის აგებისა და გაშვებისას რეალურად ჩნდება, საორიენტაციო წერტილებად MySQL 8.4 LTS-ითა და PostgreSQL 17-ით.

მოკლე ვერსია#

MySQL 8.4PostgreSQL 17
ნაგულისხმევი იზოლაციაREPEATABLE READREAD COMMITTED
კავშირებიthread-ები; უმოქმედონი იაფიაპროცესები; pooler უფრო ადრე გჭირდება
DDL ტრანზაქციებშიარა - ყოველი DDL commit-ს აკეთებსკი
RETURNINGარაკი
UpsertON DUPLICATE KEY UPDATEON CONFLICT ... DO UPDATE
ნაწილობრივი index-ებიარაკი
გამოსახულების index-ებიფუნქციური index-ები, 8.0.13+კი
JSONJSON ტიპი, index generated სვეტებითjsonb GIN index-ებით
ტექსტის შედარება ნაგულისხმევადრეგისტრის მიმართ არამგრძნობიარერეგისტრის მიმართ მგრძნობიარე
ლოგიკური ტიპიTINYINT(1)-ის ფსევდონიმინამდვილი boolean
მოვლა-პატრონობაpurge თავისით მუშაობსVACUUM / autovacuum, რომელიც უნდა გაიგო
ლიცენზიაGPLv2 (Community), Oracle-ის საკუთრებაPostgreSQL Licence, თავისუფალი

არცერთი სვეტი გამარჯვებების სია არ არის. MySQL-ის რამდენიმე ჩანაწერი - იაფი კავშირები, მოსარგები vacuum-ის არარსებობა - ოპერაციული უპირატესობებია, რომლებიც პატარა სერვერზე SQL ფუნქციებზე მეტს ნიშნავს.

SQL ფუნქციები, რომლებსაც შეამჩნევ#

ფუნქციები, რომლებიც ცვლის, როგორ წერ აპლიკაციის კოდს:

`RETURNING`. PostgreSQL ჩასმულ ან განახლებულ ხაზებს თავად ბრძანებიდან აბრუნებს: INSERT ... RETURNING id, created_at. MySQL გაძლევს LAST_INSERT_ID()-ს auto-increment გასაღებისთვის და დანარჩენისთვის არაფერს, ასე რომ ნაგულისხმევი მნიშვნელობების ან trigger-ის მიერ დაყენებული მნიშვნელობების მისაღებად მეორე query სჭირდება. ORM-ები ამას მალავს, დამატებითი round trip-ის ფასად.

ტრანზაქციული DDL. PostgreSQL-ში CREATE TABLE, ALTER TABLE და CREATE INDEX შეიძლება ტრანზაქციის შიგნით გაეშვას და მასთან ერთად დაბრუნდეს, ასე რომ შუაში ჩავარდნილი migration არაფერს ტოვებს. MySQL-ში ყოველი DDL ბრძანება იმპლიციტურად commit-ს აკეთებს. 8.0-დან ყოველი ცალკეული DDL ბრძანება ატომურია - ან სრულდება, ან არა - მაგრამ ხუთბრძანებიანი migration, რომელიც მეოთხეზე მარცხდება, სამს გამოყენებულს ტოვებს. MySQL-ზე migration-ის ინსტრუმენტები ამას ბრძანებების მიხედვით პროგრესის ჩაწერით აკომპენსირებს; ჩავარდნისას გასუფთავება მაინც ხელით გიწევს.

ნაწილობრივი index-ები. PostgreSQL-ს შეუძლია ხაზების ქვესიმრავლის index-ირება: CREATE INDEX ON orders (customer_id) WHERE status = 'open'. ის პატარა და სწრაფია, როცა ხაზების უმეტესობა დახურულია. MySQL-ს ეკვივალენტი არ აქვს; ან მთელ სვეტს აკეთებ index-ს, ან generated სვეტის ხრიკს იყენებ.

Upsert-ები. ორივეს აქვს, განსხვავებული სემანტიკით. MySQL-ის INSERT ... ON DUPLICATE KEY UPDATE ნებისმიერი უნიკალური გასაღების კონფლიქტზე ამოქმედდება, რაც მოულოდნელია რამდენიმე უნიკალური გასაღების მქონე ცხრილებზე. PostgreSQL-ის ON CONFLICT (column) DO UPDATE ასახელებს constraint-ს, რომელსაც ეხება, და MERGE 15 ვერსიიდან ხელმისაწვდომია.

Join-ები და სიმრავლის ოპერაციები. PostgreSQL-ს აქვს FULL OUTER JOIN; MySQL-ს არ აქვს და left და right join-ის UNION სჭირდება. ორივეს აქვს window ფუნქციები და common table expression-ები, რეკურსიულების ჩათვლით, MySQL 8.0-დან. MySQL-მა INTERSECT და EXCEPT 8.0.31-ში დაამატა.

Constraint-ები. MySQL CHECK constraint-ებს 8.0.16-დან ახორციელებს - მანამდე მათ კითხულობდა და უგულებელყოფდა, რაც დიდი უნდობლობის წყაროა. PostgreSQL-ს ასევე აქვს exclusion constraint-ები (ერთი ოთახის ორი ჯავშანი არ შეიძლება ერთმანეთს გადაფაროს) და deferrable constraint-ები, რომლებსაც MySQL-ში ეკვივალენტი არ აქვს.

Materialised view-ები, sequence-ები, `LISTEN`/`NOTIFY`, row-level security. PostgreSQL-ს ოთხივე აქვს. MySQL-ს არცერთი არ აქვს ჩაშენებულად. თუ რომელიმე გჭირდება, ეს თავისთავად ძლიერი არგუმენტია.

ტიპები და სიმკაცრე#

PostgreSQL-ის ტიპების სისტემა უფრო დიდია: boolean, uuid, inet და cidr, ნებისმიერი ტიპის მასივები, დიაპაზონის ტიპები (tstzrange ჯავშნის პერიოდისთვის), interval, enum-ები, რომლებიც ნამდვილი ტიპებია, და მომხმარებლის მიერ განსაზღვრული კომპოზიტური ტიპები. MySQL აუცილებელს ფარავს და რამდენიმეს სხვებზე ასახავს: BOOLEAN არის TINYINT(1), UUID-ები არის BINARY(16) UUID_TO_BIN()-ით ან CHAR(36), ხოლო მასივები JSON სვეტია.

დრო ის ტიპია, რომელშიც ხაფანგია. MySQL-ის TIMESTAMP ინახავს UTC-ს, გარდაქმნის session-ის დროის სარტყელში და მთავრდება 2038-01-19 03:14:07 UTC-ზე - თარიღი, რომელიც უკვე იპოთეკების, გარანტიებისა და გრძელვადიანი გამოწერების სიცოცხლის ხანგრძლივობაში ხვდება. ყველაფრისთვის, რაც შეიძლება მას გასცდეს, DATETIME გამოიყენე და UTC იქ თავად შეინახე. PostgreSQL-ის timestamptz 294276 წლამდე მიდის.

MySQL-ის რეპუტაცია, რომ ცუდ მონაცემებს ჩუმად იღებს, ძველი ვერსიებიდან და თავისუფალი SQL რეჟიმებიდან მოდის. MySQL 8-ის ნაგულისხმევი sql_mode მოიცავს STRICT_TRANS_TABLES, ONLY_FULL_GROUP_BY, NO_ZERO_IN_DATE, NO_ZERO_DATE და ERROR_FOR_DIVISION_BY_ZERO-ს: ზედმეტად გრძელი სტრიქონის ან 0000-00-00 თარიღის ჩასმა შეცდომაა, როგორც უნდა იყოს. ზოგიერთი ძველი აპლიკაცია მუშაობის გასაგრძელებლად დაკავშირებისას უფრო თავისუფალ რეჟიმს აყენებს; შენი შეამოწმე SELECT @@SESSION.sql_mode-ით.

ტექსტის შედარება ნაგულისხმევად განსხვავდება. MySQL-ის ნაგულისხმევი collation, utf8mb4_0900_ai_ci, რეგისტრისა და აქცენტის მიმართ არამგრძნობიაროდ ადარებს, ასე რომ WHERE email = 'Ana@Example.com' პოულობს ana@example.com-ს. PostgreSQL ზუსტად ადარებს, და არამგრძნობიარე დამთხვევისთვის lower()-ს, ILIKE-ს ან citext extension-ს იყენებ. არცერთი არ არის არასწორი, მაგრამ აპლიკაციის მათ შორის გადატანა ცვლის იმ query-ების შედეგებს, რომლებიც რეგისტრს არც კი ახსენებს. utf8mb4 და collation-ები MySQL-ის მხარეს ხსნის.

JSON#

ორივე ინახავს და query-ს უკეთებს JSON-ს, და ორივე საკმარისად კარგია, რომ ნახევრად სტრუქტურირებული ველები რელაციურ მონაცემებთან ერთად შეინახო. განსხვავება index-ირებაშია.

PostgreSQL-ის jsonb-ს შეუძლია მთელ დოკუმენტზე GIN index-ის მიღება, რომელიც შემდეგ ემსახურება შემცველობის query-ებს (WHERE attrs @> '{"colour": "red"}') ნებისმიერ გასაღებზე. MySQL-ის JSON ტიპი index-ირდება შენთვის საინტერესო მნიშვნელობების generated სვეტებში ამოღებით, ან მასივებისთვის multi-valued index-ებით (8.0.17+):

sql
-- MySQL: index one path through a generated columnALTER TABLE products  ADD COLUMN colour VARCHAR(20) AS (attrs->>'$.colour') STORED,  ADD INDEX idx_colour (colour);-- PostgreSQL: one index for any keyCREATE INDEX idx_attrs ON products USING gin (attrs jsonb_path_ops);

MySQL-ის მიდგომა ცალსახა და სწრაფია იმ გზებისთვის, რომლებიც დაგეგმე; PostgreSQL-ის მიდგომა მოქნილია იმ query-ებისთვის, რომლებიც არ დაგიგეგმავს. თუ აპლიკაცია ძირითადად JSON დოკუმენტებზე ad-hoc ფილტრაციაა, ეს სასწორს PostgreSQL-ისკენ ხრის. MySQL-ის JSON და generated სვეტები MySQL-ის მხარეს სიღრმისეულად განიხილავს.

კონკურენცია, lock-ები და მოვლა-პატრონობა#

ორივე multi-version concurrency control-ს იყენებს: მკითხველები ჩამწერებს არ ბლოკავს და ჩამწერები მკითხველებს არ ბლოკავს. მას სხვადასხვანაირად ახორციელებენ, და განსხვავება ოპერირებაში ჩანს.

MySQL-ის InnoDB ხაზებს ადგილზე ანახლებს და ძველ ვერსიებს undo log-ში ინახავს იმ ტრანზაქციებისთვის, რომლებსაც ისინი ჯერ კიდევ სჭირდება; ფონური purge thread მათ შლის, როცა აღარავის სჭირდება. მოსარგები ბევრი არაფერია. PostgreSQL ყოველ განახლებაზე ხაზის ახალ ვერსიას წერს და ძველს ცხრილში ტოვებს, სანამ VACUUM მას არ დაიბრუნებს; autovacuum ამას ავტომატურად აკეთებს, მაგრამ ჩაწერაზე მძიმე ცხრილებზე მორგებას საჭიროებს, ხოლო დავიწყებული გრძელი ტრანზაქცია მას მთლიანად აჩერებს, და ცხრილები bloat-ით იბერება. Postgres-ის vacuum და bloat სრული ამბავია. ეს PostgreSQL-ის ნამდვილი ოპერაციული ფასია, რომელსაც მისი ფუნქციების სია არ ახსენებს.

ნაგულისხმევი იზოლაცია განსხვავდება. MySQL ნაგულისხმევად REPEATABLE READ-ს იყენებს, gap და next-key lock-ებით index-ირებულ დიაპაზონებზე phantom-ების თავიდან ასაცილებლად - რაც ასევე ნიშნავს მეტ lock-ის მოლოდინს და პერიოდულ deadlock-ებს იმავე დიაპაზონში ერთდროული ჩასმებისას. PostgreSQL ნაგულისხმევად READ COMMITTED-ს იყენებს, სადაც ყოველი ბრძანება უახლეს commit-ირებულ მონაცემებს ხედავს. აპლიკაციის კოდი, რომელიც კითხულობს, ითვლის და უკან წერს, ამ ორის ქვეშ სხვადასხვანაირად იქცევა; ტრანზაქციები, lock-ები და deadlock-ები MySQL-ის ქცევას განიხილავს.

InnoDB-ის clustered primary key ხაზებს გასაღების რიგით ინახავს, ასე რომ primary key-ზე დიაპაზონის scan-ები ძალიან სწრაფია, ხოლო შემთხვევითი primary key-ები (UUIDv4) ძვირი. PostgreSQL ხაზებს heap-ში ინახავს განსაკუთრებული რიგის გარეშე, და ყოველი index, primary key-ის ჩათვლით, მასზე მიუთითებს.

კავშირები და მეხსიერება#

MySQL ყოველ კავშირს thread-ით ემსახურება. უმოქმედო კავშირი რამდენიმე ასეული კილობაიტი ჯდება, და სერვერს მათი ასობით კომფორტულად შეუძლია შეინახოს. PostgreSQL ყოველ კავშირზე პროცესს ქმნის fork-ით, თითოეულს საკუთარი მეხსიერებით; რამდენიმე ასეული უმოქმედო კავშირი რეალური ხარჯია, და ჩვეულებრივი პასუხია pooler-ი, როგორიცაა PgBouncer, წინ. პატარა სერვერზე ეს ერთ-ერთი ყველაზე პრაქტიკული განსხვავებაა: აპლიკაცია რამდენიმე worker-ით, თითოეული საკუთარი pool-ით, PostgreSQL-ის კომფორტულ ლიმიტს ბევრად უფრო ადრე აღწევს. ორივე მაინც სჯის შეუზღუდავ pool-ებს, და რჩევა connection pool-ებსა და ლიმიტებში თითოეულზე ვრცელდება.

მორგებისთვის ორივე ქეშის ზომასა და query-ზე მეხსიერების კონტროლზე დაიყვანება. MySQL-ის მთავარი სახელური innodb_buffer_pool_size-ია, ჩვეულებრივ მეხსიერების ნახევარი ან მეტი; PostgreSQL-ისა - shared_buffers დაახლოებით მეოთხედზე, დანარჩენისთვის ოპერაციული სისტემის ქეშზე დაყრდნობით. შეადარე InnoDB-ის მორგება პატარა სერვერებისთვის და PostgreSQL-ის მორგება პატარა სერვერებისთვის, რომ დაინახო, რამდენად სხვადასხვანაირად იხარჯება ერთი და იგივე მეხსიერება.

ეკოსისტემა და პორტაბელურობა#

ზოგი პროგრამა შენ მაგივრად წყვეტს. WordPress MySQL-ს მოითხოვს (ან თავსებად სერვერს). PHP აპლიკაციების, plugin-ებისა და თემების გრძელი კუდი MySQL-ზე სპეციფიკურ SQL-ს წერს და მხოლოდ მასზეა გამოცდილი. Minecraft-ის plugin-ები და FiveM-ის რესურსები, რომლებიც მონაცემებს SQL სერვერში ინახავს, ჩვეულებრივ MySQL-ზეა გათვლილი. საპირისპირო მიმართულებით, PostGIS PostgreSQL-ს გეოგრაფიული მონაცემების სტანდარტად აქცევს, ხოლო ისეთი ინსტრუმენტები, როგორიცაა Supabase, Hasura და PostgREST, მის გარშემოა აგებული.

framework-ები უმეტესად ნეიტრალურია: Django, Rails, Laravel, Prisma, SQLAlchemy, Entity Framework Core და Hibernate ორივეს უჭერს მხარს. არანეიტრალური ნაწილები ფუნქციებია: Django-ს ArrayField და მისი django.contrib.postgres-ის ძებნის ინსტრუმენტები მხოლოდ PostgreSQL-ისთვისაა, და პროექტში ნებისმიერი raw SQL მას იმ engine-ს აბამს, რომლისთვისაც დაიწერა.

მოგვიანებით მათ შორის გადასვლა შესაძლებელია, მაგრამ უფასო არ არის. მონაცემები გადადის ისეთი ინსტრუმენტებით, როგორიცაა pgloader (MySQL-იდან PostgreSQL-ში); query-ებს გადახედვა სჭირდება რეგისტრის მგრძნობელობის, განახლებების შიგნით LIMIT სინტაქსის, თარიღის ფუნქციების, იდენტიფიკატორების ციტირების (backtick-ები ორმაგი ბრჭყალების წინააღმდეგ) და upsert-ების თვალსაზრისით. მხოლოდ ORM-ზე დაფუძნებული აპლიკაცია დღეებში გადადის; ხელით დაწერილი SQL-ით, trigger-ებითა და პროცედურებით - ბევრად უფრო დიდხანს.

ლიცენზირების შესახებ: MySQL Community Server GPLv2-ია და Oracle-ს ეკუთვნის, რომელიც დამატებითი კომპონენტებით Enterprise ვერსიასაც ყიდის. PostgreSQL თავისუფალი ლიცენზიითაა და მას ავითარებს საზოგადოება, რომელსაც ერთი მფლობელი არ ჰყავს. ქსელით დაკავშირებული აპლიკაციისთვის სერვერის ლიცენზია შენს კოდს არცერთ შემთხვევაში ვალდებულებებს არ აკისრებს.

როგორ ავირჩიოთ#

აირჩიე MySQL, როცა:

  • პროგრამა, რომელსაც აყენებ, მას მოითხოვს ან ამჯობინებს: WordPress, PHP CMS-ებისა და ფორუმის პროგრამების უმეტესობა, თამაშის სერვერის plugin-ები.
  • გინდა, რომ ბაზას რაც შეიძლება ნაკლები ყურადღება სჭირდებოდეს, და შენი SQL სტანდარტული CRUD-ია ORM-ის გავლით.
  • ბევრი პატარა პროცესიდან ბევრ კავშირს ელი და pooler-ის გაშვება არ გინდა.

აირჩიე PostgreSQL, როცა:

  • გინდა უფრო მდიდარი SQL - RETURNING, ტრანზაქციული migration-ები, ნაწილობრივი index-ები, მასივები, დიაპაზონები, exclusion constraint-ები.
  • შენი მონაცემები მოიცავს გეოგრაფიას (PostGIS) ან ინტენსიურ ad-hoc JSON query-ებს.
  • ახლიდან იწყებ framework-ით, რომელიც ორივეს უჭერს მხარს, და MySQL-ის უპირატესობის მიზეზი არ გაქვს.

აირჩიე ის, რომელიც შენმა გუნდმა უკვე იცის, როცა პროექტი ჩვეულებრივია და ვადა რეალური. ერთი engine-ის ჩავარდნის ხერხების ცოდნა აპლიკაციების უმეტესობისთვის ფუნქციების სხვაობაზე მეტი ღირს. დოკუმენტურ და key-value საცავებთან შედარებები რომელი ბაზა გამოვიყენო და Postgres თუ MongoDB პოსტებშია.

RE:NODE ორივეს ცალკე ბაზის ხაზებად ყიდის. MySQL გეგმები MySQL 8.4 LTS-ზე მუშაობს, 1 GB მეხსიერებიდან და 10 GB NVMe-დან, თვეში $4-ად, გენერირებული root პაროლით, აპლიკაციის ბაზითა და აპლიკაციის მომხმარებლით. PostgreSQL გეგმები 1 GB-სა და 20 GB-ზე $6-დან იწყება, ყოველი სერვერისთვის გენერირებული მონაცემებით. ორივე გეგმის host-სა და port-ზე ხელმისაწვდომია და backup სლოტებით მოდის.

FAQ#

PostgreSQL MySQL-ზე უკეთესია?

მას მეტი SQL ფუნქცია და უფრო დიდი ტიპების სისტემა აქვს, რაც მას უკეთეს ნაგულისხმევად აქცევს ახალი აპლიკაციებისთვის, რომლებიც მათ გამოიყენებს. MySQL-ის ოპერირება უფრო მარტივია და მას ბევრი არსებული პროგრამა მოითხოვს. „უკეთესი“ დამოკიდებულია იმაზე, ამათგან რომელია მნიშვნელოვანი შენი პროექტისთვის.

MySQL PostgreSQL-ზე სწრაფია?

ზოგადად - არა. ორივე სწრაფია მარტივ index-ირებულ წაკითხვასა და ჩაწერაზე, რომლებიც ვებ ტრაფიკის უმეტესობას შეადგენს. MySQL კავშირების დიდ რაოდენობას უფრო იაფად უმკლავდება; PostgreSQL-ის planner-ი რთულ query-ებზე ხშირად უკეთესად მუშაობს. სიჩქარეზე გადაწყვეტილებამდე საკუთარი დატვირთვა გაზომე.

შეუძლია WordPress-ს PostgreSQL-ზე მუშაობა?

არცერთი მხარდაჭერილი გზით. WordPress-ის ბირთვი და plugin-ების უმეტესობა MySQL-ისთვისაა დაწერილი. ექსპერიმენტული თავსებადობის ფენები არსებობს, მაგრამ plugin-ები, რომლებიც საკუთარ SQL-ს წერს, მათზე ტყდება. WordPress MySQL-ზე გაუშვი.

რამდენად რთულია მოგვიანებით MySQL-იდან PostgreSQL-ზე გადასვლა?

მონაცემები მარტივი ნაწილია. სამუშაო იმ query-ებშია, რომლებიც MySQL-ის ქცევას ეყრდნობა: რეგისტრის მიმართ არამგრძნობიარე შედარებები, ON DUPLICATE KEY UPDATE, backtick-ებით ციტირებული იდენტიფიკატორები, MySQL-ის თარიღის ფუნქციები და თავისუფალი GROUP BY ძველ კოდში. მხოლოდ ORM-ის მომხმარებელი აპლიკაცია სწრაფად გადადის; raw SQL-ის მქონეს ფრთხილი გადახედვა და ტესტების ნაკრები სჭირდება.

მჭირდება connection pooler MySQL-ით?

ჩვეულებრივ ცალკე არა. აპლიკაციის მხარეს pool-ები deploy-ების უმეტესობისთვის საკმარისია, რადგან MySQL-ის კავშირები thread-ებია და უმოქმედონი იაფია. გონივრული pool-ის ზომები მაინც გჭირდება; ასობით დატვირთული კავშირი ორ CPU ბირთვზე ნებისმიერ ბაზაზე ნელია.


კომენტარები

სრულიად ანონიმურად: ანგარიშის, ელფოსტის და cookie-ის გარეშე. ინახება მხოლოდ სახელი, ტექსტი და დრო - სხვა არაფერი. ბმულების რაოდენობა ლიმიტირებულია.

0/2000