මට ඔයාට කියන්න දෙයක් තියෙනවා.එය පිළිගන්න මට ගොඩක් කල් ගියා. මගේ වෘත්තීය කාලය තුළ, මම හිතුවා Raw SQL ලියන එක අසාර්ථක බව සලකා බැලිය යුතු බව. එය ඔබට ORM ඔබ කැමති දේ කරන්නට නොහැකි විය. එය ඔබේ අමුද්රව්ය බිඳ වැටී ඇති බව අදහස් කළේ. උසස් ඉංජිනේරුවන් ORMs භාවිතා කළා. Junior ඉංජිනේරුවන් SQL ලිව්වා. මම වැරදි. වැරදි පමණක් නොවේ. ඒ විශ්වාසය ක්රියාකාරීව හානිදායක විය. එය මට පිරිසිදු හා ඵලදායී පෙනුමක් ඇති කේතය ලිවීමට හේතු විය, නමුත් සැබෑවටම ප්රතිඵලදායී විය. අපගේ යෙදුම් වලින් එකක් තුළ එක් පිටුවක් render කිරීමට කොපමණ SQL ප්රශ්න ගත වියදම් කළ හැකිද? සහ සංඛ්යාව 47 වන අතර, දත්ත පදනම වෙත හා ආපසු දත්ත අංක විස්සක් පෙන්වන්න. එය නිෂ්පාදනය කරන කේතය සම්පූර්ණයෙන්ම පිරිසිදු විය. Type-safe. Fully tested. With beautiful abstractions. කේතය නිහඬව අපගේ ප්රතිචාර වේලාව විනාශ කළා.එහෙත් කිසිවෙකුට ඒ ගැන අවබෝධයක් තිබුණේ නැහැ, මොකද අවබෝධය අපෙන් අපරාධය සැඟවුනා. ORM වෙළඳාම් ද්රව්ය තුළ කිසිවෙකුට නොපෙනෙන එකම දෙය වන්නේ එය සැබෑවටම දත්ත සමුදාය සමඟ කරන දේ සැඟවීමේදී ඉතා හොඳ බවයි. අපි කතා කරමු ඔබ සැබවින්ම ඇති දේ ගැන ORM මේසයට බොහෝ දේ ගෙන එයි. ඒ ප් රශ්නයේ කොටසක් වේ. ඒ දේවල් සමහරක් එතරම් හොඳයි එය ඔබ නොතේරෙන විට ඔබට හානියක් කළ හැකිය. ORM ස්කෑම් කළමනාකරණය ගෙන එයි - අනුවාදය ප්රවාහන, rollbacks, සහ ස්කෑම් diffing.And that part is fantastic.And you should absolutely keep using it. එසේම, එය සරල ඔත්තු ක්රියාකාරකම් සඳහා හොඳ API ගෙන එයි - `findById`, `create`, `update`, සහ `delete`. සහ එම කොටසක් ද විශිෂ්ට වේ. ඊළඟ දෙය - මාතෘකා සහ ටැබ්ලට් අතර මැප්ප කිරීම. සහ මෙය ORM හි ප්රධාන කොටසක් වේ.එසේම, ගැටළු ආරම්භ වන තැන මෙයයි. ORM දත්ත සන්නිවේදන දර්ශනයක් ගෙන එයි.ඔව් සමහර ආකර්ෂණීය ලෝකය තුළ ඔබ කේතය රේඛාවක් වෙනස් කිරීමකින් තොරව MySQL සිට PostgreSQL වෙත මාරු කළ හැකිය.ඒත් සැබෑ ලෝකය තුළ, ඔබ කවදාවත් කරන්නේ නැහැ.ඔබ දත්ත සන්නිවේදනය තෝරාගෙන ඔබ එය අනුගමනය කරයි. ඔබ ඒවා තේරුම් ගන්නේ නම්, ඔබ ජීවත් වනු ඇත. ඔබ එසේ නොකරන්නේ නම්, ඔබ විසි හතළිහක් (හෝ ඊට වඩා) ප්රශ්න පෙන්වීමට අවසන් වනු ඇත. N + 1 ගැටලුව ලක්ෂණයක් නොව රෝගයක් ORM සමඟ වැඩ කරන සෑම පරිගණකයක්ම N + 1 ප්රශ්නය ගැන අසා ඇත. ලෙහෙසි ප්රවේශය ලෝක් ඇතුළේ ඇති අතර, මෙම ප්රවේශය එක් ප්රවේශයකට එක් ප්රවේශයක් ඇති කරයි. N + 1 ගැටලුව ORM ගැටලුවන්ගේ අයිස්බෙරයේ දකින කොටසක් පමණි - ඒවා එතරම් පහසුකමක් දක්වන කේතය ලියන්නට ඉඩ සලසයි. මගේ 47 ප්රශ්න සියලුම N + 1 ආකෘති නොවේ. සමහරක් ප්රමාණවත් ප්රවේශයක් විය. සමහරක් දී, ORM ක්රම දෙකක් පමණක් අවශ්ය වූ විට සම්පූර්ණ ප්රවේශයන් උඩුගත කරන ලදී. සමහරක් ප්රශ්න අංකය පුස්තකාලය විසින් යැවූ ස්වයංක්රීය ගණනය ප්රශ්න විය. මෙම කිසිවක් යෙදුම් කේතය කියවීමෙන් පැහැදිලි නොවේ! ඒ වගේම Raw SQL ඔබට විරුද්ධ අත්දැකීම් ලබා දෙයි.ඔබ හරියටම දන්නේ මොන ප්රශ්න ද database වෙත යැවෙනවාද කියලා. මේ Raw SQL එක බලන්න. SELECT id, name, email FROM users WHERE account_id = ? AND is_active = 1 ORDER BY created_at DESC LIMIT 20 OFFSET 0; ඔබ ප්රශ්නය දන්නවා.ඔබ දන්නේ කුමන කූඩුවල් තෝරා ගනු ඇත.ඔබ මෙම ප්රශ්නය සඳහා ඔබට අවශ්ය වන ඉංජිනේරුවන් ගැන සිතන්න පුළුවන්.ඔබටත්,ඔබට එය සෘජුවම ඔබේ දත්ත පද්ධති කොන්සෝලයට ලියාපදිංචි කළ හැකි අතර එය මත EXPLAIN නියෝගයක් ක්රියා කළ හැකිය. ORM සමඟ, ඔබ දන්නා එකම දේ වන්නේ අරමුණු ය. සැබෑ ප්රතිපත්තිය ක්රියාත්මක කිරීමේදී පසුව වනු ඇත. සහ සැබෑ ප්රශ්න ඔබේ ආකෘතිය වෙනස් කිරීම සමඟ කාලය තුළ වෙනස් විය හැකි අතර, ඔබට ඒවා පාලනය කළ නොහැකිය. ORMs සැබවින්ම ඔබට අනුගමනය කළ නොහැක ORM වේගවත් පමණක් නොව එය ඒවා පාලනය කළ නොහැකි අතර, සැකසීම එය විසඳිය නොහැක. Window ක්රියාකාරකම් වින්ඩෝස් කාර්යයන් - `RANK()`, `ROW_NUMBER()`, `LAG()`, `LEAD()`, Running Totals, Moving Averages - නවීන SQL හි වඩාත් බලවත් විශේෂාංග වලින් එකක්. SELECT user_id, amount, order_date, SUM(amount) OVER ( PARTITION BY user_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS running_total FROM orders WHERE account_id = ?; මෙම ප්රශ්නය එක් ඉල්ලීමක් තුළ ගිණුම සඳහා ක්රියාත්මක මුළු නිෂ්පාදනය කරනු ඇත.එය වේගවත්, සුපිරි හා නිවැරදි වේ. ඔබ ORM හි ප්රශ්න නිර්මාණකයා මත එය ක්රියාත්මක කිරීමට උත්සාහ කරන්නේ නම්, ඔබ එය කළ නොහැකි වනු ඇත. එබැවින් මෙම ගණනය කිරීම සඳහා විකල්ප දෙකක් ඇත.ඔබ සියලු රේඛා මතකය වෙත ගෙන එය යෙදුම් මට්ටමේ ගණනය කර, හෝ ඔබ Raw SQL ලිවීමට. Bulk මෙහෙයුම් ඔබ විදේශීය API වලින් ලියාපදිංචි කිරීම් 10,000ක් ඇතුළත් කළ යුතු අතර එය ඔබගේ දත්ත සමුදාය තුළ ඇතුළත් කිරීම හෝ යාවත්කාලීන කිරීම අවශ්ය වේ. ORM ක් රමය : foreach ($incomingRecords as $data) { $record = $this->repository->findOneBy(['external_id' => $data['id']]); if ($record === null) { $record = new SyncRecord(); $record->setExternalId($data['id']); } $record->setPayload($data['payload']); $record->setSyncedAt(new \DateTimeImmutable()); $this->em->persist($record); } $this->em->flush(); 10k ලියාපදිංචිය ක්රියාත්මක කිරීම සඳහා අපි 10,000 තෝරා ගනුදෙනු සහ 10,000 තෝරා හෝ යාවත්කාලීන ගනුදෙනු ක්රියාත්මක කළ යුතුය. SQL ප්රවේශය : INSERT INTO sync_records (external_id, payload, synced_at) VALUES (?, ?, NOW()), (?, ?, NOW()), ... ON DUPLICATE KEY UPDATE payload = VALUES(payload), synced_at = VALUES(synced_at); 500-1,000 රේඛාවක කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොටස් කොට JSON මෙහෙයුම් ඔබ ඔබේ දත්ත පදනම තුළ JSON ගබඩා කරන්නේ නම්, MySQL 8 සහ PostgreSQL පසු එය ඉතා ප්රයෝජනවත් කර ඇත. JSON මාර්ගය අනුව ෆිල්ටර් කිරීම? JSON ක්ෂේත්රයේ අගය මත ඉංජිනේරු කිරීම? JSON මාතෘකාව රේඛා බවට පරිවර්තනය කිරීම සඳහා 'JSON_TABLE' භාවිතා කිරීම? මේවා දත්ත බැස්ම හොඳින් කටයුතු කරන සැබෑ මෙහෙයුම් වේ. -- Find all products where attributes contain color = 'blue' SELECT * FROM products WHERE JSON_UNQUOTE(JSON_EXTRACT(attributes, '$.color')) = 'blue'; -- This works because we created a functional index: -- CREATE INDEX idx_color ON products((JSON_UNQUOTE(JSON_EXTRACT(attributes, '$.color')))); ඔබ මේ වගේ දෙයක් අවශ්ය වන මොහොතේ, ඔබ කොහොමත් Raw SQL ලියනවා. තාක්ෂණිකව, ඔබ ඇතුළත් json ක්ෂේත්රයක් ටැබ්ලයේ සජීවී ක්ෂේත්රයක් බවට පරිවර්තනය කළ හැකිය, නමුත් එය වඩාත් පුරුද්දක් වගේ. Debugging: සැඟවුනු බදු මෙන්න ඔබ සමහර විට ජීවත් වුණු තත්වයක්. ඔබ නිසැකවම නිෂ්පාදන දී වේගවත් ප්රශ්නය මතක් කර ඇත. ඉතා වේගවත් නොවේ.එහෙත් පාරිභෝගිකයින් ගැන පැමිණිලි කිරීමට හෝ නිරීක්ෂණය කිරීම සඳහා එය ප්රකාශ කිරීමට ආරම්භ කිරීමට ප්රමාණවත් වේගවත් වේ. ප්රශ්නය සොයා ගැනීමට ඔබ යෙදුම කේතය විවෘත වේ.එය ක්රමය කේතයක් වේ: පනහක් ඇමතුම් ගැඹුරු, ඉල්ලුම් ප්රමාණයන් මත පදනම්ව සම්මතව ක්රියාත්මක කරන ලද ෆයිල්ටර්, ප්රධාන තැන්පතු පන්තියේ කොහේ හරි එකතු කිරීමක්, ඔබ කාලයක් තිස්සේ විවෘත නොකරන ආකෘති ගොනුව තුළ සැකසුම් කරන ලද උනන්දුව. ඔබ ප්රශ්න ලියාපදිංචි කිරීම ක්රියාත්මක කර SQL ගබඩා. එය රේඛා 60 ඇත. එය ඔබට ලිවීමට මතක නැති අතුරු ප්රශ්නයක් ඇත. ඉංජිනේරුවා නොතිබූ කූඩුව මත 'Order BY' ඇත. දැන් ඔබ සොයා ගැනීමට අවශ්ය වන්නේ එම subquery කොතැන සිට පැමිණියේද. පනහක් ක්රම කේතය ඇමතුම් එය නිෂ්පාදනය කර තිබේද? මෙය ORM සංකීර්ණතාවයේ සැඟවුනු වටිනාකමකි. යමක් වැරදි වුණොත්, ඔබ එකම වේලාවක මට්ටම් දෙකක් debug කරන්නේ: යෙදුම් ලෝගිකය සහ ප්රශ්න නිෂ්පාදනය ලෝගිකය. // What you see in code review $users = $this->userRepository ->createQueryBuilder('u') ->leftJoin('u.account', 'a') ->andWhere('u.isActive = :active') ->andWhere('a.plan = :plan') ->setParameter('active', true) ->setParameter('plan', $plan) ->getQuery() ->getResult(); // What actually runs. And nobody reads until something breaks SELECT u.id, u.name, u.email, u.created_at, u.updated_at, u.is_active, u.account_id, a.id AS a_id, a.name AS a_name, a.plan AS a_plan, a.is_active AS a_is_active, a.created_at AS a_created_at, a.updated_at AS a_updated_at, a.meta AS a_meta FROM users u LEFT JOIN accounts a ON a.id = u.account_id WHERE u.is_active = 1 AND a.plan = 'enterprise' ඒ 'SELECT *' හැසිරීම - සෑම සංකේතයක සිට සෑම සංකේතයක්ම මතකයට රැගෙන යාම - ඔබ සම්පූර්ණ සංකේත වහල් කිරීම භාවිතා කරන විට ඔබ ගෙවන දේ වේ. සැබවින්ම ක් රියාත්මක වන ආකෘතිය මෙම වැරදි සිදු කිරීම සහ දකින වසර දහයකට පසු, මම වැඩ කරන ව්යාපෘතිවලට මම භාවිතා කරන ව්යුහය මෙන්න. ORM owns: - සියලු ස්කෑම් සංකේත සහ සංක්රමණ Entity lifecycle management (Create, persist, flush, remove) (නිර්මානුකූල ජීවිත සයිකල් කළමනාකරණය) Simple lookups: find by ID, find by single filter, පිටපත් ලැයිස්තුව - සීමිත, කුඩා ප්රතිඵල රැස්වීම් තුළ සම්බන්ධතා කළමනාකරණය Raw SQL owns: Report, Dashboard, or Exports සඳහා සැලසුම් කර ඇති ප්රශ්න - සියලුම බෝල ක්රියාකාරකම්: batch inserts, batch updates, upserts Multiple Tables හරහා සංඛ්යාත කිරීම database-specific features භාවිතා කරන ඕනෑම ප්රශ්නය - සහ බොහෝ විට, වේගවත් ප්රශ්න ලැයිස්තුවේ පෙනෙන ඕනෑම ප්රශ්නය සයිෆෝනියාවේදී මෙම බෙදාහැරීමේ ක් රියාත්මක කිරීම පිරිසිදු වේ.එක්තෝපීය තැන්පතු ORM මට්ටමට ප්රතිකාර කරයි.විශ්චය පන්ති විශේෂ සංකේතයක් - මම ඒවා කියවීමේ තැන්පතු (read repositories) හෝ "query repositories" (query repositories) ලෙස හැඳින්වෙනවා.එක්තෝපීය තැන්පතු Directly DBAL භාවිතා කරමින් SQL මට්ටමට ප්රතිකාර කරයි: // Entity repository - pure ORM, simple operations class UserRepository extends ServiceEntityRepository { public function findActiveById(int $id): ?User { return $this->findOneBy(['id' => $id, 'isActive' => true]); } public function save(User $user): void { $this->getEntityManager()->persist($user); $this->getEntityManager()->flush(); } } // Query repository - raw SQL, complex reads class UserAnalyticsRepository { public function __construct(private readonly Connection $db) {} public function getRetentionBySignupCohort(\DateTimeImmutable $from, \DateTimeImmutable $to): array { $sql = <<<SQL SELECT DATE_FORMAT(u.created_at, '%Y-%m') AS cohort, COUNT(DISTINCT u.id) AS total_users, COUNT(DISTINCT CASE WHEN u.last_active_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN u.id END) AS active_last_30d, ROUND( COUNT(DISTINCT CASE WHEN u.last_active_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN u.id END) / COUNT(DISTINCT u.id) * 100, 1 ) AS retention_pct FROM users u WHERE u.created_at BETWEEN :from AND :to GROUP BY cohort ORDER BY cohort ASC SQL; return $this->db->fetchAllAssociative($sql, [ 'from' => $from->format('Y-m-d'), 'to' => $to->format('Y-m-d'), ]); } } DBAL ඔබට අවශ්ය සියලු දේ ලබා දෙයි - සූදානම් ප්රකාශයන්, සම්බන්ධතා කළමනාකරණය, තැපැල් සහාය.ඔබ SQL ලිවීමට ආරක්ෂාව අත්හරින්නේ නැහැ.ඔබ ඔක්කොම මේ ප්රශ්නය සඳහා අවශ්ය නොවන ඔක්කොම ඔස්ටේට් හයිඩ්රැකීම් අත්හරින්නේ නැහැ. ORM අනුවාදය ඔබට කළ නොහැකි බව Raw SQL අනුවාදය ඔබට ලබා දෙයි: ප්රශ්නය එහි ඇත. කණ්ඩායමේ ඕනෑම සංවර්ධකයා එය කියවා, එය තේරුම් ගත හැකිය, එය දත්ත සමුද්රතාවයට පිටපත් කර, එය මත 'EXPLAIN' ක්රියාත්මක කළ හැකිය, එය සංසන්දනය කළ හැකිය. කවදාවත් විකල්පයක් නොවන හැකියාව සමහර අය හිතන්නේ SQL යනු පැරණි හැකියාවක් වන අතර, මොහොතකට පසු නවීන මෙවලම් ඔබට අසාර්ථක වන විට ඔබට නැවත වැටෙන දෙයක් වන අතර, ඔබගේ දුරකථනය මිය ගිය නිසා භෞතික සිතියමක් භාවිතා කරන්නේ කෙසේද යන්න දැන ගැනීම වැනි. මම හිතන්නේ මේක ආපස්සට එනවා කියලා. SQL යනු ඔබේ දත්ත සමුදාය කතා කරන භාෂාවයි. දත්ත සමුදාය බොහෝ backend යෙදුම්වල වෙනත් ඕනෑම අංගයට වඩා වැඩ කරනවා. ඔබ එය කිරීමට ඉල්ලන දේ තේරුම් ගැනීම විකල්ප දැනුම නොවේ. මගේ වෘත්තිය තුළ මම වඩාත් ගරු කළ සංවර්ධකයින් එක් එක් එක් දෙයක් බෙදා: ඔවුන් සෑම මට්ටමකම පහසු වේ. ඔවුන් එය ගැලපෙන විට ORM භාවිතා හා එය නොවේ විට SQL ලිවීමට. ඔවුන් SQL සඳහා ප්රවේශ වීම පරාජය අනුමත කිරීම බව දැනෙන්නේ නැහැ. ඔවුන් එය නිවැරදි මෙවලමක් භාවිතා කරන බව දැනෙනවා. අවසාන SQL ප්රශ්නය නිර්මාණය කරන ආකාරය ගැන අපි සැලකිලිමත් නැහැ.අපි සැලකිලිමත් වන්නේ එය ඉංජිනේරු භාවිතා කළ හැකිද, එය පරීක්ෂා කළ යුතු රේඛා කීයක්ද, එය ප්රවාහ කළ යුතු දත්ත කීයක්ද යන්නයි.