<?xml version="1.0"?>
<rss version="2.0"><channel><title>DevOps: PostgreSQL</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/?d=4</link><description>DevOps: PostgreSQL</description><language>ar</language><item><title>&#x628;&#x62F;&#x621; &#x627;&#x644;&#x639;&#x645;&#x644; &#x645;&#x639; PostgreSQL</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-postgresql-r494/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_04/60716adcc79e5_---PostgreSQL.png.48efd364beff40c5483ed29d0b9edc4d.png" /></p>

<h2 id="-">
	التثبيت
</h2>

<p>
	تحتاج إلى تثبيت PostgreSQL قبل البدء باستخدامه، ومن الممكن أن يكون مُثبّتًا بالفعل على موقعك، إما لأنه مُضمّن في نظام التشغيل أو لأن مدير النظام قد ثبته مسبقًا، وفي هذه الحالة عليك الحصول على معلومات حول كيفية الوصول إليه إما من توثيق نظام التشغيل أو من مدير النظام.
</p>

<p>
	يمكنك تثبيت PostgreSQL بنفسك إذا لم تكن متأكد من أنه متاح فعلًا أو أنك تستطيع استخدامه في تجربتك، والقيام بذلك ليس صعبًا، ويستطيع أي شخص لا يتمتع بأية امتيازات تثبيته. وإذا قمت بتثبيته بنفسك، راجع مقال «<a data-ss1618321304="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-postgres-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%AA%D9%87%D8%A7-%D9%84%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r472/" rel="">تثبيت Postgres والتعرف على أساسيات إدارتها لقواعد البيانات</a>» لمزيد من المعلومات حول كيفية التثبيت، ثم عُد إلى هذا الدليل بعد اكتمال التثبيت. تأكد تمامًا من متابعة جزء إعداد متغيرات البيئة المناسبة.
</p>

<p>
	عليك القيام بأعمال إضافية إذا لم يقم مدير الموقع بإعداد بعض الأشياء بالطريقة الافتراضية، مثلًا، إذا كان خادم قاعدة البيانات آلةً بعيدةً متصلةً بشبكة أخرى، فيجب وضع اسم هذا الخادم كقيمة لمتغير البيئة PGHOST. وقد يحتاج متغير البيئة PGPORT إلى تهيئة أيضًا.
</p>

<p>
	باختصار، إذا قمت بتشغيل تطبيقك، وظهرت مشكلة عدم القدرة على الاتصال بقاعدة البيانات، يجب أن تستعين بمدير موقعك، أو إذا كنت أنت المدير، راجع التوثيق للتأكد من إعداد بيئتك بشكل صحيح، وإذا لم تفهم الفقرة السابقة، اقرأ القسم التالي.
</p>

<h2 id="-">
	الأساسيات البنيوية
</h2>

<p>
	يجب أن تفهم البنية الأساسية لنظام PostgreSQL قبل المضي في هذا الفصل، حيث أن فهم طريقة تفاعل أجزاء النظام مع بعضها سيجعل هذا الفصل أكثر وضوحًا.
</p>

<p>
	تستخدم PostgreSQL نموذج عميل/خادم. تتألف جلسة PostgreSQL من العمليات أو البرامج التالية:
</p>

<ul>
<li>
		عملية الخادم، وهي التي تدير ملفات قاعدة البيانات، وتقبل اتصال تطبيقات العميل بقاعدة البيانات، وتنفذ إجراءات قاعدة البيانات نيابةً عن العميل، ويدعى برنامج الخادم باسم postgres.
	</li>
	<li>
		تطبيق العميل، وهو الواجهة الأمامية التي تَوَد تنفيذ عمليات قاعدة البيانات. تتنوع تطبيقات العميل في طبيعتها، يمكن أن تكون أداة موجهة للنصوص، أو تطبيقًا رسوميًا، أو خادم ويب يصل إلى قاعدة البيانات لعرض صفحات الويب، أو أداة مخصصة لصيانة قاعدة البيانات. بعض تطبيقات العميل توزع مع نظام PostgreSQL وأغلبها تُطوّر من قبل المستخدمين. من المعتاد أن تكون تطبيقات العميل/الخادم على مضيفين مختلفين، يتصلان عبر اتصال شبكة TCP/IP، يجب أن تضع هذا في الحسبان، لأن الملفات التي يمكن الوصول اليها على العميل يمكن ألا يتم الوصل إليها على خادم قاعدة البيانات، أو ربما يمكن الوصول إليها باستخدام اسم ملف مختلف.
	</li>
</ul>
<p>
	يستطيع خادم PostgreSQL التعامل مع عدة اتصالات من الزبائن وبنفس الوقت، حيث أنه يبدأ عملية جديدة لكل اتصال، ومن هذه النقطة يتواصل العميل مع عملية الخادم الجديدة بدون تدخل عملية postgres الأساسية، ولذلك فإن عملية الخادم الأساسية تعمل بشكل مستمر، وتنتظر اتصالات العميل، بينما تأتي وتذهب عمليات العميل والخادم المرتبطة.
</p>

<h2 id="-">
	إنشاء قاعدة البيانات
</h2>

<p>
	إن محاولة إنشاء قاعدة البيانات هو أول اختبار لمعرفة فيما إذا كنت تستطيع الوصول إلى خادم قواعد البيانات.
</p>

<p>
	يستطيع خادم PostgreSQL إدارة العديد من قواعد البيانات، يوجد عادةً قاعدة بيانات منفصلة لكل مشروع أو لكل مستخدم. من المحتمل أن يُنشِئ مدير موقعك قاعدة بياناتك، وفي هذه الحالة تتجاوز هذه الخطوة إلى الخطوة التي تليها. لإنشاء قاعدة بيانات جديدة باسم mydb نستخدم الأمر التالي:
</p>

<pre class="ipsCode">
<code><span class="hljs-variable">$ </span>created mydb
</code></pre>

<p>
	تكون هذه الخطوة ناجحة إذا لم ينتج أي استجابة، وفي هذه الحالة تستطيع تجاوز بقية هذا القسم. أما إذا رأيت رسالة كالتالي:
</p>

<pre class="ipsCode">
<code>Createdb: <span class="hljs-keyword">command</span> <span class="hljs-title">not</span> <span class="hljs-title">found</span>
</code></pre>

<p>
	فهذا يعني أنه لم يتم تثبيت Postgres بدقة، فإما أنه لم يتم تثبيته على الإطلاق، أو أنه لم يتم إعداد مسار بحث الصدَفة (shell) بحيث يتضمنه، وفي هذه الحالة اكتب الأمر مع المسار الكامل كالتالي:
</p>

<pre class="ipsCode">
<code>$ <span class="hljs-regexp">/usr/</span>local<span class="hljs-regexp">/pgsql/</span>bin<span class="hljs-regexp">/created mydb</span>
</code></pre>

<p>
	ربما يكون مسار موقعك مختلفًا، لذلك اتصل بمدير الموقع أو تفحّص تعليمات التثبيت من أجل التصحيح. إذا كانت الاستجابة بالشكل التالي:
</p>

<pre class="ipsCode" id="ips_uid_6708_7">
Created: could not connect to database postgres : could not connect to server : No such file or directory 
Is the server running locally and accepting connections on Unix domain socket "/tmp/ .s.PGSQL.5432"?
</pre>

<p>
	هذا يعني أنه لم يتم تشغيل الخادم بعد، أو أنه لم يكن قد بدأ عندما توقع الأمر created أنه قد بدأ، وفي هذه الحالة أيضا يجب مراجعة تعليمات التثبيت أو استشارة مدير النظام. وإذا كانت الاستجابة بهذا الشكل:
</p>

<pre class="ipsCode">
<code>Created: could <span class="hljs-keyword">not</span> connect <span class="hljs-keyword">to</span> database postgres:  FATAL:   role <span class="hljs-string">"joe"</span> <span class="hljs-keyword">does</span> <span class="hljs-keyword">not</span> exist
</code></pre>

<p>
	حيث يُذكر اسم المستخدم الخاص بك. يحدث هذا عندما لا يُنشِئ المدير حساب مستخدم خاص بك، حيث أن حسابات مستخدمي Postgres مختلفة عن حسابات مستخدمي نظام التشغيل.
</p>

<p>
	فإذا كنت المدير، انظر إلى الفصل 21 للمساعدة في إنشاء حسابات المستخدمين، ولإنشاء أول حساب مستخدم يجب أن تكون مستخدم نظام التشغيل الذي نُصّب Postgres عليه.
</p>

<p>
	وربما تكون المشكلة هي اختلاف اسم مستخدم Postgres الخاص بك عن اسم مستخدم نظام التشغيل الخاص بك أيضًا، وفي هذه الحالة تحتاج استخدام الراية ‎-U، أو تعيين اسم مستخدم Postgres الخاص بك كقيمة لمتغير البيئة PGUSER.
</p>

<p>
	إذا كان لديك حساب مستخدم بدون صلاحية إنشاء قاعدة بيانات سترى الرسالة التالية:
</p>

<pre class="ipsCode">
<code><span class="hljs-string">Created:</span> database creation <span class="hljs-string">failed:</span>  <span class="hljs-string">ERROR:</span>  permission denied to create database
</code></pre>

<p>
	إذا حدث هذا يجب عليك استشارة مدير الموقع، لأنه ليس جميع المستخدمين مصرّح لهم بإنشاء قواعد بيانات جديدة، وبالتالي يجب أن يمنحك مدير موقعك صلاحية إنشاء قواعد بيانات إذا لم تتمكن من ذلك.
</p>

<p>
	يجب عليك تسجيل الدخول من حساب المستخدم الذي شغّل الخادم إذا قمت بتثبيت Postgres بنفسك.
</p>

<p>
	يمكنك إنشاء قواعد بيانات بأسماء أخرى، حيث يسمح Postgres بأي عدد من قواعد البيانات للموقع المُعطى.
</p>

<p>
	يجب أن تبدأ أسماء قواعد البيانات بحرف وألا يتجاوز طولها 63 بايت. وإنشاء قاعدة بيانات بنفس اسم المستخدم الخاص بك هو الخيار الأفضل، حيث تفترض عدة أدوات اسم افتراضي لقاعدة البيانات، لذلك يمكن استخدام الأمر كما يلي:
</p>

<pre class="ipsCode">
<code><span class="hljs-variable">$ </span>created
</code></pre>

<p>
	يمكنك حذف قاعدة البيانات إذا كنت لا تريد أن يستخدمها أحد، فإذا كنت مُنشئ قاعدة البيانات mydb يمكنك تدميرها باستخدام الأمر:
</p>

<pre class="ipsCode">
<code><span class="hljs-variable">$ </span>dropdb mydb
</code></pre>

<p>
	اسم قاعدة البيانات في هذا الأمر ليس افتراضيًا، حيث تحتاج دائمًا لتحديده، هذا الأمر يحذف كل الملفات المرتبطة بقاعدة البيانات، لذلك يجب تنفيذه بحذر شديد.
</p>

<p>
	يمكنك الحصول على المزيد من المعلومات حول إنشاء وحذف قواعد البيانات بالرجوع إلى المقال «<a data-ss1618321304="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B5%D8%AF%D9%81%D8%A9-psql-r473/" rel="">أساسيات استخدام صدفة psql</a>» والمقال الذي يليه «<a data-ss1618321304="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-sql-%D9%81%D9%8A-postgres-r474/" rel="">استخدام أساسيات SQL في Postgres</a>».
</p>

<h2 id="-">
	الوصول إلى قاعدة البيانات
</h2>

<p>
	تستطيع الوصل إلى قاعدة البيانات بمجرد إنشاءها، وذلك عن طريق:
</p>

<ul>
<li>
		تشغيل البرنامج الطرفي التفاعلي والذي يُدعى psql، والذي يسمح بإدخال وتعديل وتنفيذ أوامر SQL.
	</li>
	<li>
		استخدام أداة الواجهة الأمامية الرسومية، مثل pgAdmin، أو تركيبة مكتبية تدعم اتصال قاعدة بيانات مفتوح(ODBC) أو اتصال قاعدة بيانات يستخدم لغة جافا (JDBC)، وذلك من أجل إنشاء قاعدة البيانات والتعامل معها. لن نتحدث في الفصل عن هذه الإمكانيات.
	</li>
	<li>
		كتابة تطبيق مخصص يستخدم واحدة من روابط اللغة المتاحة.
	</li>
</ul>
<p>
	يتم تشغيل واجهة psql من أجل قاعدة البيانات mydb باستخدام الأمر:
</p>

<pre class="ipsCode">
<code><span class="hljs-variable">$ </span>psql mydb
</code></pre>

<p>
	إذا لم تضع اسم قاعدة البيانات سيتم أخذ القيمة الافتراضية المساوية لاسم المستخدم الخاص بحسابك، وسيتم استقبالك في psql بالرسالة التالية:
</p>

<pre class="ipsCode">
<code>Psql (13.1)
Type <span class="hljs-string">"help"</span> <span class="hljs-keyword">for</span> <span class="hljs-built_in">help</span>
Mydb=&gt;
ويمكن أن يكون السطر الأخير بالشكل التالي:
Mydb=<span class="hljs-comment">#</span>
</code></pre>

<p>
	يعني هذا أنك مدير قاعدة البيانات، وسيحدث هذا إذا قمت بتثبيت Postgres بنفسك، كونك مدير قاعدة البيانات يعني أنك لست خاضعًا للتحكم بالوصول. هذا ليس مهمًا هنا.
</p>

<p>
	إذا واجهت مشكلة في تشغيل psql راجع القسم السابق، حيث أن تشخيص مشاكل إنشاء قواعد البيانات createdb وتشغيل واجهة psql واحد، وإذا نجحت العملية الأولى ستنجح الثانية.
</p>

<p>
	آخر سطر طُبِع باستخدام psql هو الموجّه، ويشير إلى أن psql يصغي لك وبإمكانك كتابة استعلامات SQL في مساحة عمل مُصانة من قبل psql، حاول كتابة هذه الأوامر:
</p>

<pre class="ipsCode">
<code><span class="hljs-meta">Mydb=&gt;</span><span class="clojure"> SELECT version()<span class="hljs-comment">;</span></span>
</code></pre>

<p>
	ناتج الأمر السابق:
</p>

<pre class="ipsCode">
<code background-color:="" rgb="">|version|
***
|postgreSQL <span class="hljs-number">13.1</span> on x86_64-pc-linux-gnu، compiled by GCC (Debian <span class="hljs-number">4.9</span><span class="hljs-number">.2</span><span class="hljs-number">-10</span>) <span class="hljs-number">4.9</span><span class="hljs-number">.2</span>، <span class="hljs-number">64</span>-bit|
 (<span class="hljs-number">1</span> row)
</code>{&gt;</pre>

<pre class="ipsCode">
<code><span class="hljs-attribute">Mydb</span>=&gt; SELECT current_date<span class="hljs-comment">;</span>
</code></pre>

<p>
	ناتج الأمر السابق:
</p>

<pre class="ipsCode">
<code>|Date|
***
<span class="hljs-number">2016</span><span class="hljs-number">-01</span><span class="hljs-number">-07</span>||

(<span class="hljs-number">1</span> row)
</code></pre>

<pre class="ipsCode">
<code><span class="hljs-meta">Mydb=&gt;</span><span class="clojure"> SELECT <span class="hljs-number">2</span> + <span class="hljs-number">2</span><span class="hljs-comment">;</span></span>
</code></pre>

<p>
	ناتج الأمر السابق:
</p>

<pre class="ipsCode">
<code>|<span class="hljs-string">column</span>|
<span class="hljs-symbol">*</span><span class="hljs-symbol">*</span><span class="hljs-symbol">*</span>
|<span class="hljs-string">4</span>|
(1 row)
</code></pre>

<p>
	يوجد في برنامج psql عدة أوامر غير موجودة في SQL، تبدأ بالرمز <code>\</code>، مثلًا الحصول على مساعدة يتم بالشكل:
</p>

<pre class="ipsCode">
<code><span class="hljs-meta">Mydb=&gt;</span><span class="clojure"> \h</span>
</code></pre>

<p>
	وللخروج من برنامج psql نكتب :
</p>

<pre class="ipsCode">
<code><span class="hljs-meta">Mydb=&gt;</span><span class="clojure"> \q</span>
</code></pre>

<p>
	حيث سيتم الخروج من psql والعودة إلى الصدفة command shell.
</p>

<p>
	ننصحك بالرجوع إلى كتاب <a data-ss1618321304="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL</a> لمزيد من التفاصيل حول قواعد بيانات PostgreSQL.
</p>

<p>
	ترجمة وبتصرف لصفحات القسم <a data-ss1618321304="1" href="https://www.postgresql.org/docs/13/tutorial-install.html" rel="external nofollow">Getting Started</a> في موقع <a data-ss1618321304="1" href="https://www.postgresql.org/docs/current" rel="external nofollow">postgreSQL</a>
</p>
]]></description><guid isPermaLink="false">494</guid><pubDate>Tue, 13 Apr 2021 09:27:00 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x639;&#x646; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; PostgreSQL &#x648;&#x62A;&#x627;&#x631;&#x64A;&#x62E; &#x638;&#x647;&#x648;&#x631;&#x647;&#x627;</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-%D9%88%D8%AA%D8%A7%D8%B1%D9%8A%D8%AE-%D8%B8%D9%87%D9%88%D8%B1%D9%87%D8%A7-r493/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_04/60716855344fe_----PostgreSQL.png.66024600fafe819546b1b1a36b3c8576.png" /></p>

<p>
	قواعد بيانات PostgreSQL هي عبارة عن نظام لإدارة قواعد البيانات العلائقية الغرضية اعتمادًا على مشروع بيركلي <a data-ss1618320373="1" href="https://dsf.berkeley.edu/postgres.html" rel="external nofollow"><strong>بوستغرس</strong> (POSTGRES)، الإصدار 4.2</a>، الذي طُوِّر في قسم علوم الحاسوب في جامعة كاليفورنيا في مدينة بيركلي، حيث ابتكر <strong>بوستغرس</strong> (POSTGRES) العديد من المفاهيم المستخدَمة فقط في بعض أنظمة قواعد البيانات التجارية.
</p>

<p>
	يُعَدّ PostgreSQL مفتوح المصدر، وهو منحدر من شيفرة بيركلي الأصلي، كما يدعم جزءًا كبيرًا من معيار <strong>SQL</strong>، ويقدِّم العديد من المميزات، وهي:
</p>

<ul>
<li>
		الاستعلامات المعقدة؛
	</li>
	<li>
		المفاتيح الأجنبية؛
	</li>
	<li>
		القوادح (triggers)؛
	</li>
	<li>
		العروض القابلة للتعديل؛
	</li>
	<li>
		سلامة العمليات؛
	</li>
	<li>
		التحكم المتزامن متعدد النسخ.
	</li>
</ul>
<p>
	ويمكن توسيعها من قِبل المستخدِم بعِدة طرق، منها إضافة أشياء جديدة، مثل:
</p>

<ul>
<li>
		أنواع بيانات؛
	</li>
	<li>
		توابع؛
	</li>
	<li>
		معاملات؛
	</li>
	<li>
		توابع تجميع؛
	</li>
	<li>
		عمليات فهرسة؛
	</li>
	<li>
		لغات إجرائية.
	</li>
</ul>
<p>
	حيث يمكن لأيّ شخص استخدام (PostgreSQL) وتعديلها لأيّ غرض سواءً كان خاصًا، أو تجاريًا، أو أكاديميًّا. وذلك وفقًا للترخيص الليبرالي.
</p>

<h2 id="-postgresql">
	لمحة موجزة من تاريخ PostgreSQL
</h2>

<p>
	لقد اشتُقّ نظام إدارة قواعد البيانات العلائقية الغرضية المعروف باسم (PostgreSQL) من حزمة بوستغرس التي كُتِبت في جامعة كاليفورنيا في بيركلي. والآن، وبعد مضي أكثر من عقدين على تطويرها، فهي تُعَد قاعدة البيانات الأكثر تطورًا على الإطلاق.
</p>

<h3 id="-postgres-">
	مشروع POSTGRES في بيركلي
</h3>

<p>
	كان مشروع بوستغرس بقيادة البروفيسور مايكل ستون بريكر (Michael Stonebraker)، وتحت رعاية وكالة المشاريع البحثية المتطوِّرة للدفاع (DARPA)، ومكتب بحث الجيش (ARO)، ومؤسَّسة العلوم الوطنية (NSF)، وبرنامج الإنكليزية لغةً ثانية (ESL)، وغيرها. حيث بدأ تنفيذ بوستغرس عام 1986، وقد مُثِّلت المفاهيم الأولية للنظام في <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/biblio.html#STON86" rel="external nofollow">ston86</a>، كما ظهر تعريف النموذج الأولي للبيانات في <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/biblio.html#ROWE87" rel="external nofollow">rowe87</a>. وقد وُصِف تصميم النظام في ذلك الوقت في <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/biblio.html#STON87A" rel="external nofollow">ston87a</a>، أمّا الأساس المنطقي وبنية مدير التخزين فقد فُصلت في <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/biblio.html#STON87B" rel="external nofollow">ston87b</a>، لتُصدِر بوستغرس منذ ذلك الحين عدة إصدارات رئيسية، حيث شُغِّل أول نظام ديمووير (demoware) في عام 1987، ليظهر في مؤتمر (ACM-SIGMOD) عام 1988. 
</p>

<p>
	وقد وُصِف الإصدار الأول في <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/biblio.html#STON90A" rel="external nofollow">ston90a</a>، والذي أُطلِق لعدد قليل من المستخدمين الخارجيين في حزيران عام 1989. وردًا على نقد أول نظام <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/biblio.html#STON89" rel="external nofollow">ston1989</a>، فقد أُعيد تصميم النظام <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/biblio.html#STON90B" rel="external nofollow">ston90b</a><a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/biblio.html#STON90B)%D8%8C" rel="external nofollow">،</a> وإطلاق الإصدار الثاني في حزيران 1990 مع النظام الجديد؛ أمّا الإصدار الثالث فقد ظهر عام1991، وأضاف دعمًا لعدة مدراء تخزين، ولمُنفِّذ استعلام محسّن، ولإعادة كتابة النظام؛ لتُركِِّز الإصدارات اللاحقة حتى بوستغرس 95 (Postgres95) على قابلية النقل والموثوقية.
</p>

<p>
	استُخدِمَت بوستغرس لتنفيذ تطبيقات العديد من مشاريع البحث والإنتاج، وتتضمن هذه الأخيرة تحليل بيانات مالية، وحزمة مراقبة أداء محرِّك الطائرة النفاثة، وقاعدة بيانات تتَّبع الكويكبات، وقاعدة بيانات معلومات طبية، والعديد من أنظمة المعلومات الجغرافية. كما استُخدمت بوستغرس مثل أداة تعليمية في العديد من الجامعات.
</p>

<p>
	وفي النهاية، أخذت تقنيات معلومات الوسترا (Illustra) التي دُمِجت مؤخَّرًا مع <a data-ss1618320373="1" href="https://www.ibm.com/analytics/Informix" rel="external nofollow">Informix</a> التي تملكها شركة <a data-ss1618320373="1" href="https://www.ibm.com/" rel="external nofollow">IBM</a> بأخذ الشيفرة وتسويقها، ليُصبح مشروع بوستغرس في عام 1992، مديرًا للبيانات الرئيسي لـ <a data-ss1618320373="1" href="http://meteora.ucsd.edu/s2k/s2k_home.html" rel="external nofollow">Sequoia 2000 scientific computing project</a>.
</p>

<p>
	وفي سنة 1993، تضاعف حجم المستخدمين الخارجيين، وأصبح جليًا أنّ صيانة النموذج الأولي للشيفرة والدعم، ستستغرق وقتًا طويلًا كان من الممكن استغلاله في بحوث قواعد البيانات، وانتهى مشروع بيركلي بالإصدار 4.2 في محاولة لتقليل عبء الدعم.
</p>

<h3 id="postgres-95">
	Postgres 95
</h3>

<p>
	أضاف أندرو يو (Andrew Yu) وجولي تشين (Jolly Chen)، مُفسّر (SQL) إلى بوستغرس عام 1994، حيث أُطلِق إلى الويب باسم "بوستغرس 95"، ليجد طريقه في العالم خلَفًا لشيفرة بيركلي الأصلية .
</p>

<p>
	اعتمدت شيفرة "بوستغرس 95" كليًّا على لغة البرمجة <strong>سي</strong> (C) التي نُشِرت من قِبل المعهد الوطني الأمريكي للمعايير (ANSI)، والتي قُلِِّصت إلى 25%. حيث كان هناك عدة تغييرات حسّنت من الأداء، وقابلية الصيانة. فقد كان الإصدار 1.0x أسرع من 30-50% على مقياس ويسكونسن بينتشمارك (Wisconsin Benchmark) بالموازنة مع بوستغرس 4.2. وبصرف النظر عن إصلاح الأخطاء، فقد كانت التحسينات التالية هي التحسينات الرئيسية :
</p>

<ul>
<li>
		استُبدِلت لغة الاستعلام (PostQUEL) بلغة (SQL) (التي تُنفَّذ في الخادم)، وسُميت مكتبة الواجهة <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/libpq.html" rel="external nofollow">libpq</a>، بعد PostQUEL. كما لم تدعَم بعض الاستعلامات الجزئية حتى (PostgreSQL)، ولكن كان يمكن تقليدها في "بوستغرس 95" من خلال توابع (SQL) المُعَرّفة من قِبل المستخدِم، إلى جانب إعادة تنفيذ عملية إضافة توابع التجميع، إلى جانب إضافة دعم لعبارة الاستعلام (GROUP BY) .
	</li>
	<li>
		زُوِّدت ببرنامج جديد (psql) من أجل استعلامات (sql) التفاعلية، حيث تستخدم قراءة الترخيص العام (GPL) الذي حلّ مكان برنامج الشاشة القديم.
	</li>
	<li>
		دُعِمت مكتبة جديدة للواجهة الأمامية، وهي مكتبة (libpgtcl)، التي تعتمد على تقنية (TCL). حيث زُوِّد (pgtclsh) بأوامر (TCL)،وذلك لمقابلة برامج (TCL)مع خادم "بوستغرس 95".
	</li>
	<li>
		أُصلِحت واجهة الكائنات الكبيرة، فقد كانت الطريقة الوحيدة لتخزين الأشياء الكبيرة هي الكائنات الكبيرة المعكوسة (حيث حُذِف نظام الملفات المعكوس).
	</li>
	<li>
		أُزيل نظام مستوى النسخة (instance-level)، كانت القواعد لا تزال متوفرة مثل قواعد إعادة الكتابة.
	</li>
	<li>
		وُزِّع برنامج تعليمي مختصر يقدم ميزات SQL العادية مع ميزات بوستغرس 95 في شيفرة المصدر.
	</li>
	<li>
		استُخدِمَ الترخيص العام (GNU) بدلًا من توزيع برمجيات بيركلي (BSD) في البناء، حيث يمكن أن تُصرّف بوستغرس 95 باستخدام مجموعة مُصرّف ترخيص عام (GCC) غير مصحح (أُصلِحت محاذاة الأعداد العشُرية مضاعفة الدقّة).
	</li>
</ul>
<h3 id="postgresql">
	PostgreSQL
</h3>

<p>
	اختير اسم جديد في عام 1996 وهو PostgreSQL، وذلك ليعكس العلاقة بين مشروع بوستغرس الأساسي، والاصدارات الحديثة المدمجة مع امكانيات (SQL)، حيث بدأ ترقيم الإصدارات من 6.0، وذلك كي تعود الأرقام إلى السلسلة الأصلية كما كان الحال في مشروع بيركلي. وأُشير إلى PostgreSQL باسم Postgres كاسم مستعار لسهولة اللفظ. كان التركيز خلال تطوير بوستغرس 95 على تحديد وفهم المشكلات الموجودة في شيفرة الخادم، بينما تحول التركيز في PostgreSQL إلى زيادة المميزات والقدرات على الرغم من استمرار العمل في جميع المجالات. يمكن العثور على مزيد من التفاصيل حول ما حدث في PostgreSQL في <a data-ss1618320373="1" href="https://www.postgresql.org/docs/13/release.html" rel="external nofollow">Appendix E</a>.
</p>

<h2 id="-">
	الأعراف
</h2>

<p>
	استخدِمت الأعراف التالية في اختصار الأوامر:
</p>

<ul>
<li>
		الأقواس (<code>[ ]</code>) تشير إلى أجزاء اختيارية، واستخدمت اشارة الاستفهام (<code>?</code>) بدلًا منها في اختصار أمر TCI
	</li>
	<li>
		الأقواس (<code>{ }</code>) و الخط العمودي (<code>|</code>) تشير إلى أنك يجب أن تختار أحد الاختيارات.
	</li>
	<li>
		النقاط (<code>…</code>) تعني أنه من الممكن تكرار العنصر السابق.
	</li>
</ul>
<p>
	وبينما كانت تزيد الوضوح، فقد سُبقت أوامر SQL ب <code>&lt;=</code>، وسُبقت أوامر الصدفة بالرمز<code>$</code> ، ومع ذلك فإنها لا تُرى.
</p>

<p>
	المدير بشكل عام، هو الشخص الذي يقوم بتثبيت الخادم وتشغيله. والمستخدم يمكن أن يكون أي شخص يستخدم أو يريد أن يستخدم أي جزء من نظام PostgreSQL.
</p>

<h2 id="-">
	المزيد من المعلومات
</h2>

<p>
	هناك العديد من مصادر المعلومات العربية حول PostgreSQL وفرتها أكاديمية حسوب وموسوعة حسوب وهي:
</p>

<ul>
<li id="-">
		<a data-ss1618320373="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/" rel="">قسم PostgreSQL في أكاديمية حسوب</a>: يحوي القسم على الكثير من المقالات المفيدة النافعة حول مختلف المواضيع المتعلقة بقواعد بيانات PostgreSQL.
	</li>
	<li>
		<a data-ss1618320373="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">كتاب الدليل العملي إلى قواعد بيانات PostgreSQL</a>: كتاب عملي بسيط يشرح قواعد بيانات PostgreSQL من الصفر بدءًا ويغطي أغلب حالات استعمال قواعد البيانات والأوامر فيها.
	</li>
	<li>
		<a data-ss1618320373="1" href="https://wiki.hsoub.com/SQL" rel="external">توثيق SQL في موسوعة حسوب</a>: توثيق كامل شامل للغة SQL يحوي فيه أي ملاحظات أو تفاصيل متعلقة بقواعد بيانات PostgreSQL أهمها موضوع التوافيقة.
	</li>
	<li>
		 <a data-ss1618320373="1" href="https://academy.hsoub.com/files/16-%D9%85%D9%84%D8%A7%D8%AD%D8%B8%D8%A7%D8%AA-%D9%84%D9%84%D8%B9%D8%A7%D9%85%D9%84%D9%8A%D9%86-%D8%A8%D9%84%D8%BA%D8%A9-sql/" rel="">ملاحظات للعاملين بلغة SQL</a>: كتاب متقدم بعض الشيء يتحدث حول لغة SQL بأسلوب يتوقع من القارئ أن يكون عارفًا لأساسيات لغة SQL العامة التي يمكن استعمالها مع قواعد بيانات PostgreSQL. 
	</li>
</ul>
<p id="-">
	ترجمة -وبتصرف- لصفحات القسم <a data-ss1618320373="1" href="https://www.postgresql.org/docs/current/preface.html" rel="external nofollow">Preface</a> في موقع <a data-ss1618320373="1" href="https://www.postgresql.org/docs/current" rel="external nofollow">postgreSQL</a>
</p>
]]></description><guid isPermaLink="false">493</guid><pubDate>Tue, 06 Apr 2021 08:57:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x631;&#x62C;&#x639; &#x627;&#x644;&#x634;&#x627;&#x645;&#x644; &#x625;&#x644;&#x649; &#x62A;&#x639;&#x644;&#x645; PostgreSQL</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-postgresql-r481/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/Postgres-toturial.png.e04c4086b16b19d176f0d83fccdcaa0f.png" /></p>
<p>
	PostgreSQL – تُعرَف أيضا بـ Postgres – هي نظام مفتوح المصدر لإدارة قواعد البيانات. تُستخدم لتخزين البيانات مهما كان حجمها، وتتميز بكفائتها وأدائها العالي وغناها بالميزات والوظائف. تُعد PostgreSQL أفضل أنظمة قواعد البيانات مفتوحة المصدر وأكثرها شعبية على مستوى العالم.
</p>

<p>
	هل تريد أن تتعلم PostgreSQL ولكن لا تعرف من أين تبدأ؟ لقد جئت إلى المكان الصحيح. هذا المرجع هو دليلك الشامل إلى تعلم PostgreSQL، إذ يستعرض عددًا كبيرا من الدروس العربية الممتازة التي ستتعلم فيها أساسيات PostgreSQL، علاوة على الكثير من الدروس التطبيقية المتقدمة.
</p>

<h2>
	تاريخ PostgreSQL
</h2>

<p>
	ظهرت PostgreSQL سنة 1982، وكانت نتيجة لمشروع Ingres في جامعة كاليفورنيا. ثمّ قرر قائد فريق العمل في مشروع Ingres إنشاء نسخة تجارية منها، وبدأ مشروع post-Ingres (أي <strong>ما بعد Ingres</strong>)، لهذا هناك من يسميها Postgres.
</p>

<p>
	انكبّ العاملون في مشروع post-Ingres على تطويرها وإضافة الكثير من المزايا المهمة إليها. وقد خرج الإصدار الأول منها سنة 1989، ثم توالت الإصدارات وتزايدت شعبيتها وعدد مستخدميها باطراد. عرفت سنة 1994 حدثا مهما لمستخدمي Postgres، وهو أنّها أصبحت تُوزَّع وفق رخصة MIT الحرة والمجانية، وهذا أدى إلى إقبال المزيد من المطورين للمساهمة في تطوير Postgres والتعديل عليها بحرِّية.
</p>

<p>
	أعيدت تسمية Postgres سنة 1996 ليصبح PostgreSQL للدلالة على دعمها للغة الاستعلامات البنيوية SQL.
</p>

<h2>
	فيما تُستخدَم PostgreSQL؟
</h2>

<p>
	تُستخدم PostgreSQL في العديد من المجالات، سواء في القطاع الأكاديمي أو التجاري. يبين المبيان التالي أكبر عشر مجالات تُستخدم فيها PostgreSQL:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52799" href="https://academy.hsoub.com/uploads/monthly_2020_11/postgresql_industry.png.77f806c46a5a8295fe654fba6d714fff.png" rel="" data-fileext="png"><img alt="postgresql_industry.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52799" data-unique="vayseyx5w" src="https://academy.hsoub.com/uploads/monthly_2020_11/postgresql_industry.thumb.png.4667cf709ded5f77b4ded2a4d89219e4.png"></a>
</p>

<p style="text-align: center;">
	<em><a href="https://enlyft.com/tech/products/postgresql" rel="external nofollow" target="_blank">مصدر</a> الصورة</em>
</p>

<p>
	يوضح المبيان تنوع استخدامات PostgreSQL في مختلف القطاعات، خصوصا في مجالي البرمجيات وتقنيات المعلومات، علاوة على القطاعات الصحية والمالية والتعليم والتسويق. وهذا ناتج عن طبيعة PostgreSQL، فهي مفتوحة المصدر، ما يجعلها مرنة وقابلة للتطوير والتوسيع والتخصيص. إضافة إلى ذلك فهي آمنة وموثوقة تضاهي أنظمة قواعد البيانات المدفوعة، ما يجعلها مثالية للشركات والمشاريع في مختلف المجالات. يُقدّر عدد الشركات التي تستخدم PostgreSQL بحوالي 48500 شركة <a href="https://enlyft.com/tech/products/postgresql" rel="external nofollow" target="_blank">[1]</a>. ومن أشهر هذه الشركات Apple وDebian و Sun Microsystem و Skype وغيرها.
</p>

<h2>
	لماذا PostgreSQL؟
</h2>

<p>
	توفر PostgreSQL العديد من الميزات المهمة والمفيدة التي تجعلها خيارًا مثاليا للمطورين وأصحاب المشاريع. وهذه بعضها:
</p>

<ol>
	<li>
		<p>
			<strong>مفتوحة المصدر ومجانية</strong>: هذا يعنى أنّه يمكنك استخدامها بدون أيّ تكاليف أو رسوم، كما يمكنك التعديل عليها بحرّية.
		</p>
	</li>
	<li>
		<p>
			<strong>قابلة للتخصيص</strong>: أحد مزايا البرامج مفتوحة المصدر أنّها تعطيك حرية كبيرة وتحكمًا عميقًا في البرامج. و PostgreSQL ليست استثناء، إذ تتمتع بمرونة كبيرة، فهي تتيح مثلًا تعريف أنواع بيانات جديدة وتعريف دوال مُخصّصة. كما أنّها متكاملة مع العديد من لغات البرمجة الأخرى.
		</p>
	</li>
	<li>
		<p>
			<strong>تعدد أنواع البيانات</strong>: تدعم PostgreSQL الكثير من أنواع البيانات، سواء العددية أو النصية أو المنطقية. علاوة على البيانات المركبة، مثل المصفوفات والمجالات والتواريخ والبيانات الهندسية و تنسيقات الملفات، بما فيها JSON و XML و CSV.
		</p>
	</li>
	<li>
		<p>
			<strong>التوافق مع مواصفات SQL</strong>: تتوافق PostgreSQL مع معظم مواصفات SQL، إلا أنّها لا تلتزم بها حرفيا، فمطورو PostgreSQL يخالفون أحيانا مواصفات SQL إن كانت تتعارض مع الميزات التقليدية التي تتيحها PostgreSQL، أو إن وجدوا حلولًا أفضل.
		</p>
	</li>
	<li>
		<p>
			<strong>دعم جميع اللغات</strong>: تدعم PostgreSQL جميع اللغات العالمية، بما فيها اللغة العربية.
		</p>
	</li>
	<li>
		<p>
			<strong>متعدد المنصات</strong>: PostgreSQL متعددة المنصات، ويمكن أن تستخدمها على جميع أنظمة التشغيل المشهورة، بما فيها نظام ويندوز ويونيكس وماك و Solaris و BSD.
		</p>
	</li>
	<li>
		<p>
			<strong>البحث والتنقيب</strong>: تدعم PostgreSQL تشكيلة كبيرة من التعابير النمطية (regex)، ما يجعلها مثالية للبحث والتنقيب في البيانات وتحليلها.
		</p>
	</li>
	<li style="text-align: center;">
		<p>
			<strong>الشعبية</strong>: PostgreSQL هي أكثر قواعد البيانات مفتوحة المصدر شعبية على صعيد العالم، والثانية من بين جميع أنظمة قواعد البيانات كما يشير آخر استطلاع لموقع <a href="https://insights.stackoverflow.com/survey/2020" rel="external nofollow" target="_blank">stackoverflow</a>:
		</p>

		<p style="text-align: center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52690" href="https://academy.hsoub.com/uploads/monthly_2020_11/Stack-Overflow-Developer-Survey-2020.png.060cc7ba462b406eae9dc0c57a54808e.png" rel="" data-fileext="png"><img alt="Stack-Overflow-Developer-Survey-2020.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52690" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_11/Stack-Overflow-Developer-Survey-2020.png.060cc7ba462b406eae9dc0c57a54808e.png"></a>
		</p>
		<em>أكثر قواعد البيانات شعبية على صعيد العالم.</em>
	</li>
	<li>
		<p>
			<strong>محبوبة من المطورين</strong>: في الاستطلاع نفسه، حلت PostgreSQL في المرتبة الثانية في قائمة أحب أنظمة قواعد البيانات إلى المطورين.
		</p>
	</li>
</ol>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52691" href="https://academy.hsoub.com/uploads/monthly_2020_11/Stack-Overflow.png.71e91690cf63da5050fdd9686fb2936f.png" rel="" data-fileext="png"><img alt="Stack-Overflow.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52691" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_11/Stack-Overflow.png.71e91690cf63da5050fdd9686fb2936f.png"></a>
</p>

<p style="text-align: center;">
	<em>أكثر قواعد البيانات المحبوبة</em>
</p>

<ol start="10">
	<li>
		<strong>دعم أطر العمل</strong>: تدعم PostgreSQL أكثر من 80 إطار عمل، لذا لن تضطر على الأرجح لتعلم إطار عمل جديد، فمهما كان إطار العمل الذي تعمل به، فعلى الغالب أنّها تدعمه.
	</li>
	<li>
		<strong>التزامن</strong>: نظام PostgreSQL متزامن، إذ أنّه يمنح لكل عملية نسخة أو عينة من قاعدة البيانات، وهذا يتيح القيام بعدة عمليات على قاعدة البيانات دون أن تتداخل فيما بينها.
	</li>
</ol>

<p>
	هل تريد أن تتعلم PostgreSQL بسرعة وسهولة لاستخدامها في تطبيقاتك وبرامجك؟ سوف نستعرض فيما بقي من هذا الدليل مجموعة متنوعة من المقالات والدروس العربية المتكاملة التي تجمع بين الجانبين النظري والعملي.
</p>
<style type="text/css">
@media screen and (min-width: 650px) {
.response_image {
    width: 33%;
    display: inline-block;
    vertical-align: top;
    margin-top: 0px;
}

.response_descrip {
    width: 64%;
    display: inline-block;
    margin-right: 10px;
    vertical-align: top;
    margin-top: 0px;
}
}</style>
<h2>
	سلسلة "دليل postgreSQL العملي"
</h2>

<p>
	لا يخفى على أحد أنّ هناك ضعفا في المكتبة العربية في كل المجالات العلمية والتقنية. خصوصا في مجال البرمجة والتطوير، فهي مجالات متغيرة باستمرار، فسنة واحدة في مجال البرمجة كمثل عشر سنوات في المجالات الأخرى، ففي كل عام تظهر تقنيات وإصدارات جديدة. لأجل هذا أطلقت أكاديمية حسوب مشروعًا طموحا لتوفير العديد من المواد التعليمية الممتازة في مختلف المجالات التقنية، سواء مقالات أو دروسًا أو كتبًا. من ثمار هذا المشروع إعداد أحد أفضل المواد التعليمية العملية المتاحة لتعليم PostgreSQL، المبني على سلسلة مقالات <a href="http://postgresguide.com/" rel="external nofollow" target="_blank">Postgres Guide</a>.
</p>

<p>
	يأخذ هذا الدليل بيدك في أمثلة عملية ومتنوعة تغطي أساسيات SQL وأساسيات إدارة قواعد بيانات PostgreSQL، وتمر على مزايا مهمة في PostgreSQL تزيد من فاعلية الاستعلامات ووضوح عبارتها، ويصل هذا الدليل إلى مواضيع متقدمة في إدارة قواعد البيانات كالنسخ الاحتياطي وتتبع استخدام الذاكرة، وبذلك يتميز بأنه مناسب للمبتدئ والمتوسط ويضع قدمك على سكة المستوى المتقدم في قواعد بيانات PostgreSQL.
</p>

<p>
	فما يميزه عن غيره، فهو أننا اتبعنا في بداية العمل على هذا الدليل قاعدة باريتو 80/20، حيث حرصنا على تغطية 20% من مواضيع Postgres التي تُستخدَم في 80% من الحالات في الواقع والمجال العملي، إذ حاولنا الابتعاد عن التفاصيل غير العملية أو قليلة الاستخدام، أي أن هذا الدليل لا يتطرق إلى شرح أو استخدام الأدوات المتقدمة والتي قد يندر استخدام بعضها (مذكورة في هذا القسم من التوثيق) ولا يتطرق أيضًا إلى كيفية تطوير Postgres بكتابة شيفرات برمجية خاصة (مذكورة في هذا القسم من التوثيق)، فلم نرد تعليمك شيئًا لن تستخدمه إلا في حالات قليلة (تكون قد نسيتها إلى حين استعمالها <span class="ipsEmoji">?</span> ).
</p>

<p>
	وفقًا لذلك، حاولنا جاهدين أن يكون هذا الدليل دليلًا عمليًا ومرجعًا سريعًا للمبرمج، يتعرف فيه على الجزء الأكثر أهمية مما قد يجهله عن قواعد بيانات Postgres ويختبر فيه في ذات الوقت معرفته بالمزايا المتنوعة لقواعد البيانات تلك. باختصار، صُمم ليكون رحلة ممتعة فعالة مليئة بالأمثلة المفيدة الواضحة في قواعد بيانات Postgres.
</p>

<p>
	يغطي هذا الدليل ما يلي:
</p>

<ul>
	<li>
		لمحة عن الأسس النظرية لقواعد البيانات
	</li>
	<li>
		تغطية فعالة لأساسيات استخدام لغة SQL عمليًّا
	</li>
	<li>
		تغطية شاملة لما تتميز به Postgres عن SQL الصرفة (أي لغة قواعد البيانات العامة)
	</li>
	<li>
		أساسيات إدارة قواعد بيانات Postgres (إدارة الذاكرة، الأداء، النسخ الاحتياطي وغيرها)
	</li>
	<li>
		أهم التعليمات اللازم معرفتها في صَدَفة psql (واجهة سطر الأوامر الخاصة بPostgres)
	</li>
</ul>

<p>
	في حال أردت أولًا التعمق في SQL، فننصحك بالبدء بسلسلة «<a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D9%82%D8%AF%D9%85-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-sql-r961/" rel="">المرجع المتقدم إلى لغة SQL</a>» أولًا فمعلوم أن لغة SQL هي اللغة الأم لقواعد بيانات SQL (ومنها Postgres)، فلن تجد هذا الدليل يتعمق كثيرًا في تعليمات SQL لأننا شرحناها بالتفصيل مسبقًا في تلك السلسلة. ننصحك بعد الانتهاء من هذا الدليل الانتقال إلى كتاب «<a href="https://itwadi.com/PostgreSQL_Cookbook" rel="external nofollow" target="_blank">بوستجريسكل كتاب الوصفات</a>» إن أردت التوسع أكثر في PostgreSQL، فتلك خارطة الطريق التي ننصحك بها لتعلم لغة SQL وقواعد بيانات PostgreSQL من الأساسيات وحتى الاحتراف.
</p>
<iframe allowfullscreen="" class="ipsEmbed_finishedLoading" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" data-embedid="embed2791447615" src="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/?do=embed" style="overflow: hidden;height: 473px;max-width: 502px;margin: auto;"></iframe>

<p>
	سوف نستعرض سلسلة مقالات هذا الدليل، وإن كنت تريد تحميله جملة واحدة على هيئة كتب رقمي، فيمكنك ذلك من <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">هنا</a>.
</p>

<h3>
	1. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D8%B9%D9%84%D9%89-postgres-%D9%88%D8%AA%D8%A7%D8%B1%D9%8A%D8%AE%D9%87%D8%A7-r471/" rel="">نظرة عامة على Postgres وتاريخها</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52692" href="https://academy.hsoub.com/uploads/monthly_2020_11/1.png.64f7d2ab17b71f67cd5a808d8d29af4b.png" rel="" data-fileext="png"><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52692" data-unique="lwatgxakb" src="https://academy.hsoub.com/uploads/monthly_2020_11/1.thumb.png.267952f0b04ff85e437b9d5456854fa8.png"></a>
</p>

<p class="response_descrip">
	تستعرض هذه المقالة مجموعة من المعارف التاريخية عن Postgres، وعن قواعد البيانات عموما منذ بداية ظهورها وحتى يومنا هذا. مع استعراض بعض مميزات Postgres وخصائصها ونماذج عملها.
</p>

<h3>
	2. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-postgres-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%AA%D9%87%D8%A7-%D9%84%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r472/" rel="">تثبيت Postgres والتعرف على أساسيات إدارتها لقواعد البيانات</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52693" href="https://academy.hsoub.com/uploads/monthly_2020_11/2.png.afe412ab541a64e49eecdbafc2b6f782.png" rel="" data-fileext="png"><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52693" data-unique="1i4jeow6k" src="https://academy.hsoub.com/uploads/monthly_2020_11/2.thumb.png.9d8d64ef0fef46a1df0847ac05d6e054.png"></a>
</p>

<p class="response_descrip">
	يقدم هذا المقال دليلًا شاملًا لأهم جوانب قواعد بيانات Postgres بدءًا من تنزيل التطبيقات اللازمة لإدارة قواعد البيانات وتثبيتها، وانتهاءً ببعض الجوانب المتقدمة في معالجة الجداول مرورًا بمعظم العمليات الأساسية لمعالجة البيانات ضمن قاعدة البيانات.
</p>

<h3>
	3. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B5%D8%AF%D9%81%D8%A9-psql-r473/" rel="">أساسيات استخدام صَدَفة psql</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52694" href="https://academy.hsoub.com/uploads/monthly_2020_11/3.png.8c81fcd867a0df0e4c884a00ad782e63.png" rel="" data-fileext="png"><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52694" data-unique="siph1ezw1" src="https://academy.hsoub.com/uploads/monthly_2020_11/3.thumb.png.b32dc371a2b4dcb8b164cc5ffbb0e44d.png"></a>
</p>

<p class="response_descrip">
	صدفة psql هي برنامج الواجهة التفاعلية للاتصال بـ Postgres، سوف نستعرض في هذه المقالة بعض أهم الأوامر المٌستخدمة في صدفة psql لاستعراض قواعد البيانات والجداول والمستخدمين وخصائصهم وتحرير الاستعلامات في محرر النصوص وغيرها.
</p>

<h3>
	4. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-sql-%D9%81%D9%8A-postgres-r474/" rel="">استخدام أساسيات SQL في Postgres</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52695" href="https://academy.hsoub.com/uploads/monthly_2020_11/4.png.fe355ed96837804735a50d7321c962be.png" rel="" data-fileext="png"><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52695" data-unique="gvil61qwj" src="https://academy.hsoub.com/uploads/monthly_2020_11/4.thumb.png.aee1d2d5aa3b2f5fe1e2592a31a5888f.png"></a>
</p>

<p class="response_descrip">
	تشرح هذه المقالة كيفية إنشاء وتعديل وحذف الجداول، كما تشرح كيفية إدخال البيانات فيها ثم الاستعلام عنها مع ترشيحها والاستفادة من العديد من الأوامر للحصول على المخرجات المطلوبة، وتتطرق إلى عمليات التجميع وتعرض بالأمثلة الواضحة طرق ربط الجداول للحصول على النتائج من مصادر متعددة.
</p>

<h3>
	5. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%85%D8%B2%D8%A7%D9%8A%D8%A7-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-postgres-r475/" rel="">مزايا متقدمة في Postgres</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52696" href="https://academy.hsoub.com/uploads/monthly_2020_11/5.png.7460c241aef263d1e1630dff2c761dc4.png" rel="" data-fileext="png"><img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52696" data-unique="3a7nq2p0c" src="https://academy.hsoub.com/uploads/monthly_2020_11/5.thumb.png.b3f343fef890924f0efa5b94ac8534c8.png"></a>
</p>

<p class="response_descrip">
	تستعرض هذه المقالة العرض View وتعابير الجداول الشائعة CTE التي تساهم في تحسين طريقة كتابة الاستعلامات، وذلك بجعلها أقصر وأسهل قراءةً، وتبين كيفية استخدام دوال النوافذ Window Functions التي تسمح بإجراء عمليات تجميعية على مجموعة جزئية من الأسطر، وتتطرق إلى الفهارس وأهميتها في تسريع البحث ضمن البيانات.
</p>

<h3>
	6. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%AE%D8%A7%D8%B5%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r476/" rel="">أنواع بيانات خاصة في قواعد بيانات Postgres</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52697" href="https://academy.hsoub.com/uploads/monthly_2020_11/6.png.599f29efdda010eaa69e0873847fe83b.png" rel="" data-fileext="png"><img alt="6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52697" data-unique="sptaokq7b" src="https://academy.hsoub.com/uploads/monthly_2020_11/6.thumb.png.9e1ae3e26d9b60ed42d661ba692b3978.png"></a>
</p>

<p class="response_descrip">
	تتحدث هذه المقالة عن عدة أنواع بيانات تتميز بها Postgres، وهي المصفوفات Arrays والنوع Hstore والنوع JSONB، كما تتطرق إلى الأنواع التعدادية ENUM لتحديد قيم مخصصة في أعمدة الجداول.
</p>

<h3>
	7. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D9%8A%D8%A7%D8%B7%D9%8A-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r477/" rel="">إدارة النسخ الاحتياطي في قواعد بيانات Postgres</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52698" href="https://academy.hsoub.com/uploads/monthly_2020_11/7.png.afd248be9780f6dc360dfe76596ffd09.png" rel="" data-fileext="png"><img alt="7.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52698" data-unique="4vwsbu9mo" src="https://academy.hsoub.com/uploads/monthly_2020_11/7.thumb.png.4756c708871377166f6a2169a9d7b880.png"></a>
</p>

<p class="response_descrip">
	تتحدث هذه المقالة عن كيفية أخذ نسخة احتياطية من قاعدة البيانات، ثم استعادتها. كما تشرح الأمر <code>‎\copy‎</code> وكيفية استخدامه لتحديد نمط البيانات في النسخة الاحتياطية.
</p>

<h3>
	8. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%B0%D8%A7%D9%83%D8%B1%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r478/" rel="">أساسيات إدارة الذاكرة في قواعد بيانات Postgres</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52699" href="https://academy.hsoub.com/uploads/monthly_2020_11/8.png.af733e23f514d23f657134d98b980045.png" rel="" data-fileext="png"><img alt="8.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52699" data-unique="od3gbudep" src="https://academy.hsoub.com/uploads/monthly_2020_11/8.thumb.png.bf39a1ceeb8dda0b16c14fe273a24e31.png"></a>
</p>

<p class="response_descrip">
	تشرح هذه المقالة كيفية تتبع استخدام الذاكرة في قاعدة البيانات، لمعرفة الحجم الذي تستهلكه الفهارس والجداول عمومًا، مما يساعد في إدارة ذاكرة التخزين لقاعدة البيانات ككل.
</p>

<h3>
	9. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A3%D8%AF%D8%A7%D8%A1-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r479/" rel="">كيفية إدارة الأداء في قواعد بيانات Postgres</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52700" href="https://academy.hsoub.com/uploads/monthly_2020_11/9.png.0cd6f5ce9e347d1a8ce06f662761dd9f.png" rel="" data-fileext="png"><img alt="9.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52700" data-unique="58pszhzbq" src="https://academy.hsoub.com/uploads/monthly_2020_11/9.thumb.png.846edb451481930d41ab70c7886cbc41.png"></a>
</p>

<p class="response_descrip">
	تشرح هذه المقالة طريقة تتبع أداء الاستعلامات في Postgres، وذلك لمعرفة الزمن المتوقع والحقيقي للاستعلام. ثمّ تبين كيفية عمل قيود على استخدام الفهارس، وتتطرق إلى موضوع ذاكرة التخزين المؤقتة Cache في Postgres.
</p>

<h3>
	10. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%B5%D8%AF%D9%81%D8%A9-psql-r480/" rel="">أوامر متقدمة في صدفة psql</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52701" href="https://academy.hsoub.com/uploads/monthly_2020_11/10.png.36ee7d99b3edef1385205c50f4f7c202.png" rel="" data-fileext="png"><img alt="10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52701" data-unique="3ggnfylow" src="https://academy.hsoub.com/uploads/monthly_2020_11/10.thumb.png.f7dbcc7e4b68d82afa390023196a1ecb.png"></a>
</p>

<p class="response_descrip">
	تستعرض هذه المقالة أوامر الاتصال بقاعدة البيانات واستعراض الفهارس وتنسيق المخرجات، وكيفية استخدام الأوامر الشرطية وكيفية تنفيذ أوامر نظام التشغيل من داخل صدفة <code>psql</code> وغيرها من الأوامر المتقدمة.
</p>

<h2>
	دروس تطبيقية
</h2>

<p>
	هذه بعض الدروس والمقالات التطبيقية لترسيخ فهمك لنظام PostgreSQL وتعلم المهارات الضرورية في قواعد البيانات، مثل التكامل مع التطبيقات الأخرى، والجوانب الأمنية والحماية من الهجمات المؤتمتة والبحث والتنقيب وغيرها.
</p>

<h3>
	1. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-r400/" rel="">فيديو - تثبيت وإعداد قاعدة بيانات PostgreSQL</a>
</h3>

<p class="response_image">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52702" href="https://academy.hsoub.com/uploads/monthly_2020_11/PostgreSQL.png.9093b6cae4c4e4e9f39e6cb61aaac614.png.d7b3f72564353a30fa398e9cb5ce6856.png" rel="" data-fileext="png"><img alt="PostgreSQL.png.9093b6cae4c4e4e9f39e6cb61aaac614.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52702" data-unique="9n16sgn1j" src="https://academy.hsoub.com/uploads/monthly_2020_11/PostgreSQL.png.9093b6cae4c4e4e9f39e6cb61aaac614.thumb.png.66925ff77c2a4d6527a08bfc126306a5.png"></a>
</p>

<p class="response_descrip">
	يشرح هذا الفيديو التعليمي طريقة تثبيت وإعداد خادم PostgreSQL على نظام أوبنتو 18.04. ثمّ يتطرق إلى كيفية إعداد كلمة مرور للمستخدم root؛ وإنشاء قاعدة بيانات جديدة ومستخدم جديد لديه صلاحيات كاملة.
</p>

<h3>
	2. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D8%AA-postgresql-%D9%88%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%87-%D8%B9%D9%84%D9%89-ubuntu-1404-r147/" rel="">كيف تثبت PostgreSQL وتستخدمه على Ubuntu 14.04</a>
</h3>

<p class="response_image">
	<img alt="postgresql-ubuntu.png.03201b9651bb33edaf0893c71726d795.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52703" data-unique="3f5lun36t" src="https://academy.hsoub.com/uploads/monthly_2020_11/postgresql-ubuntu.png.03201b9651bb33edaf0893c71726d795.png.870c59ef469cdee7d52b51bffd2285c4.png">
</p>

<p class="response_descrip">
	يشرح هذا المقال كيفية تثبيت Postgres على Ubuntu 14.04 وبعض الأمور الأساسية الأخرى، مثل مفهوم الأدوار وكيفية إنشاء قاعدة بيانات جديدة وإنشاء جداول البيانات وإضافة التسجيلات والاستعلام عنها وحذفها.
</p>

<h3>
	3. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-postgresql-%D9%85%D8%B9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-django-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D9%8A%D8%B9%D9%85%D9%84-%D8%A8%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r381/" rel="">كيفية استخدام PostgreSQL مع تطبيق Django على خادم يعمل بأوبنتو 16.04</a>
</h3>

<p class="response_image">
	<img alt="5a68c59c3ab11_27-2(2).png.6d84190940247b9bf936115535282783.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52704" data-unique="d44ez24iu" src="https://academy.hsoub.com/uploads/monthly_2020_11/5a68c59c3ab11_27-2(2).png.6d84190940247b9bf936115535282783.png.89cc2ee039272969cfbac6d4be66573a.png">
</p>

<p class="response_descrip">
	يستعرض هذا الدرس كيفية تثبيت وتهيئة PostgreSQL لاستخدامها مع تطبيقات Django، وكذلك تثبيت الحزم اللازمة وإنشاء اعتماديات قاعدة البيانات، مع توضيح كيفية بدء مشروع Django جديد وتجهيزه وإعداده.
</p>

<h3>
	4. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-postgresql-%D9%85%D8%B9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-django-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D9%8A%D8%B9%D9%85%D9%84-%D8%A8%D8%AF%D9%8A%D8%A8%D9%8A%D8%A7%D9%86-8-r372/" rel="">كيفية استخدام PostgreSQL مع تطبيق Django على خادم يعمل بدوبيان 8</a>
</h3>

<p class="response_image">
	<img alt="16-2.png.e0a6addd576b25fa3cad6cf772e35a19.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52705" data-unique="ks8ricwoc" src="https://academy.hsoub.com/uploads/monthly_2020_11/16-2.png.e0a6addd576b25fa3cad6cf772e35a19.png.f7ed5ea581d4c368fef20096bfa0078d.png">
</p>

<p class="response_descrip">
	ستتعلم في هذا الدليل كيفية تثبيت وتهيئة PostgreSQL لاستخدامها مع تطبيقات Django على خادم يعمل بدوبيان 8، وسنثبّت الحزم اللازمة وننشئ اعتماديات قاعدة البيانات للتطبيق، ثم نبدأ مشروع Django جديد ونجهّزه ليستخدم هذه اﻹعدادات.
</p>

<h3>
	5. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-postgresql-%D9%85%D9%86-%D8%A7%D9%84%D9%87%D8%AC%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%A4%D8%AA%D9%85%D8%AA%D8%A9-automated-attacks-r380/" rel="">كيفيّة حماية PostgreSQL من الهجمات المُؤتمتة (Automated Attacks)</a>
</h3>

<p class="response_image">
	<img alt="25-2.png.9c34280a208d4c36a3764eab08f2199c.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52706" data-unique="w4x7if9bl" src="https://academy.hsoub.com/uploads/monthly_2020_11/25-2.png.9c34280a208d4c36a3764eab08f2199c.png.b754013bdcc35bc210eb0e715e4f956f.png">
</p>

<p class="response_descrip">
	سنلقي في هذا الدّرس نظرة على كيفيّة تقليل خطر الوصول غير المُصرّح في حال تفعيل الاتّصالات البعيدة (remote connections). هذا ضروري لصد الهجمات المُؤتمتة التي تُصمَّمُ للبحث عن الأخطاء الشّائعة بغية النفاد منها واستغلالها.
</p>

<h3>
	6. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-%D8%A8%D8%AD%D8%AB-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D9%83%D8%A7%D9%85%D9%84%D8%A9-full-text-search-%D9%81%D9%8A-postgresql-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r369/" rel="">كيف تستخدم تقنية بحث النصوص الكاملة Full-Text Search في PostgreSQL على خادم أوبنتو 16.04</a>
</h3>

<p class="response_image">
	<img alt="18.png.aa5cde7c1160ea273b5776387dcc369d.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52707" data-unique="ed81q63og" src="https://academy.hsoub.com/uploads/monthly_2020_11/18.png.aa5cde7c1160ea273b5776387dcc369d.png.14e250dc9e11709cec22cf5f02290430.png">
</p>

<p class="response_descrip">
	ستتعلم في هذا المقال تقنية بحث النصوص الكاملة، وهي مفيدة في تقوية نتائج البحث في مواقع مثل المتاجر الرقمية ومحركات البحث والجرائد وغيرها. ستتعلم كذلك كيف تبحث في قاعدة البيانات باستخدام FTS واختيار أفضل النتائج فقط.
</p>

<h3>
	7. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D9%86%D8%B8%D8%A7%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-%D8%B9%D9%84%D9%89-%D8%AA%D9%88%D8%B2%D9%8A%D8%B9%D8%A9-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r378/" rel="">شرح التكرار في نظام قواعد البيانات PostgreSQL على توزيعة أوبنتو</a>
</h3>

<p class="response_image">
	<img alt="13-2.png.2183be6b8cbe84c29edcd46e98e33fc5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52708" data-unique="fm0zvj3oz" src="https://academy.hsoub.com/uploads/monthly_2020_11/13-2.png.2183be6b8cbe84c29edcd46e98e33fc5.png.3c47817531841531330625648882f8e1.png">
</p>

<p class="response_descrip">
	ستتعلم في هذا الدليل كيفية إعداد تكرار من نوع (رئيسي-Master/ثانوي-Slave)، وهي عملية مزامنة بين قاعدتي بيانات من خلال النسخ من قاعدة بيانات على خادم (رئيسي) إلى قاعدة بيانات أخرى في خادم آخر (ثانوي). سوف ننفذ هذه العملية على خادم يعمل بتوزيعة أوبنتو 16.04.
</p>

<h3>
	8. <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D9%82%D9%84-%D9%85%D8%AC%D9%84%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-postgresql-%D8%A5%D9%84%D9%89-%D9%85%D8%B3%D8%A7%D8%B1-%D9%85%D8%AE%D8%AA%D9%84%D9%81-%D9%81%D9%8A-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r368/" rel="">كيف تنقل مجلد البيانات في PostgreSQL إلى مسار مختلف في خادم أوبنتو 16.04</a>
</h3>

<p class="response_image">
	<img alt="20-2.png.8731c2500de28b29a2454837b1fa062b.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52709" data-unique="xez0c69zs" src="https://academy.hsoub.com/uploads/monthly_2020_11/20-2.png.8731c2500de28b29a2454837b1fa062b.png.b42d59ec92380e724616b6359c41fa29.png">
</p>

<p class="response_descrip">
	ستتعلم في هذا الدليل كيفية نقل مجلد البيانات في نظام PostgreSQL إلى مكان جديد في حال كنت تريد إضافة مساحة جديدة أو ترغب في تحسين الأداء، أو الاستفادة من مزايا التخزين الأخرى التي توفرها أنظمة مصفوفات الأقراص المستقلة RAID، أو عُقد التخزين الشبكية “Network Block Storages”، أو غيرها من الأجهزة وأنظمة التخزين.
</p>

<h2>
	خاتمة
</h2>

<p>
	تُضاف مزيد من المقالات والدروس في الأكاديمية حول PostgreSQL وقواعد البيانات ولغات البرمجة وغيرها باستمرار، لذلك تابع مستجدات الأكاديمية، وإن وجدت مشكلة فيمكنك أن تسأل عنها في <a href="https://academy.hsoub.com/questions/c3-programming/" rel="">قسم الأسئلة والأجوبة</a> الخاص بالأكاديمية.
</p>

<p>
	لا تنس كذلك الاشتراك في <a href="https://www.youtube.com/channel/UCJv37tcBvJlBF2MoVMRMvbQ" rel="external nofollow" target="_blank">قناة حسوب</a> على اليوتيوب ومشاهدة عشرات الفيديوهات التعليمية في كل المجالات التقنية.
</p>

<p>
	إن كنت مهتما بتعلم لغات برمجة أخرى، فيمكنك زيارة قسم <a href="https://academy.hsoub.com/programming/" rel="">البرمجة</a> في الأكاديمية، أيضًا لا تنس زيارة <a href="https://wiki.hsoub.com" rel="external" target="_blank">موسوعة حسوب</a> التي تضم توثيقات الكثير من لغات البرمجة. وفّقك الله تعالى.
</p>
]]></description><guid isPermaLink="false">481</guid><pubDate>Sat, 07 Nov 2020 16:00:00 +0000</pubDate></item><item><title>&#x623;&#x648;&#x627;&#x645;&#x631; &#x645;&#x62A;&#x642;&#x62F;&#x645;&#x629; &#x641;&#x64A; &#x635;&#x62F;&#x641;&#x629; psql</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%B5%D8%AF%D9%81%D8%A9-psql-r480/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/10.png.6ce3ab4e5ce9d5d4acd17b1eba255375.png" /></p>

<p>
	تعرفنا في بداية هذا الدليل إلى بعض أوامر صدفة <code>psql</code> الأساسية، ولكننا يجب أن نتعرف إلى بقية هذه الأوامر، والتي يوجد العديد منها لمساعدتنا في أمور قد تبدو صعبة التنفيذ بطرق أخرى.
</p>

<p>
	نذكر في هذا الفصل أوامر للاتصال بقاعدة بيانات، استعراض الفهارس، تنسيق المخرجات، كيفية استخدام الأوامر الشرطية وكيفية تنفيذ أوامر نظام التشغيل من داخل صدفة <code>psql</code> وغيرها من الأوامر التي تُعتبر الأكثر أهمية من بين الأوامر المتقدمة.
</p>

<h2>
	أصناف أوامر psql
</h2>

<p>
	تنقسم أوامر psql إلى المجموعات التالية:
</p>

<ul>
<li>
		أوامر مساعدة، لعرض معلومات مساعدة في كيفية استخدام أوامر أخرى.
	</li>
	<li>
		<strong>أوامر التحكم بمخزن الاستعلامات</strong>، هو ملف مؤقت يمكن كتابة الاستعلامات فيه عن طريق محرر النصوص، لتسهيل كتابة الاستعلامات الطويلة قبل تنفيذها، أو كتابة عدة أوامر واستعلامات وتحرير كل ذلك قبل التنفيذ.
	</li>
	<li>
		<strong>أوامر الإدخال والإخراج</strong>، تسمح بتنفيذ تعليمات مخزنة في ملفات خارجية، أو كتابة مخرجات التعليمات والاستعلامات إلى ملفات خارجية.
	</li>
	<li>
		<strong>الأوامر الشرطية</strong>، تسمح باستخدام <code>if</code> و <code>else</code> للتحكم بسير سلسلة من التعليمات.
	</li>
	<li>
		<strong>أوامر استعراض المعلومات</strong>، لعرض معلومات عن قاعدة البيانات، الجداول، المخططات، وغيرها.
	</li>
	<li>
		<strong>أوامر تنسيق البيانات</strong>، تسمح بتنسيق طريقة إظهار المخرجات.
	</li>
	<li>
		<strong>أوامر الاتصال</strong>، للاتصال بقاعدة بيانات أخرى.
	</li>
	<li>
		<strong>أوامر نظام التشغيل</strong>، تسمح بتنفيذ أوامر نظام التشغيل من داخل الصدفة
	</li>
	<li>
		<strong>أوامر التحكم بالمتغيرات</strong>، لتحديد قيمة متغير أو إزالتها أو إدخالها من قبل المستخدم
	</li>
	<li>
		<strong>أوامر الكائنات الكبيرة</strong>، وهي الكائنات التي لا يتم تخزينها في قاعدة البيانات مباشرةً بل تُخزن في ملفات مستقلة، ويتم الإشارة إليها باستخدام Object id.
	</li>
</ul>
<p>
	سنتعرف في هذه الفقرة إلى الأوامر الأكثر أهمية فقط، إلا أن اطلاعك على باقي الأوامر لا شك سيتيح لك استخدامًا أكثر حرية واحترافية لصدفة psql، كما سيسمح لك في كتابة استعلامات معقدة حتى لو لم تكن محترفًا في SQL.
</p>

<h2>
	أوامر الاتصال
</h2>

<p>
	تُعتبر أوامر الاتصال من أهم أوامر صدفة <code>psql</code>، فهي التي تسمح بالاتصال بقاعدة بيانات معينة، أو استعراض المعلومات الخاصة بها.
</p>

<h3>
	استعراض معلومات الاتصال
</h3>

<p>
	يمكن استخدام الأمر '‎\conninfo' لاستعراض المعلومات الرئيسية للاتصال الحالي (اسم قاعدة البيانات، اسم المستخدم، رقم المنفذ للعملية <code>postgres</code>):
</p>

<pre class="ipsCode">
hsoubguide=# \conninfo

You are connected to database "hsoubguide" as user "postgres" via socket in "/var/run/postgresql" at port "5432".
</pre>

<h3>
	الاتصال بقاعدة بيانات أخرى
</h3>

<p>
	إن لم تقم بالدخول إلى الصدفة محددًّا اسم قاعدة البيانات التي ترغب بالاتصال بها، فيمكنك الاتصال من داخل الصدفة بالأمر '‎\connect'
</p>

<pre class="ipsCode">
hsoubguide=# \connect postgres

You are now connected to database "postgres" as user "postgres".

postgres=# \connect hsoubguide
You are now connected to database "hsoubguide" as user "postgres".
</pre>

<h2>
	أوامر استعراض أخرى مهمة
</h2>

<p>
	سنذكر فيما يلي كيفية استعراض التوابع في صدفة <code>psql</code> وكيفية استعراض الفهارس المخزنة في قاعدة البيانات، وقد ذكرنا العديد من أوامر الاستعراض في الفصل الرابع من هذا الدليل، استعرضنا فيها الجداول وقواعد البيانات، فيمكن الرجوع للفصل الرابع لأوامر الاستعراض الأساسية.
</p>

<h3>
	استعراض جميع التوابع المتاحة
</h3>

<p>
	يعرض الأمر '‎\df' قائمة بجميع التوابع التي يٌمكن استخدامها في الصدفة، مع نوع القيمة المعادة من كل تابع، ونوع الوسطاء الممررة لكل منهم:
</p>

<pre class="ipsCode">
hsoubguide=# \df

                                                   List of functions
 Schema |           Name           | Result data type |                   Argument data types                   | Type 
--------+--------------------------+------------------+---------------------------------------------------------+------
 public | akeys                    | text[]           | hstore                                                  | func
 public | avals                    | text[]           | hstore                                                  | func
 public | defined                  | boolean          | hstore, text                                            | func
 public | delete                   | hstore           | hstore, hstore                                          | func
 public | delete                   | hstore           | hstore, text                                            | func
 public | delete                   | hstore           | hstore, text[]                                          | func
 public | each                     | SETOF record     | hs hstore, OUT key text, OUT value text                 | func
 public | exist                    | boolean          | hstore, text                                            | func
 public | exists_all               | boolean          | hstore, text[]                                          | func
 public | exists_any               | boolean          | hstore, text[]                                          | func
 public | fetchval                 | text             | hstore, text                                            | func
...
...
(58 rows)
</pre>

<p>
	كما يمكن الحصول على المزيد من المعلومات التي تخص كل تابع بإضافة الرمز <code>+</code> في نهاية الأمر السابق.
</p>

<h3>
	استعراض الفهارس المخزنة في قاعدة البيانات
</h3>

<p>
	يعرض الأمر '‎\di' قائمة بأهم الفهارس (indexes) المخزنة في قاعدة البيانات، كما يمكن استخدام الرمز <code>+</code> لاستعراض معلومات إضافية، منها الحجم الذي تحجزه هذه الفهارس في الذاكرة.
</p>

<pre class="ipsCode">
hsoubguide=# \di+

                                        List of relations
 Schema |            Name            | Type  |  Owner   |    Table    |    Size    | Description 
--------+----------------------------+-------+----------+-------------+------------+-------------
 public | basket_a_pkey              | index | postgres | basket_a    | 16 kB      | 
 public | basket_b_pkey              | index | postgres | basket_b    | 16 kB      | 
 public | departments_department_key | index | postgres | departments | 16 kB      | 
 public | departments_pkey           | index | postgres | departments | 16 kB      | 
 public | employees_pkey             | index | postgres | employees   | 16 kB      | 
 public | marks_pkey                 | index | postgres | marks       | 16 kB      | 
 public | names_pkey                 | index | postgres | names       | 16 kB      | 
 public | phones_pkey                | index | postgres | phones      | 16 kB      | 
 public | products_pkey              | index | postgres | products    | 16 kB      | 
 public | purchases_pkey             | index | postgres | purchases   | 40 kB      | 
 public | student_pkey               | index | postgres | student     | 16 kB      | 
 public | table1_pkey                | index | postgres | table1      | 16 kB      | 
 public | table2_pkey                | index | postgres | table2      | 16 kB      | 
 public | test_table_pkey            | index | postgres | test_table  | 16 kB      | 
 public | users2_pkey                | index | postgres | users2      | 8192 bytes | 
 public | users_pkey                 | index | postgres | users       | 16 kB      | 
(16 rows)
</pre>

<h2>
	أوامر التنسيق
</h2>

<p>
	تسمح هذه الأوامر بتغيير التنسيق الافتراضي للجداول الناتجة من الاستعلامات، وتتيح ميزة كبيرة قد تختصر عليك الكثير من الوقت والجهد الذي يلزم لتحويل التنسيق الافتراضي يدويًّا إلى شكل أكثر فائدة.
</p>

<h3>
	تنسيق المحاذاة
</h3>

<p>
	يمكن استخدام الأمر '‎\a' لتشغيل محاذاة محتوى العمود مع اسمه، أو لإيقاف ذلك.
</p>

<pre class="ipsCode">
hsoubguide=# \a

Output format is unaligned.

hsoubguide=# SELECT * FROM products LIMIT 4;
id|title|price|created_at|deleted_at|tags
1|Dictionary|9.99|2011-01-01 22:00:00+02||{Book}
2|Python Book|29.99|2011-01-01 22:00:00+02||{Book,Programming,Python}
3|Ruby Book|27.99|2011-01-01 22:00:00+02||{Book,Programming,Ruby}
4|Baby Book|7.99|2011-01-01 22:00:00+02||{Book,Children,Baby}
(4 rows)

hsoubguide=# \a

Output format is aligned.

hsoubguide=# SELECT * FROM products LIMIT 4;
 id |    title    | price |       created_at       | deleted_at |           tags            
----+-------------+-------+------------------------+------------+---------------------------
  1 | Dictionary  |  9.99 | 2011-01-01 22:00:00+02 |            | {Book}
  2 | Python Book | 29.99 | 2011-01-01 22:00:00+02 |            | {Book,Programming,Python}
  3 | Ruby Book   | 27.99 | 2011-01-01 22:00:00+02 |            | {Book,Programming,Ruby}
  4 | Baby Book   |  7.99 | 2011-01-01 22:00:00+02 |            | {Book,Children,Baby}
(4 rows)
</pre>

<p>
	كما يمكنك تغيير المحرف الفاصل بين الأعمدة باستخدام الأمر '‎\f' مع تمرير المحرف المُراد، ويمكنك كذلك منع طباعة أسماء الأعمدة والاكتفاء بالمحتويات باستخدام الأمر '‎\t'.
</p>

<h3>
	تنسيق HTML
</h3>

<p>
	يمكنك استخدام الأمر '‎\H' لتغيير حالة المخرجات من النمط المكتوب إلى نمط HTML وبالعكس:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM products LIMIT 4;

 id |    title    | price |       created_at       | deleted_at |           tags            
----+-------------+-------+------------------------+------------+---------------------------
  1 | Dictionary  |  9.99 | 2011-01-01 22:00:00+02 |            | {Book}
  2 | Python Book | 29.99 | 2011-01-01 22:00:00+02 |            | {Book,Programming,Python}
  3 | Ruby Book   | 27.99 | 2011-01-01 22:00:00+02 |            | {Book,Programming,Ruby}
  4 | Baby Book   |  7.99 | 2011-01-01 22:00:00+02 |            | {Book,Children,Baby}
(4 rows)
</pre>

<pre class="ipsCode">
hsoubguide=# \H

Output format is html.
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM products LIMIT 4;

&lt;table border="1"&gt;
  &lt;tr&gt;
    &lt;th align="center"&gt;id&lt;/th&gt;
    &lt;th align="center"&gt;title&lt;/th&gt;
    &lt;th align="center"&gt;price&lt;/th&gt;
    &lt;th align="center"&gt;created_at&lt;/th&gt;
    &lt;th align="center"&gt;deleted_at&lt;/th&gt;
    &lt;th align="center"&gt;tags&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr valign="top"&gt;
    &lt;td align="right"&gt;1&lt;/td&gt;
    &lt;td align="left"&gt;Dictionary&lt;/td&gt;
    &lt;td align="right"&gt;9.99&lt;/td&gt;
    &lt;td align="left"&gt;2011-01-01 22:00:00+02&lt;/td&gt;
    &lt;td align="left"&gt;&amp;nbsp; &lt;/td&gt;
    &lt;td align="left"&gt;{Book}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr valign="top"&gt;
    &lt;td align="right"&gt;2&lt;/td&gt;
    &lt;td align="left"&gt;Python Book&lt;/td&gt;
    &lt;td align="right"&gt;29.99&lt;/td&gt;
    &lt;td align="left"&gt;2011-01-01 22:00:00+02&lt;/td&gt;
    &lt;td align="left"&gt;&amp;nbsp; &lt;/td&gt;
    &lt;td align="left"&gt;{Book,Programming,Python}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr valign="top"&gt;
    &lt;td align="right"&gt;3&lt;/td&gt;
    &lt;td align="left"&gt;Ruby Book&lt;/td&gt;
    &lt;td align="right"&gt;27.99&lt;/td&gt;
    &lt;td align="left"&gt;2011-01-01 22:00:00+02&lt;/td&gt;
    &lt;td align="left"&gt;&amp;nbsp; &lt;/td&gt;
    &lt;td align="left"&gt;{Book,Programming,Ruby}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr valign="top"&gt;
    &lt;td align="right"&gt;4&lt;/td&gt;
    &lt;td align="left"&gt;Baby Book&lt;/td&gt;
    &lt;td align="right"&gt;7.99&lt;/td&gt;
    &lt;td align="left"&gt;2011-01-01 22:00:00+02&lt;/td&gt;
    &lt;td align="left"&gt;&amp;nbsp; &lt;/td&gt;
    &lt;td align="left"&gt;{Book,Children,Baby}&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;(4 rows)&lt;br /&gt;
&lt;/p&gt;
</pre>

<pre class="ipsCode">
hsoubguide=# \H

Output format is aligned.
</pre>

<h2>
	استعراض تاريخ الاستعلامات وحفظه
</h2>

<p>
	يمكن استعراض تاريخ الاستعلامات وأوامر الصدفة التي نُفّذت من قبل باستخدام الأمر <code>‎\s</code>، كما يمكنك حفظ هذا السجل بإضافة اسم الملف الذي ترغب بحفظ السجل فيه.
</p>

<pre class="ipsCode">
hsoubguide=# \s /tmp/psql_history.txt

Wrote history to file "/tmp/psql_history.txt".
</pre>

<h2>
	أوامر التعامل مع المتغيرات
</h2>

<p>
	تسمح psql بتعريف متغيرات داخلها، واستخدامها لاحقًا ضمن التعليمات أو الاستعلامات اللاحقة.
</p>

<p>
	يمكن تعريف متغير باستخدام الأمر <code>set\</code> كما يمكن حذفه باستخدام <code>unset\</code>، وفي حال أردنا استخدام قيمة هذا المتغير، علينا أن نضع قبل اسمه الرمز <code>:</code>.
</p>

<pre class="ipsCode">
hsoubguide=# \set NAME mostafa
hsoubguide=# \set rate 5.9

hsoubguide=# \echo :rate
5.9

hsoubguide=# \echo :NAME
mostafa
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM test_table WHERE number &gt; :rate;

 id | number | name  
----+--------+-------
  4 |     22 | hel..
  1 |     10 | 10
  2 |     13 | 13
(3 rows)
</pre>

<p>
	كما يمكن استخدام الأمر <code>prompt\</code> لطلب إدخال قيمة من المستخدم، وذلك بعد طباعة عبارة الطلب:
</p>

<pre class="ipsCode">
hsoubguide=# \prompt 'Please enter your name: ' NAME
Please enter your name: Mostafa

hsoubguide=# \echo :NAME
Mostafa
</pre>

<p>
	يمكنك استخدام قيم هذه المتغيرات ضمن الاستعلامات أو ضمن أوامر psql أخرى.
</p>

<h2>
	الأوامر الشرطية
</h2>

<p>
	بعد أن تعرفنا على الأوامر الخاصة بالمتغيرات، يجدر بنا أن نعرف أن psql تتيح استخدام التعليمات الشرطية <code>if\</code> و <code>elif\</code> و <code>else\</code> للتحكم بكيفية سير التنفيذ، ويوضح المثال التالي المأخوذ من <a data-ss1613715962="1" href="postgresql.org/docs/current/app-psql.html" rel="">التوثيق</a> كيفية استخدامها:
</p>

<pre class="ipsCode">
SELECT
    EXISTS(SELECT 1 FROM customer WHERE customer_id = 123) as is_customer,
    EXISTS(SELECT 1 FROM employee WHERE employee_id = 456) as is_employee
\gset
\if :is_customer
    SELECT * FROM customer WHERE customer_id = 123;
\elif :is_employee
    \echo 'is not a customer but is an employee'
    SELECT * FROM employee WHERE employee_id = 456;
\else
    \if yes
        \echo 'not a customer or employee'
    \else
        \echo 'this will never print'
    \endif
\endif
</pre>

<h2>
	أوامر نظام التشغيل
</h2>

<p>
	تسمح لنا صدفة <code>psql</code> بتنفيذ أوامر من خارج إمكانيات الصدفة، وهذا يسمح لنا بالبقاء ضمنها، والتعامل مع نظام التشغيل من داخلها مباشرةً.
</p>

<h3>
	تنفيذ أوامر صدفة bash ضمن psql
</h3>

<p>
	تسمح psql بتنفيذ أوامر صدفة bash بكتابتها بعد الأمر <code>!\</code> كما يلي:
</p>

<pre class="ipsCode">
postgres=# \! echo Hello

Hello
</pre>

<pre class="ipsCode">
postgres=# \! pwd

/usr/pgsql-12/bin
</pre>

<h3>
	تشغيل توقيت الاستعلام
</h3>

<p>
	في الحالة الافتراضية لا يكون توقيت تنفيذ الاستعلام مُتاحًا للعرض، ولكن يمكننا تفعيله من خلال الأمر التالي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM products LIMIT 1;

 id |   title    | price |       created_at       | deleted_at |  tags  
----+------------+-------+------------------------+------------+--------
  1 | Dictionary |  9.99 | 2011-01-01 22:00:00+02 |            | {Book}
(1 row)

Time: 0.723 ms
</pre>

<p>
	حيث سيتيح ذلك الأمر إظهار توقيت الاستعلام بالميلي ثانية.
</p>

<h2>
	الخروج من صدفة postgres
</h2>

<p>
	قد تقضي وقتًا طويلًا داخل صدفة psql، ليس حبًّا بها، ولكن لعدم معرفة كيفية الخروج منها، لذلك لا تنسَ أن الأمر <code>‎\q</code> هو الذي يُخرجك من صدفة psql.
</p>

<pre class="ipsCode">
hsoubguide=# \q

bash-4.2$ 
</pre>

<h2>
	خلاصة
</h2>

<p>
	تعرفنا في هذا الفصل إلى جميع أنواع أوامر صدفة <code>psql</code>، وذكرنا أكثرها أهمية، بما يسمح لك بزيادة كفاءة تعاملك مع قواعد بيانات Postgres، وتذكر دومًا أنه يمكنك استعراض العديد من الأوامر الأخرى من خلال الأمر <code>‎\?‎</code>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a data-ss1613715962="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A3%D8%AF%D8%A7%D8%A1-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r479/" rel="">كيفية إدارة الأداء في قواعد بيانات Postgres</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a data-ss1613715962="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
	<li>
		<a data-ss1613715962="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-%D8%A8%D8%AD%D8%AB-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D9%83%D8%A7%D9%85%D9%84%D8%A9-full-text-search-%D9%81%D9%8A-postgresql-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r369/" rel="">كيف تستخدم تقنية بحث النصوص الكاملة Full-Text Search في PostgreSQL على خادم أوبنتو</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">480</guid><pubDate>Mon, 19 Oct 2020 13:06:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x625;&#x62F;&#x627;&#x631;&#x629; &#x627;&#x644;&#x623;&#x62F;&#x627;&#x621; &#x641;&#x64A; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; Postgres</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A3%D8%AF%D8%A7%D8%A1-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r479/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/9.png.ce58ad633d0862c25f296694099e08d0.png" /></p>

<p>
	سنتعرف في هذا الفصل إلى طريقة تتبع أداء الاستعلامات في Postgres، وذلك لمعرفة الزمن المتوقع والحقيقي للاستعلام، كما يذكر كيفية عمل قيود على استخدام الفهارس، ثم سنتطرق لفهم ذاكرة التخزين المؤقتة Cache في Postgres.
</p>

<h2>
	خطة التنفيذ (Execution plan)
</h2>

<p>
	لدى Postgres قدرة كبيرة على إظهار كيفية تنفيذ الاستعلامات خلف الكواليس، وهذا ما يُسمى بخطة التنفيذ ونستخدم لإظهار ذلك التعليمة <code>explain</code>، وإن فهمك لهذه المعلومات يساعدك في تحسين قاعدة بياناتك باستخدام الفهارس لرفع الكفاءة.
</p>

<p>
	سننشئ جدولًا صغيرًا لنقوم عليه ببعض التجارب:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE test_explain(msg varchar(20));

CREATE TABLE
</pre>

<p>
	جميع الاستعلامات في Postgres يكون لها خطة تنفيذ عندما يتم تنفيذها، وهناك ثلاث أشكال لتنفيذ التعليمة <code>explain</code> كما يلي:
</p>

<ul>
<li>
		الشكل العام: باستخدام <code>EXPLAIN</code>، يقوم بعرض توقّع لما سيحدث تقريبًا، دون أن يتم التنفيذ الفعلي للتعليمة
	</li>
</ul>
<pre class="ipsCode">
hsoubguide=# EXPLAIN INSERT INTO test_explain(msg) VALUES('Hsoub');

                        QUERY PLAN                         
-----------------------------------------------------------
 Insert on test_explain  (cost=0.00..0.01 rows=1 width=58)
   -&gt;  Result  (cost=0.00..0.01 rows=1 width=58)
(2 rows)

hsoubguide=# SELECT * FROM test_explain ;
 msg 
-----
(0 rows)
</pre>

<ul>
<li>
		الشكل التحليلي: باستخدام <code>EXPLAIN ANALYZE</code>، يقوم بتنفيذ الاستعلام ثم يعرض شرحًا لما حدث خلال التنفيذ.
	</li>
</ul>
<pre class="ipsCode">
hsoubguide=# EXPLAIN ANALYZE INSERT INTO test_explain(msg) VALUES('Hsoub');

                                             QUERY PLAN                                              
-----------------------------------------------------------------------------------------------------
 Insert on test_explain  (cost=0.00..0.01 rows=1 width=58) (actual time=0.898..0.898 rows=0 loops=1)
   -&gt;  Result  (cost=0.00..0.01 rows=1 width=58) (actual time=0.003..0.004 rows=1 loops=1)
 Planning Time: 0.067 ms
 Execution Time: 0.952 ms
(4 rows)

hsoubguide=# SELECT * FROM test_explain ;
  msg  
-------
 Hsoub
(1 row)
</pre>

<ul>
<li>
		الشكل المستفيض (verbose)، يزيد عن الشكل التحليلي بالقليل من المعلومات، وهنا يمكن استخدام <code>EXPLAIN VERBOSE</code> للشرح دون التنفيذ:
	</li>
</ul>
<pre class="ipsCode">
hsoubguide=# EXPLAIN VERBOSE INSERT INTO test_explain(msg) VALUES('Hsoub2');

                            QUERY PLAN                            
------------------------------------------------------------------
 Insert on public.test_explain  (cost=0.00..0.01 rows=1 width=58)
   -&gt;  Result  (cost=0.00..0.01 rows=1 width=58)
         Output: 'Hsoub2'::character varying(20)
(3 rows)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM test_explain ;

  msg  
-------
 Hsoub
(1 row)
</pre>

<p>
	أو استخدام <code>EXPLAIN ANALYZE VERBOSE</code> للشرح المستفيض مع التنفيذ:
</p>

<pre class="ipsCode">
hsoubguide=# EXPLAIN ANALYZE VERBOSE INSERT INTO test_explain(msg) VALUES('Hsoub2');

                                                 QUERY PLAN                                                 
------------------------------------------------------------------------------------------------------------
 Insert on public.test_explain  (cost=0.00..0.01 rows=1 width=58) (actual time=0.044..0.045 rows=0 loops=1)
   -&gt;  Result  (cost=0.00..0.01 rows=1 width=58) (actual time=0.003..0.004 rows=1 loops=1)
         Output: 'Hsoub2'::character varying(20)
 Planning Time: 0.074 ms
 Execution Time: 0.086 ms
(5 rows)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM test_explain ;

  msg  
-------
 Hsoub
 Hsoub2
(2 rows)
</pre>

<p>
	غالبًا يتم استخدام التعليمة <code>explain</code> مع عبارات <code>SELECT</code>، إلا أنه يمكن استخدامها أيضًا مع التعليمات:
</p>

<ul>
<li>
		<code>INSERT</code>
	</li>
	<li>
		<code>UPDATE</code>
	</li>
	<li>
		<code>DELETE</code>
	</li>
	<li>
		<code>EXECUTE</code>
	</li>
	<li>
		<code>DECLARE</code>
	</li>
</ul>
<h3>
	استخدام التعليمة Explain لشرح الاستعلامات
</h3>

<p>
	نستعلم في المثال التالي عن الأسماء الأخيرة للموظفين ذوي الرواتب التي تبدأ من 50000 فما فوق، كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT last_name FROM employees WHERE salary &gt;= 50000;

 last_name 
-----------
 Adams
 Smith
(2 rows)
</pre>

<p>
	يمكننا تفحّص كيفية قيام Postgres بتنفيذ الاستعلام السابق كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# EXPLAIN SELECT last_name FROM employees WHERE salary &gt;= 50000;

                        QUERY PLAN                         
-----------------------------------------------------------
 Seq Scan on employees  (cost=0.00..1.06 rows=2 width=128)
   Filter: (salary &gt;= 50000)
(2 rows)
</pre>

<p>
	كما يمكن فهم أداء تنفيذ الاستعلام الحقيقي عن طريق <code>ANALYZE</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# EXPLAIN ANALYZE SELECT last_name FROM employees WHERE salary &gt;= 50000;

                                             QUERY PLAN                                              
-----------------------------------------------------------------------------------------------------
 Seq Scan on employees  (cost=0.00..1.06 rows=2 width=128) (actual time=0.032..0.036 rows=2 loops=1)
   Filter: (salary &gt;= 50000)
   Rows Removed by Filter: 3
 Planning Time: 0.142 ms
 Execution Time: 0.084 ms
(5 rows)
</pre>

<h3>
	فهم خطط التنفيذ
</h3>

<p>
	إن نفّذنا التعليمة <code>EXPLAIN ANALYZE</code> على جدول مشابه للجدول السابق ولكن مع احتوائه على مليوني سطر، يمكن أن نحصل على المخرجات التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51680" data-ss1613715858="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/execution1.png.abbf255a49639088dc5321bf6cde5224.png" rel=""><img alt="execution1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51680" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/execution1.png.abbf255a49639088dc5321bf6cde5224.png"></a>
</p>

<p>
	تَوضّح الصورة التالية معاني هذه الأرقام المكتوبة كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51681" data-ss1613715858="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/execution2.png.e401cb64710e47fe3c366fe85187e45d.png" rel=""><img alt="execution2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51681" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/execution2.png.e401cb64710e47fe3c366fe85187e45d.png"></a>
</p>

<p>
	تشير الكلمة <code>Seq Scan</code> إلى أن عملية البحث التي تجري هي البحث التسلسلي. أما العبارة التالية:
</p>

<pre class="ipsCode">
(cost=0.00..35811.00 rows=1 width=6)
</pre>

<p>
	فهي التقدير التقريبي (وليس الحقيقي) لما يُتوقّع أن يستغرقه تنفيذ الاستعلام، حيث يعبر الزمن <code>0.00</code> عن الزمن اللازم لبدء الاستعلام، والزمن <code>35811.00</code> هو الزمن المتوقع لإنهاء الاستعلام، أما القيمة <code>rows=1</code> هي عدد الأسطر التي يُتوقّع أن تُعطى في المخرجات، والقيمة <code>width=6</code> هي الحجم التقريبي لمحتوى الأسطر التي يُتوقع أن تُعطى في المخرجات.
</p>

<p>
	ولأننا قُمنا بتنفيذ التعليمة <code>EXPLAIN ANALYZE</code> فإننا لم نحصل فقط على التقدير المتوقع للتنفيذ، بل على الوقت الحقيقي المستغرق كذلك كما تبيّن الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51682" data-ss1613715858="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/execution3.png.88b70e385dd36f5bebb904f1b9d904dd.png" rel=""><img alt="execution3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51682" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/execution3.png.88b70e385dd36f5bebb904f1b9d904dd.png"></a>
</p>

<p>
	يُمكننا بذلك رؤية الوقت الكبير المستهلك في المسح المتتالي، وسنقارنه مع الوقت المستغرق عند إضافة فهرس واختبار النتائج:
</p>

<pre class="ipsCode">
CREATE INDEX idx_emps on employees (salary);
</pre>

<p>
	وبذلك خفضنا زمن الاستعلام من 295 ميللي ثانية إلى 1.7 ميللي ثانية فقط كما يوضح الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51683" data-ss1613715858="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/execution4.png.c1a68dc3a2a4adcc1cfb1654af3c91fb.png" rel=""><img alt="execution4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51683" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/execution4.png.c1a68dc3a2a4adcc1cfb1654af3c91fb.png"></a>
</p>

<p>
	كانت هذه مقدمة في استخدام التعليمة <code>EXPLAIN</code> ولا بد أن تجربها على استعلامات أكبر حجمًا لاستكشاف ما يمكنها إظهاره.
</p>

<h2>
	قيود شرطية على إنشاء الفهارس
</h2>

<p>
	قد نحتاج أحيانًا إلى وضع بعض القيود على البيانات التي نرغب بالفعل في فهرستها، فمثلًا قد لا نرغب بحذف مستخدم ما من قاعدة البيانات ولكن نريد أن نظهره على أنه محذوف بحيث يمكن إرجاع بياناته لو أراد العودة للموقع بعد شهر مثلًا، ولكن في الوقت نفسه لا نريد أن يزداد حجم البيانات التي نقوم بفهرستها، ولذلك نستخدم <a data-ss1613715858="1" href="https://www.postgresql.org/docs/current/indexes-partial.html" rel="external nofollow">الفهارس الجزئية</a>.
</p>

<p>
	سنستخدم الفهارس الجزئية في المثال التالي لوضع فهرس فريد فقط للمستخدمين غير المحذوفين:
</p>

<pre class="ipsCode">
CREATE UNIQUE INDEX user_email ON users (email) WHERE deleted_at IS NULL;
</pre>

<h2>
	ذاكرة التخزين المؤقتة (Cache)
</h2>

<p>
	إن معظم التطبيقات تتعامل مع جزء صغير من البيانات بشكل متكرر، ومثل العديد من الأمور الأخرى فإن البيانات يمكن أن تتبع قاعدة 80/20 حيث أن 20% من البيانات هي التي يتم قراءتها في 80% من الحالات، وأحيانا يكون هذا الرقم أكبر من ذلك.
</p>

<p>
	تقوم Postgres بتتبع أنماط استخدامك للبيانات وتحاول الإبقاء على البيانات الأكثر وصولًا في ذاكرة التخزين المؤقتة.
</p>

<p>
	عمومًا، سترغب في أن يكون نسبة نجاح الوصول إلى ذاكرة التخزين المؤقتة هي 99%، ويمكنك معرفة هذه النسبة باستخدام التعليمات التالية:
</p>

<pre class="ipsCode">
SELECT
       sum(heap_blks_read) as heap_read, 
       sum(heap_blks_hit) as heap_hit, 
       (sum(heap_blks_hit) - sum(heap_blks_read)) / sum(heap_blks_hit) as ratio

FROM
     pg_statio_user_tables;
</pre>

<p>
	إن وجدت أن نسبة نجاح الوصول إلى التخزين المؤقتة عندك أخفض من 99% بشكل كبير، فربما يتوجب عليك زيادة حجمها المخصص لقاعدة البيانات.
</p>

<h3>
	فهم استخدام الفهارس
</h3>

<p>
	تُعد <a data-ss1613715858="1" href="https://devcenter.heroku.com/articles/postgresql-indexes?utm_source=referral&amp;utm_medium=content&amp;utm_campaign=craigkerstiens" rel="external nofollow">الفهارس</a> الطريقة الأساسية الأخرى لزيادة كفاءة قاعدة البيانات، حيث تضيف العديد من بيئات العمل الفهارس إلى المفاتيح الرئيسية في الجداول، ولكن إن كنت تُجري عمليات البحث على حقول أخرى أو تقوم بالربط بين الجداول فربما عليك إضافة الفهارس يدويًّا إلى هذه الأعمدة.
</p>

<p>
	الفهارس هي الأهم في الجداول الكبيرة، فرغم أن الوصول إلى الجداول في ذاكرة التخزين المؤقتة أسرع من الوصول إليها على القرص الصلب، إلا أنه حتى البيانات فيها يمكن أن تكون بطيئة إن كان يتوجب على Postgres أن تحلل مئات آلاف الأسطر لمعرفة إن كانت تحقق شرطًا ما.
</p>

<p>
	يمكنك استخدام التعليمة التالية لتوليد قائمة بالجداول مع النسبة المئوية لاستخدام الفهارس فيها:
</p>

<pre class="ipsCode">
SELECT
      relname, 100 * idx_scan / (seq_scan + idx_scan) percent_of_times_index_used, 
      n_live_tup rows_in_table
FROM
     pg_stat_user_tables
WHERE
     seq_scan + idx_scan \&gt; 0
ORDER BY
     n_live_tup DESC;
</pre>

<p>
	إن لم تكن قريبًا من النسبة 99% في الجداول التي تحوي 10 آلاف سطرًا فأكثر، فربما يجب عليك إضافة المزيد من الفهارس، ولكن عليك معرفة العمود المناسب الذي يجب اعتباره فهرسًا، وذلك عن طريق معرفة نوع الاستعلامات التي تتم على الجداول.
</p>

<p>
	عمومًا، قد يكون من المناسب وضع الأعمدة التي تحوي المعرّفات ID أو على الأعمدة تقوم بالتصفية على أساسها غالبًا مثل <code>created_at</code>.
</p>

<p>
	نصيحة احترافية: إن كنت تضيف فهرسًا في قاعدة بيانات قيد العمل استخدم <code>CREATE INDEX CONCURRENTLY</code> لتقوم ببناء الفهرس في الخلفية دون أن يتم قفل الجدول ومنع الاستعلامات عليه.
</p>

<p>
	يمكن أن يستغرق الإنشاء <a data-ss1613715858="1" href="http://www.postgresql.org/docs/9.1/static/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY" rel="external nofollow">الآني</a> للفهارس 2-3 أضعاف الوقت المستغرق في العادة، ولا يمكن تنفيذها على دفعات، ولكن هذه المقايضة بين الوقت وتجربة المستخدم تستحق ذلك، فلا شك أنك لا تريد توقّف الموقع الخاص بك كلما قمت بإنشاء فهرس جديد في جدول كبير الحجم.
</p>

<h3>
	مثال باستخدام بيانات حقيقية
</h3>

<p>
	عند النظر إلى بيانات حقيقية من <a data-ss1613715858="1" href="https://devcenter.heroku.com/articles/heroku-dashboard" rel="external nofollow">واجهة Heroku</a> التي تم إطلاقها مؤخرًا، يمكن تنفيذ الاستعلام التالي ورؤية النتائج كما يلي:
</p>

<pre class="ipsCode">
SELECT relname, 
       100 * idx_scan / (seq_scan + idx_scan) percent_of_times_index_used, 
       n_live_tup rows_in_table 
FROM pg_stat_user_tables 
ORDER BY n_live_tup DESC;

 relname              | percent_of_times_index_used | rows_in_table
 ---------------------+-----------------------------+--------------- 
 events               |             0               |       669917
 app_infos_user_info  |             0               |       198218 
 app_infos            |            50               |       175640
 user_info            |             3               |       46718 
 rollouts             |             0               |       34078 favorites            |             0               |       3059
 schema_migrations    |             0               |       2 
 authorizations       |             0               |       0 
 delayed_jobs         |            23               |       0
</pre>

<p>
	يمكننا أن نرى أن جدول <code>events</code> فيه 700 ألف سطرًا تقريبًا وليس فيه فهارس تم استخدامها، ومن هنا يمكننا التحقق ضمن تطبيقنا لنرى بعض الاستعلامات الشائعة التي تُستخدم، وأحد هذه الأمثلة هو جلب الأحداث لمدوّنة ما.
</p>

<p>
	يمكنك أن ترى خطة التنفيذ باستخدام التعليمة <a data-ss1613715858="1" href="https://postgresguide.com/performance/explain.html" rel="external nofollow"><code>EXPLAIN ANALYZE</code></a> التي تعطيك فكرة أفضل عن الاستعلام:
</p>

<pre class="ipsCode">
EXPLAIN ANALYZE SELECT * FROM events WHERE app_info_id = 7559;

QUERY PLAN
 -------------------------------------------------------------------
 Seq Scan on events (cost=0.00..63749.03 rows=38 width=688) (actual
 time=2.538..660.785 rows=89 loops=1) Filter: (app_info_id = 7559)
 Total runtime: 660.885 ms
</pre>

<p>
	وبما أن طريقة البحث ضمن هذا الجدول هي المسح التسلسلي، فيمكننا تحسين ذلك باستخدام فهرس، وسنضيف الفهرس الخاص بنا آنيًّا لمنع قفل الجدول، ثم سنرى كيف تتغير كفاءة الجدول:
</p>

<pre class="ipsCode">
CREATE INDEX CONCURRENTLY idx_events_app_info_id ON
events(app_info_id); 
EXPLAIN ANALYZE SELECT * FROM events WHERE app_info_id = 7559;

---------------------------------------------------------------------- 
Index Scan using idx_events_app_info_id on events (cost=0.00..23.40 rows=38 width=688) (actual time=0.021..0.115 rows=89 loops=1)
 :   Index Cond: (app_info_id = 7559)

 Total runtime: 0.200 ms
</pre>

<p>
	يتضح من التعليمة السابقة التحسن الذي أدى إليه استخدام الفهرس، ولكن يمكننا أيضًا أن نحلل النتيجة باستخدام الإضافة <a data-ss1613715858="1" href="https://elements.heroku.com/addons/newrelic" rel="external nofollow">New Relic</a> لنرى أننا خفّضنا بشكل كبير من الوقت المستغرق في المعالجة لقاعدة البيانات بإضافة هذا الفهرس وفهارس أخرى.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51684" data-ss1613715858="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/cache.png.8cf62d86e8e50d4b1cfbe9b2af7ad672.png" rel=""><img alt="cache.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51684" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/cache.png.8cf62d86e8e50d4b1cfbe9b2af7ad672.png"></a>
</p>

<h3>
	معدل نجاح الوصول إلى الفهارس في ذاكرة التخزين المؤقت
</h3>

<p>
	أخيرًا لدمج الأمرين معًا، فيمكنك استخدام التعليمة التالية في حال كنت ترغب بمعرفة معدل نجاح الوصول إلى الفهارس المخزنة ضمن ذاكرة التخزين المؤقت:
</p>

<pre class="ipsCode">
SELECT
   sum(idx_blks_read) as idx_read, 
   sum(idx_blks_hit) as idx_hit, 
   (sum(idx_blks_hit) - sum(idx_blks_read)) / sum(idx_blks_hit) as ratio
FROM
     pg_statio_user_indexes;
</pre>

<p>
	عمومًا يمكنك أن تتوقع أن يكون هذا المعدل بقيمة 99% بشكل مشابه لمعدل نجاح الوصول إلى الكاش المعتاد.
</p>

<h2>
	خلاصة
</h2>

<p>
	تعرفنا في هذا الفصل إلى طريقة تتبع أداء الاستعلامات في Postgres عن طريق التعليمة <code>EXPLAIN</code>، كما عرفنا أهمية ذاكرة التخزين المؤقتة Cache في Postgres، ويُعد هذا الفصل خطوتك الأولى في إدارة الأداء عمومًا أثناء عملك مع قواعد بيانات Postgres.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a data-ss1613715858="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%B5%D8%AF%D9%81%D8%A9-psql-r480/" rel="">أوامر متقدمة في صدفة psql</a>
	</li>
	<li>
		المقال السابق: <a data-ss1613715858="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%B0%D8%A7%D9%83%D8%B1%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r478/" rel="">أساسيات إدارة الذاكرة في قواعد بيانات Postgres</a>
	</li>
	<li>
		النسخة الكاملة من كتاب <a data-ss1613715858="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
	<li>
		<a data-ss1613715858="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D9%82%D9%84-%D9%85%D8%AC%D9%84%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-postgresql-%D8%A5%D9%84%D9%89-%D9%85%D8%B3%D8%A7%D8%B1-%D9%85%D8%AE%D8%AA%D9%84%D9%81-%D9%81%D9%8A-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r368/" rel="">كيف تنقل مجلد البيانات في PostgreSQL إلى مسار مختلف في خادم أوبنتو</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">479</guid><pubDate>Thu, 15 Oct 2020 13:00:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x625;&#x62F;&#x627;&#x631;&#x629; &#x627;&#x644;&#x630;&#x627;&#x643;&#x631;&#x629; &#x641;&#x64A; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; Postgres</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%B0%D8%A7%D9%83%D8%B1%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r478/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/8.png.4b73fd6e8569bef617528536cf61f348.png" /></p>

<p>
	سنتعرف في هذا الفصل على الملفات التي تُخزّن فيها قواعد البيانات في Postgres، وكيف نستعرض المساحات التخزينية التي تحجزها الجداول والفهارس.
</p>

<h2>
	مسارات تخزين البيانات
</h2>

<p>
	لعله من البديهي أنه لا بد من وجود مكان لتخزين البيانات لأي قواعد بيانات، وهذا المكان هو ملفات موجودة في مكان ما من الخادوم الذي يشغّل عملية <code>postgres</code>.
</p>

<p>
	لمعرفة مكان تخزين البيانات من داخل صدفة <code>psql</code> نستخدم التعليمة التالية:
</p>

<pre class="ipsCode" id="ips_uid_4946_7">
hsoubguide=# SELECT name, setting FROM pg_settings WHERE category = 'File Locations';
+
       name        |                setting                 
-------------------+----------------------------------------
 config_file       | /var/lib/pgsql/12/data/postgresql.conf
 data_directory    | /var/lib/pgsql/12/data
 external_pid_file | 
 hba_file          | /var/lib/pgsql/12/data/pg_hba.conf
 ident_file        | /var/lib/pgsql/12/data/pg_ident.conf
(5 rows)
</pre>

<p>
	تبيّن مخرجات التعليمة السابقة مسارات ملفات الإعدادات، كما تشير إلى المسار الخاص بالبيانات <code>data_directory</code> فإذا انتقلنا إلى هذا المسار واستعرضنا محتوياته سنجد ما يلي:
</p>

<pre class="ipsCode" id="ips_uid_4946_9">
-bash-4.2$ cd /var/lib/pgsql/12/data
-bash-4.2$ ls -l

total 64
drwx------. 6 postgres postgres    54 Jun 30 00:16 base
-rw-------  1 postgres postgres    30 Aug 14 14:01 current_logfiles
drwx------. 2 postgres postgres  4096 Aug 14 15:23 global
drwx------. 2 postgres postgres   188 Jun 15 00:30 log
drwx------. 2 postgres postgres     6 Jun  5 16:10 pg_commit_ts
drwx------. 2 postgres postgres     6 Jun  5 16:10 pg_dynshmem
-rw-------. 1 postgres postgres  4269 Jun  5 16:10 pg_hba.conf
-rw-------. 1 postgres postgres  1636 Jun  5 16:10 pg_ident.conf
drwx------. 4 postgres postgres    68 Aug 14 14:06 pg_logical
drwx------. 4 postgres postgres    36 Jun  5 16:10 pg_multixact
drwx------. 2 postgres postgres    18 Aug 14 14:01 pg_notify
drwx------. 2 postgres postgres     6 Jun  5 16:10 pg_replslot
drwx------. 2 postgres postgres     6 Jun  5 16:10 pg_serial
drwx------. 2 postgres postgres     6 Jun  5 16:10 pg_snapshots
drwx------. 2 postgres postgres     6 Aug 14 14:01 pg_stat
drwx------. 2 postgres postgres    63 Aug 14 15:28 pg_stat_tmp
drwx------. 2 postgres postgres    18 Jun  5 16:10 pg_subtrans
drwx------. 2 postgres postgres     6 Jun  5 16:10 pg_tblspc
drwx------. 2 postgres postgres     6 Jun  5 16:10 pg_twophase
-rw-------. 1 postgres postgres     3 Jun  5 16:10 PG_VERSION
drwx------. 3 postgres postgres    92 Jun 29 23:21 pg_wal
drwx------. 2 postgres postgres    18 Jun  5 16:10 pg_xact
-rw-------. 1 postgres postgres    88 Jun  5 16:10 postgresql.auto.conf
-rw-------. 1 postgres postgres 26632 Jun  5 16:10 postgresql.conf
-rw-------. 1 postgres postgres    58 Aug 14 14:01 postmaster.opts
-rw-------  1 postgres postgres   102 Aug 14 14:01 postmaster.pid
</pre>

<p>
	يمكنك اكتشاف الكثير عن آلية عمل postgres من الداخل في هذا المسار، ولكننا مهتمون بمعرفة مساحتها في الذاكرة، ولذا سنقوم بكتابة الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_4946_11">
-bash-4.2$ du -sh /var/lib/pgsql/12/data

66M /var/lib/pgsql/12/data
</pre>

<p>
	يُخبرنا ذلك بأن حجم جميع بيانات postgres هي 66 ميغا بايت.
</p>

<p>
	ولكننا قد نحتاج إلى معرفة حجم قاعدة بيانات أو جدول أو فهرس على حدة، ولذلك توفر Postgres طريقة مناسبة لمعرفة هذه المعلومات عن طريق الاستعلام من داخل صدفة psql أو عن طريق تعليمات الصدفة psql أيضًا.
</p>

<h2>
	معرفة حجم قاعدة البيانات
</h2>

<p>
	يمكن معرفة حجم قاعدة البيانات بشكل سهل عن طريق التوجيه <code>‎\l+‎</code> الذي يعرض قائمة لقواعد البيانات مع أحجامها في العمود <code>Size</code> ;
</p>

<pre class="ipsCode" id="ips_uid_4946_13">
hsoubguide=# \l+

                                                                    List of databases
    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   |  Size   | Tablespace |                Description             

------------+----------+----------+-------------+-------------+-----------------------+---------+------------+----------------------------------------
----
 hsoubguide | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 |                       | 9353 kB | pg_default | 
 postgres   | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 |                       | 8201 kB | pg_default | default administrative connection datab
ase
 template0  | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres          +| 8049 kB | pg_default | unmodifiable empty database
            |          |          |             |             | postgres=CTc/postgres |         |            | 
 template1  | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres          +| 8049 kB | pg_default | default template for new databases
            |          |          |             |             | postgres=CTc/postgres |         |            | 
(4 rows)
</pre>

<p>
	كما يمكننا تنفيذ الاستعلام التالي للحصول على حجم قاعدة بيانات محددة، وواحدة هذا الحجم هي البايت:
</p>

<pre class="ipsCode" id="ips_uid_4946_15">
hsoubguide=# SELECT pg_database_size('hsoubguide');

 pg_database_size 
------------------
          9577327
(1 row)
</pre>

<p>
	كما يمكننا استخدام التابع <code>pg_size_pretty</code> لإظهار الحجم بواحدة مقروءة للمستخدم مثل kB أو MB كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_4946_18">
hsoubguide=# SELECT pg_size_pretty(pg_database_size('hsoubguide'));

 pg_size_pretty 
----------------
 9353 kB
(1 row)
</pre>

<h2>
	معرفة حجم الجدول
</h2>

<p>
	يمكن استخدام التعليمة <code>‎\dt+‎</code> من صَدَفة psql لتظهر لك كل الجداول مع أحجامها:
</p>

<pre class="ipsCode" id="ips_uid_4946_20">
hsoubguide=# \dt+

                              List of relations
 Schema |         Name         | Type  |  Owner   |    Size    | Description 
--------+----------------------+-------+----------+------------+-------------
 public | basket_a             | table | postgres | 8192 bytes | 
 public | basket_b             | table | postgres | 8192 bytes | 
 public | departments          | table | postgres | 8192 bytes | 
 public | employee_departments | table | postgres | 8192 bytes | 
 public | employees            | table | postgres | 8192 bytes | 
 public | marks                | table | postgres | 8192 bytes | 
 public | names                | table | postgres | 8192 bytes | 
 public | phones               | table | postgres | 8192 bytes | 
 public | products             | table | postgres | 16 kB      | 
 public | purchase_items       | table | postgres | 328 kB     | 
 public | purchases            | table | postgres | 120 kB     | 
 public | student              | table | postgres | 16 kB      | 
 public | table1               | table | postgres | 8192 bytes | 
 public | table2               | table | postgres | 8192 bytes | 
 public | test_table           | table | postgres | 8192 bytes | 
 public | users                | table | postgres | 16 kB      | 
 public | users2               | table | postgres | 8192 bytes | 
(17 rows)
</pre>

<p>
	أو يمكنك استخدام الاستعلام التالي للحصول على حجم جدول محدد:
</p>

<pre class="ipsCode" id="ips_uid_4946_22">
hsoubguide=# SELECT pg_size_pretty(pg_relation_size('users'));

 pg_size_pretty 
----------------
 8192 bytes
(1 row)
</pre>

<h2>
	معرفة حجم الفهرس (index)
</h2>

<p>
	يمكن تطبيق التعليمة السابقة لمعرفة حجم الفهرس كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_4946_24">
hsoubguide=# SELECT pg_size_pretty(pg_relation_size('users_pkey'));

 pg_size_pretty 
----------------
 16 kB
(1 row)
</pre>

<h2>
	قياس حجم الجدول مع الفهارس
</h2>

<p>
	تُخزّن الفهارس بمعزل عن الجداول، لكن يمكنك معرفة الحجم الكلي للجدول بالإضافة للفهارس بالتعليمة التالية:
</p>

<pre class="ipsCode" id="ips_uid_4946_26">
hsoubguide=# SELECT pg_size_pretty(pg_total_relation_size('users'));

 pg_size_pretty 
----------------
 32 kB
(1 row)
</pre>

<p>
	ماذا تعني هذه الأرقام؟
</p>

<p>
	عندما تُخبرنا Postgres بأن حجم الجدول 32KB فإن هذا الرقم ليس هو بالفعل حجم البيانات المخزنة فيه، ولكنه الحجم الذي يحجزه الجدول في الذاكرة.
</p>

<p>
	ولفهم ذلك، سنقوم بإنشاء جدول بسيط ومراقبة تغير حجمه مع زيادة البيانات فيه أو نقصها:
</p>

<pre class="ipsCode" id="ips_uid_4946_28">
hsoubguide=# CREATE TABLE size_calc(msg VARCHAR(255));

CREATE TABLE
</pre>

<p>
	حجم الجدول الآن في الذاكرة، هو 0 بايت :
</p>

<pre class="ipsCode" id="ips_uid_4946_30">
hsoubguide=# SELECT pg_size_pretty(pg_total_relation_size('size_calc'));

 pg_size_pretty 
----------------
 0 bytes
(1 row)
</pre>

<p>
	سنقوم بإضافة نص من 64 حرفًا:
</p>

<pre class="ipsCode" id="ips_uid_4946_32">
hsoubguide=# INSERT INTO size_calc(msg) VALUES ('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..');

INSERT 0 1
</pre>

<p>
	وسنجد أن حجم الجدول قفز إلى 8kB فورًا:
</p>

<pre class="ipsCode" id="ips_uid_4946_34">
hsoubguide=# SELECT pg_size_pretty(pg_total_relation_size('size_calc'));

 pg_size_pretty 
----------------
 8192 bytes
(1 row)
</pre>

<p>
	ولكن ماذا لو قمنا بحذف محتويات الجدول؟
</p>

<pre class="ipsCode" id="ips_uid_4946_36">
hsoubguide=# SELECT * FROM size_calc;

                               msg                                
------------------------------------------------------------------
 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..
(1 row)

hsoubguide=# DELETE FROM size_calc;
DELETE 1
hsoubguide=# SELECT * FROM size_calc;
 msg 
-----
(0 rows)
</pre>

<p>
	رأينا أن الجدول فارغٌ الآن من المحتوى، ولكن حجمه في الذاكرة لا زال 8kB كما نرى في الاستعلام التالي:
</p>

<pre class="ipsCode" id="ips_uid_4946_38">
hsoubguide=# SELECT pg_size_pretty(pg_total_relation_size('size_calc'));

 pg_size_pretty 
----------------
 8192 bytes
(1 row)
</pre>

<p>
	إلا أنه يمكننا استخدام المكنسة الكهربائية لقواعد البيانات، التعليمة <code>VACUUM FULL</code> التي تنظّف الذاكرة من الملفات الفارغة، أو تلك التي تمددت في وقت ما، ثم لم يعد هناك حاجة إلى حجمها الكبير، كما في المثال التالي:
</p>

<pre class="ipsCode" id="ips_uid_4946_40">
hsoubguide=# VACUUM FULL;

VACUUM
hsoubguide=# SELECT pg_size_pretty(pg_total_relation_size('size_calc'));
 pg_size_pretty 
----------------
 0 bytes
(1 row)
</pre>

<h2>
	خلاصة
</h2>

<p>
	لا شك أن هذا الفصل قد ساعدك في التعرف إلى كيفية تتبع استخدام الذاكرة في قاعدة بياناتك، وقد أصبح بإمكانك معرفة الحجم الذي تستهلكه الفهارس، والحجم الذي تستهلكه الجداول عمومًا، مما سيساعدك لاحقًا في إدارة ذاكرة التخزين لقاعدة البيانات ككل.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A3%D8%AF%D8%A7%D8%A1-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r479/" rel="">كيفية إدارة الأداء في قواعد بيانات Postgres</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D9%8A%D8%A7%D8%B7%D9%8A-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r477/" rel="">إدارة النسخ الاحتياطي في قواعد بيانات Postgres</a>
	</li>
	<li>
		النسخة الكاملة من كتاب <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">478</guid><pubDate>Mon, 12 Oct 2020 13:02:00 +0000</pubDate></item><item><title>&#x625;&#x62F;&#x627;&#x631;&#x629; &#x627;&#x644;&#x646;&#x633;&#x62E; &#x627;&#x644;&#x627;&#x62D;&#x62A;&#x64A;&#x627;&#x637;&#x64A; &#x641;&#x64A; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; Postgres</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D9%8A%D8%A7%D8%B7%D9%8A-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r477/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/7.png.1a77872fee5d846295c9902483608969.png" /></p>

<p>
	نتعرف في هذا الفصل إلى كيفية أخذ نسخة احتياطية عن قاعدة البيانات الخاصة بنا، ثم نقوم باستعادتها، كما نتعرف إلى الأمر <code>‎\copy‎</code> وكيف نستخدمه لتحديد نمط البيانات في النسخة الاحتياطية.
</p>

<h2>
	النسخ الاحتياطي والاستعادة
</h2>

<p>
	النسخ الاحتياطي هو أخذ نسخة كاملة عن مخططات الجداول وبيانات قاعدة البيانات، أما الاستعادة فهي القدرة على استخدام هذه البيانات التي تم نسخها احتياطيًا وتحميلها إلى قاعدة البيانات الخاصة بك أو قاعدة بيانات اخرى.
</p>

<p>
	ملاحظة: تتم عملية النسخ الاحتياطي والاستعادة على قاعدة بيانات بأكملها أو على جدول بأكمله وليس الهدف منها استخلاص أجزاء من البيانات فقط، ففي تلك الحالة نستخدم النسخ (copy) الذي سنتحدث عنه لاحقًا.
</p>

<h3>
	إجراء النسخ الاحتياطي
</h3>

<p>
	لأخذ نسخة احتياطية من قاعدة البيانات نستخدم الأداة <a data-ss1613715754="1" data-ss1613715850="1" href="https://www.postgresql.org/docs/12/app-pgdump.html" rel="external nofollow">pg_dump</a>، وعلينا تحديد بعض الإعدادات لتحديد نتيجة عملية النسخ، ومنها:
</p>

<ul>
<li>
		هل نريد أن تكون النتيجة على شكل نص عادي (قابل للقراءة ولكنه كبير الحجم) أو بصيغة ثنائية (غير قابلة للقراءة صغيرة الحجم) أو بصيغة مضغوطة tarball (مثالي للقيام بعملية الاستعادة).
	</li>
	<li>
		هل نرغب بنسخ كل قاعدة البيانات أم مخططات (schema) أو جداول معينة.
	</li>
</ul>
<p>
	قبل البدء بالنسخ الاحتياطي قد ترغب باستعراض قواعد البيانات المخزنة لديك، باستخدام الأمر التالي:
</p>

<pre class="ipsCode">
bash-4.2$ psql -l

                                   List of databases
    Name     |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
-------------+----------+----------+-------------+-------------+-----------------------
 hsoubguide  | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | 
 hsoubguide2 | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | 
 postgres    | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | 
 template0   | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres          +
             |          |          |             |             | postgres=CTc/postgres
 template1   | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres          +
             |          |          |             |             | postgres=CTc/postgres
(5 rows)
</pre>

<p>
	لاحظ أن العمل يتم ضمن صدفة <code>bash</code> في هذه الفقرة.
</p>

<p>
	يمكنك القيام بعملية النسخ الاحتياطي باستخدام التعليمة التالية:
</p>

<pre class="ipsCode">
pg_dump database_name_here &gt; database.sql
</pre>

<p>
	فمثلًا سنقوم بأخذ نسخة احتياطية من قاعدة البيانات <code>hsoubguide</code> التي كنا نعمل عليها خلال هذا الدليل كما يلي:
</p>

<pre class="ipsCode">
bash-4.2$ pg_dump hsoubguide &gt; /tmp/hsoubguide.sql
</pre>

<p>
	خزّنّا نسخة قاعدة البيانات في ملف اسمه <code>hsoubguide.sql</code> ضمن المجلد <code>‎/‎‎tmp‎</code>، يمكنك مراجعة دليل <a data-ss1613715754="1" data-ss1613715850="1" href="https://academy.hsoub.com/devops/linux/%D9%83%D9%8A%D9%81-%D8%AA%D9%81%D9%87%D9%85-%D9%87%D9%8A%D9%83%D9%84%D9%8A%D8%A9-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D9%86%D9%83%D8%B3-r53/" rel="">كيف تفهم هيكلية نظام الملفات في لينكس</a> للتعرف أكثر إلى دور المجلد <code>tmp</code> وغيره في نظام لينكس.
</p>

<p>
	تنتج التعليمة السابقة نسخة عن قاعدة البيانات على شكل نص عادي، سنستعرض أول 50 سطرًا منها من باب الاطلاع:
</p>

<pre class="ipsCode" id="ips_uid_1855_11">
bash-4.2$ cat /tmp/hsoubguide.sql | head -50

--
-- PostgreSQL database dump
--

-- Dumped from database version 12.3
-- Dumped by pg_dump version 12.3

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- Name: hstore; Type: EXTENSION; Schema: -; Owner: -
--

CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA public;


--
-- Name: EXTENSION hstore; Type: COMMENT; Schema: -; Owner: 
--

COMMENT ON EXTENSION hstore IS 'data type for storing sets of (key, value) pairs';


SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: basket_a; Type: TABLE; Schema: public; Owner: postgres
--

CREATE TABLE public.basket_a (
    id integer NOT NULL,
    fruit character varying(100) NOT NULL
);


ALTER TABLE public.basket_a OWNER TO postgres;

--
-- Name: basket_b; Type: TABLE; Schema: public; Owner: postgres
</pre>

<p>
	ولكن بما أن النسخة الاحتياطية مكتوبة بشكلها المقروء، فإن حجمها ليس بالقليل:
</p>

<pre class="ipsCode" id="ips_uid_1855_13">
bash-4.2$ du -h /tmp/hsoubguide.sql 

212K    /tmp/hsoubguide.sql
</pre>

<p>
	بلغ حجم النسخة الاحتياطية 212 كيلو بايت تقريبًا.
</p>

<p>
	لإنشاء نسخة احتياطية أكثر ملاءمة للتخزين الدائم، يمكنك استخدام الضغط لحفظ قاعدة البيانات بشكلها الثنائي
</p>

<pre class="ipsCode">
bash-4.2$ pg_dump --format=c hsoubguide &gt; /tmp/hsoubguide.bak

bash-4.2$ du -h /tmp/hsoubguide.bak 
76K    /tmp/hsoubguide.bak
</pre>

<p>
	تمكّنّا من ضغط قاعدة البيانات 2.8 مرات تقريبا، وذلك بسبب استخدام الراية <code>format</code> مع الحرف <code>c</code> الذي يدل على الكلمة <code>custome</code>.
</p>

<p>
	للتوسع في استخدام التطبيق <code>pg_dump</code> يمكنك الرجوع إلى <a data-ss1613715754="1" data-ss1613715850="1" href="https://www.postgresql.org/docs/12/app-pgdump.html" rel="external nofollow">توثيق Postgres الرسمي</a>.
</p>

<h3>
	استعادة البيانات من نسخة احتياطية
</h3>

<p>
	ما رأيك أن نبدأ هذه الفقرة بحركة خطيرة، يمكن أن تؤدي إلى طردك من العمل؟ سنقوم بحذف قاعدة البيانات!
</p>

<pre class="ipsCode">
bash-4.2$ dropdb hsoubguide
</pre>

<p>
	في حال لم يكن لديك نسخة احتياطية من قاعدة البيانات، فيمكن أن يكون الأمر السابق هو آخر ما تقوم به في عملك، ولكنك قد أخذت نسخة احتياطية بالفعل باستخدام <code>pg_dump</code> في الفقرة السابقة، فلنقم الآن بالاستعادة.
</p>

<p>
	ملاحظة: يجدر بك تعلّم كيفية عمل نسخ احتياطي دوري تلقائي عن طريق مهام <code>cron</code> في لينكس، وقد يفيدك مقال <a data-ss1613715754="1" data-ss1613715850="1" href="https://academy.hsoub.com/devops/linux/10-%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D9%84%D8%AC%D8%AF%D9%88%D9%84%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-cron-r281/" rel="">10 أمثلة لجدولة المهام باستخدام Cron</a> في الأكاديمية.
</p>

<p>
	هناك العديد من الخيارات عند استعادة قاعدة البيانات، ولكن عملية الاستعادة لا يمكنها العمل دون وجود قاعدة بيانات بالفعل ضمن العنقود الخاص بك، لذا عليك إنشاءها ثم الاستعادة إليها كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_1855_15">
bash-4.2$ createdb hsoubguide
bash-4.2$ pg_restore --format=c --dbname=hsoubguide /tmp/hsoubguide.bak
</pre>

<p>
	للتوسع في استخدام التطبيق <code>pg_restore</code> يمكنك الرجوع إلى <a data-ss1613715754="1" data-ss1613715850="1" href="https://www.postgresql.org/docs/12/app-pgrestore.html" rel="external nofollow">توثيق Postgres الرسمي</a>.
</p>

<h3>
	النسخ (Copy)
</h3>

<p>
	يُرفق Postgres بالعديد من الأدوات المساعدة لنقل البيانات أشهرها <code>pg_dump</code> و <code>pg_restore</code> لأخذ نسخة احتياطية من قاعدة البيانات واستعادتها التي تعرفنا عليها في الفقرة السابقة. كما أن هناك أداة مشابهة بنفس القدر من الأهمية إلا أنها أقل شهرة هي أداة Postgres للنسخ التي تسمح بنسخ البيانات من الجداول في قاعدة البيانات وإليها، وتدعم هذه الأداة عدة أنماط، منها:
</p>

<ul>
<li>
		النمط الثنائي
	</li>
	<li>
		نمط الجدولة باستخدام tab
	</li>
	<li>
		نمط csv، للجدولة باستخدام الفاصلة <code>,</code>
	</li>
</ul>
<p>
	قد تحتاج إلى هذه الأداة يومًا ما سواءً لتحميل كتل من البيانات للتجربة، أو القيام ببعض من عمليات <a data-ss1613715754="1" data-ss1613715850="1" href="https://www.webopedia.com/TERM/E/ETL.html" rel="external nofollow">ETL</a>، أو حتى لاستخراج البيانات لإرسالها إلى جهة ما.
</p>

<h4>
	أمثلة عملية لاستخدام الأداة Copy
</h4>

<p>
	سنبين في هذه الفقرة بعض الأمثلة لشرح طريقة استخدام هذه الأداة، فمثلًا لاستخراج جميع الموظفين إلى ملف مُجدول بواسطة tab:
</p>

<pre class="ipsCode">
hsoubguide=# \copy (SELECT * FROM employees) TO '~/employees.tsv';

COPY 5
</pre>

<pre class="ipsCode">
hsoubguide=# quit
</pre>

<pre class="ipsCode">
bash-4.2$ ls -l

total 52
drwx------. 4 postgres postgres    51 Jun 15 02:22 12
-rw-rw-r--. 1 postgres postgres    75 Jun 30 06:12 employees.tsv
-rw-r--r--. 1 postgres postgres 46429 Jun  5 16:48 example.dump
</pre>

<pre class="ipsCode">
bash-4.2$ cat employees.tsv 

1    Jones   45000
2    Adams   50000
3    Johnson 40000
4    Williams    37000
5    Smith   55000
</pre>

<p>
	استخراج جميع الموظفين إلى ملف csv:
</p>

<pre class="ipsCode">
hsoubguide=# \copy (SELECT * FROM employees) TO '~/employees.csv' WITH (FORMAT CSV); 

COPY 5
</pre>

<pre class="ipsCode">
hsoubguide=# quit
</pre>

<pre class="ipsCode">
bash-4.2$ ls -l employees.csv

-rw-rw-r--. 1 postgres postgres 75 Jun 30 06:13 employees.csv
</pre>

<pre class="ipsCode">
bash-4.2$ cat employees.csv

1,Jones,45000
2,Adams,50000
3,Johnson,40000
4,Williams,37000
5,Smith,55000
</pre>

<p>
	استخراج جميع الموظفين إلى ملف ثنائي (لاحظ علامات التنصيص المزدوجة حول الكلمة Binary):
</p>

<pre class="ipsCode">
hsoubguide=# \copy (SELECT * FROM employees) TO '~/employees.dat' WITH (FORMAT "binary");

COPY 5
</pre>

<pre class="ipsCode">
hsoubguide=# quit
</pre>

<pre class="ipsCode">
bash-4.2$ ls -l employees.dat

-rw-rw-r--. 1 postgres postgres 161 Jun 30 06:16 employees.dat
</pre>

<pre class="ipsCode">
bash-4.2$ hexdump employees.dat

0000000 4750 4f43 5950 ff0a 0a0d 0000 0000 0000
0000010 0000 0000 0003 0000 0004 0000 0001 0000
0000020 4a05 6e6f 7365 0000 0400 0000 c8af 0300
0000030 0000 0400 0000 0200 0000 0500 6441 6d61
0000040 0073 0000 0004 c300 0050 0003 0000 0004
0000050 0000 0003 0000 4a07 686f 736e 6e6f 0000
0000060 0400 0000 409c 0300 0000 0400 0000 0400
0000070 0000 0800 6957 6c6c 6169 736d 0000 0400
0000080 0000 8890 0300 0000 0400 0000 0500 0000
0000090 0500 6d53 7469 0068 0000 0004 d600 ffd8
00000a0 00ff                                   
00000a1
</pre>

<p>
	ولتحميل البيانات من الملفات إلى جدول، فالأسطر التالية تعاكس العمليات السابقة بالترتيب:
</p>

<pre class="ipsCode">
\copy employees FROM '~/employees.tsv';
\copy employees FROM '~/employees.csv' WITH CSV;
\copy employees FROM '~/employees.dat' WITH BINARY; 
</pre>

<p>
	لتجربة الأوامر السابقة سنقوم بحذف محتويات الجدول واستعادتها كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# DELETE FROM employees;

DELETE 5
</pre>

<pre class="ipsCode">
hsoubguide=# \copy employees FROM '~/employees.csv' WITH CSV;

COPY 5
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * from employees;

 id | last_name | salary 
----+-----------+--------
  1 | Jones     |  45000
  2 | Adams     |  50000
  3 | Johnson   |  40000
  4 | Williams  |  37000
  5 | Smith     |  55000
(5 rows)
</pre>

<p>
	إن هذه التعليمة <code>‎\copy</code> مهمة خصوصًا عند الحاجة إلى إنشاء الجدول خارج صدفة <code>psql</code> عن طريق الكتابة على ملف ما ثم إدخال هذه البيانات مباشرةً إلى جدول في قاعدة البيانات.
</p>

<p>
	ولكن تجدر الإشارة إلى أنه لا يمكن استعادة جدول إلا إذا كان الجدول معرّفًا من قبل في قاعدة البيانات، فكما نرى، فإن البيانات المخزنة في الملفات ليست سوى بيانات الجدول دون تعريف لمخطط الجدول.
</p>

<h2>
	خلاصة
</h2>

<p>
	إن إدارة النسخ الاحتياطي لقاعدة البيانات أمر شديد الأهمية، ولن يقدّر أحد أهميته كما يقدرها من فقد بياناته دون أخذه مسبقًا لنسخة احتياطية، وقد تعرفنا في هذا الفصل على الأدوات المساعدة على ذلك، فاستخدمها بشكل دوري، ولا تعرض بياناتك لخطر الزوال.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a data-ss1613715754="1" data-ss1613715850="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%B0%D8%A7%D9%83%D8%B1%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r478/" rel="">أساسيات إدارة الذاكرة في قواعد بيانات Postgres</a>
	</li>
	<li>
		المقال السابق: <a data-ss1613715754="1" data-ss1613715850="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%AE%D8%A7%D8%B5%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r476/" rel="">أنواع بيانات خاصة في قواعد بيانات Postgres</a>
	</li>
	<li>
		النسخة الكاملة من كتاب <a data-ss1613715754="1" data-ss1613715850="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
	<li>
		<a data-ss1613715850="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D9%86%D8%B8%D8%A7%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-%D8%B9%D9%84%D9%89-%D8%AA%D9%88%D8%B2%D9%8A%D8%B9%D8%A9-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r378/" rel="">شرح التكرار في نظام قواعد البيانات PostgreSQL على توزيعة أوبنتو</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">477</guid><pubDate>Thu, 08 Oct 2020 13:09:00 +0000</pubDate></item><item><title>&#x623;&#x646;&#x648;&#x627;&#x639; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x62E;&#x627;&#x635;&#x629; &#x641;&#x64A; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; Postgres</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%AE%D8%A7%D8%B5%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r476/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/6.png.f4004b5f3508cea9c8087eda959f4f32.png" /></p>

<p>
	تتميز Postgres بإضافة عدة أنواع بيانات مميزة، نتحدث عنها في هذا الفصل، وهي المصفوفات Arrays والنوع Hstore والنوع JSONB وهي تساهم بشكل أساسي بالسماح بتخزين هيكل بيانات أكبر من مجرد قيمة واحدة في العمود في الجدول، كما سنستخدم الأنواع التعدادية ENUM لتحديد قيم مخصصة في أعمدة جداولنا.
</p>

<h2>
	المصفوفات (Arrays)
</h2>

<p>
	تتيح Postgres تخزين بيانات على شكل مصفوفات متغيرة الطول ضمن عمود واحد، حيث يمكن أن يكون نوع المصفوفات من الأنواع الأساسية، أو نوعًا جديدًا يحدده المستخدم أو من الأنواع التعدادية (enumerated).
</p>

<p>
	لتحديد عمود ما لتخزين مصفوفة، نقوم بوضع قوسين <code>[]</code> بعد اسم النوع كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE hsoub_team
hsoubguide-# (
hsoubguide(# team_name text,
hsoubguide(# team_members text[]
hsoubguide(# );

CREATE TABLE
</pre>

<p>
	يُنشئ الأمر السابق جدولًا اسمه <code>hsoub_team</code> له عمودان، أحدهما نص نخزّن فيه اسم الفريق، وعمود آخر <code>team_members</code> يخزن مصفوفة أحادية البعد لتخزين أسماء أعضاء الفريق.
</p>

<h3>
	إدخال قيم المصفوفات
</h3>

<pre class="ipsCode">
hsoubguide=# INSERT INTO hsoub_team
hsoubguide-# VALUES
hsoubguide-# ('postgres_team',
hsoubguide(# '{"mostafa","jamil","abood"}'
hsoubguide(# );

INSERT 0 1
</pre>

<p>
	لاحظ أن السلاسل النصية بداخل المصفوفة تكون محصورة بعلامات تنصيص مزدوجة، وذلك لأن قيمة المصفوفة كاملة هي التي تُكتب بين علامات تنصيص مفردة.
</p>

<p>
	سيُظهر استعلام الجدول ما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team ;

   team_name   |     team_members      
---------------+-----------------------
 postgres_team | {mostafa,jamil,abood}
(1 row)
</pre>

<p>
	كما يمكن بناء المصفوفات بطريقة ثانية، عن طريق استخدام باني المصفوفات (Constructor) كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO hsoub_team
hsoubguide-# VALUES
hsoubguide-# ('C++ team',
hsoubguide(# ARRAY['mostafa','yougharta']
hsoubguide(# );

INSERT 0 1
</pre>

<p>
	عند استخدام باني المصفوفات يتم حصر السلاسل النصية بعلامات تنصيص مفردة، ولا شك أن هذه الطريقة أكثر وضوحًا وأسهل مقروئيّة.
</p>

<p>
	يُعطي استعلام الجدول الآن ما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team ;

   team_name   |     team_members      
---------------+-----------------------
 postgres_team | {mostafa,jamil,abood}
 C++ team      | {mostafa,yougharta}
(2 rows)
</pre>

<p>
	ولكن لماذا نستخدم المصفوفات؟ ألم يكن بإمكاننا تخزين محتويات المصفوفة كلها كنص عادي؟ إن ميزة المصفوفات تأتي من القدرة على اختيار عنصر محدد من المصفوفة والوصول إليه، كما سنرى في الفقرة التالية.
</p>

<h3>
	الوصول إلى عناصر من المصفوفة
</h3>

<p>
	يمكن اختيار عناصر المصفوفة عن طريق رقم العنصر للوصول إلى عنصر مفرد، أو باستخدام المجال (من العنصر: إلى العنصر) كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team WHERE team_members[2] = 'jamil';

   team_name   |     team_members      
---------------+-----------------------
 postgres_team | {mostafa,jamil,abood}
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team WHERE team_members[2:3] = ARRAY['jamil','abood'];

   team_name   |     team_members      
---------------+-----------------------
 postgres_team | {mostafa,jamil,abood}
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT team_members[2:3] FROM hsoub_team ;

 team_members  
---------------
 {jamil,abood}
 {yougharta}
(2 rows)
</pre>

<p>
	<strong>ملاحظة</strong>: يجب الانتباه إلى أن ترقيم عناصر المصفوفة يبدأ من 1 وليس من 0 كما في بعض لغات البرمجة.
</p>

<h3>
	تعديل قيم عناصر المصفوفات
</h3>

<p>
	يمكن تعديل قيمة عنصر واحد في المصفوفة، كما يمكن تعديل المصفوفة كاملةً، أو مجالًا محدّدًا منها.
</p>

<p>
	فلتعديل عنصر واحد في المصفوفة، نستخدم الوصول إلى العنصر المُراد تعديله كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# UPDATE hsoub_team SET team_members[3]='new_member';

UPDATE 2
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team ;

   team_name   |          team_members          
---------------+--------------------------------
 postgres_team | {mostafa,jamil,new_member}
 C++ team      | {mostafa,yougharta,new_member}
(2 rows)
</pre>

<p>
	يمكن الوصول إلى عنصر خارج حدود المصفوفة كما في المثال السابق، ولكن يمكن كذلك تجاوز هذا الحد لتعديل العنصر رقم 5 مثلًا في مصفوفة من 3 عناصر فقط، عندها يتم ملء العناصر الفارغة بقيمة <code>NULL</code> كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# UPDATE hsoub_team SET team_members[5]='new_member2';

UPDATE 2
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team ;

   team_name   |                  team_members                  
---------------+------------------------------------------------
 postgres_team | {mostafa,jamil,new_member,NULL,new_member2}
 C++ team      | {mostafa,yougharta,new_member,NULL,new_member2}
(2 rows)
</pre>

<p>
	أما لتعديل المصفوفة كاملةً فلا نستخدم الوصول إلى عنصر مفرد، بل نقوم بتغيير قيمة العمود كاملةً:
</p>

<pre class="ipsCode">
hsoubguide=# UPDATE hsoub_team SET team_members = ARRAY ['a','b'] WHERE team_name ='C++ team';

UPDATE 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team ;

   team_name   |                team_members                
---------------+--------------------------------------------
 postgres_team | {mostafa,jamil,new_member,NULL,new_member}
 C++ team      | {a,b}
(2 rows)
</pre>

<p>
	كما يمكن تغيير قيمة مجالٍ من المصفوفة كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# UPDATE hsoub_team SET team_members[2:3] = ARRAY['x','y'] WHERE team_name LIKE 'postgres%';

UPDATE 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team ;

   team_name   |         team_members          
---------------+-------------------------------
 C++ team      | {a,b}
 postgres_team | {mostafa,x,y,NULL,new_member}
(2 rows)
</pre>

<p>
	<strong>ملاحظة</strong>: يجب أن يكون حجم المجال المُستبدل مساويًا أو أصغر من طول المصفوفة الجديدة، فلو حاولنا استبدال مجالٍ بمجالٍ أصغر منها سيظهر الخطأ التالي:
</p>

<pre class="ipsCode">
hsoubguide=# UPDATE hsoub_team SET team_members[2:4] = ARRAY['one_member']  WHERE team_name LIKE 'postgres%';

ERROR:  source array too small
</pre>

<p>
	أما إن كان حجم المصفوفة الجديدة أكبر من الأصلية، فيتم أخذ عدد من العناصر مساوٍ للمجال الأصلي، كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# UPDATE hsoub_team SET team_members[2:4] = ARRAY['one_member','a','b','c','d','e']  WHERE team_name LIKE 'postgres%';

UPDATE 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team ;

   team_name   |            team_members             
---------------+-------------------------------------
 C++ team      | {a,b}
 postgres_team | {mostafa,one_member,a,b,new_member}
(2 rows)
</pre>

<h3>
	البحث ضمن المصفوفات
</h3>

<p>
	للبحث عن عنصر معين ضمن المصفوفة نستخدم الكلمة المفتاحية <code>ANY</code> كما يوضح المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team WHERE 'mostafa' = ANY(team_members);

   team_name   |            team_members             
---------------+-------------------------------------
 postgres_team | {mostafa,one_member,a,b,new_member}
(1 row)
</pre>

<p>
	ويمكن البحث للتحقق من كون كل قيم المصفوفة تطابق قيمة معينة باستخدام الكلمة <code>ALL</code>.
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO hsoub_team
hsoubguide-# VALUES
hsoubguide-# ('team1',
hsoubguide(# ARRAY['programmer1','programmer1','programmer1']
hsoubguide(# );

INSERT 0 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team WHERE 'programmer1' = ALL(team_members);
 team_name |             team_members              
-----------+---------------------------------------
 team1     | {programmer1,programmer1,programmer1}
(1 row)
</pre>

<p>
	كما يمكن استخدام <code>ALL</code> مع تحديد المجال ضمن المصفوفة كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO hsoub_team
VALUES
('team7',
ARRAY['programmer1','programmer1','another_programmer']
);

INSERT 0 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM hsoub_team WHERE 'programmer1' = ALL(team_members[1:2]);

 team_name |                 team_members                 
-----------+----------------------------------------------
 team1     | {programmer1,programmer1,programmer1}
 team7     | {programmer1,programmer1,another_programmer}
(2 rows)
</pre>

<h2>
	أنواع البيانات التعدادية (Enumerated Data Types)
</h2>

<p>
	توفر Postgres نوع بيانات تعدادية <code>enums</code> تُستخدم لحصر قيم عمود ما في مجموعة قيم محددة مسبقًا من القيم.
</p>

<p>
	سنقوم في المثال التالي بحصر قيم العمود <code>contact_method</code> بمجموعة القيم <code>Email</code> و <code>SMS</code> و <code>Phone</code>، وذلك عن طريق تعريف التعداد كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TYPE e_contact_method AS ENUM (
hsoubguide(# 'Email',
hsoubguide(# 'Sms',
hsoubguide(# 'Phone');

CREATE TYPE
</pre>

<p>
	ومن ثم نرفق نوع التعداد الجديد بالعمود الذي نريد حصر قيمه كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE contact_method_info (
hsoubguide(# contact_name text,
hsoubguide(# contact_method e_contact_method,
hsoubguide(# value text
hsoubguide(# );

CREATE TABLE
</pre>

<h3>
	استخدام الأنواع التعدادية
</h3>

<p>
	سنحاول في هذا المثال إدخال قيم في العمود الذي يستخدم النوع التعدادي، لنرى ما يحصل عند الخروج عن القيم المحددة مسبقًا:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO contact_method_info
hsoubguide-# VALUES ('Jamil', 'Email', 'jamil@mail.com');
INSERT 0 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM contact_method_info ;
 contact_name | contact_method |     value      
--------------+----------------+----------------
 Jamil        | Email          | jamil@mail.com
(1 row)
</pre>

<p>
	لا يمكن إدراج قيمة للعمود <code>contact_method</code> غير موجودة سلفًا ضمن التعداد <code>e_contact_method</code> وسيظهر خطأ كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO contact_method_info VALUES ('Jamil', 'Fax', '4563456');

ERROR:  invalid input value for enum e_contact_method: "Fax"
LINE 1: INSERT INTO contact_method_info VALUES ('Jamil', 'Fax', '456...
</pre>

<h2>
	عرض وتعديل قيم التعداد
</h2>

<p>
	يمكننا عرض قائمة القيم في التعداد بالاستعانة بالجداول pg_type و pg_enum التي تُخزّن إعدادات الأنواع والتعدادات، وذلك كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT pg_type.typname, pg_enum.enumlabel
hsoubguide-# FROM pg_type,pg_enum
hsoubguide-# WHERE pg_type.oid = pg_enum.enumtypid;

     typname      | enumlabel 
------------------+-----------
 e_contact_method | Email
 e_contact_method | Sms
 e_contact_method | Phone
(3 rows)
</pre>

<p>
	كما يمكن إضافة قيم للتعدادات الموجودة مسبقًا كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# ALTER TYPE e_contact_method
hsoubguide-# ADD VALUE 'Facebook' AFTER 'Phone';

ALTER TYPE
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT pg_type.typname, pg_enum.enumlabel
hsoubguide-# FROM pg_type,pg_enum
hsoubguide-# WHERE pg_type.oid = pg_enum.enumtypid;

     typname      | enumlabel 
------------------+-----------
 e_contact_method | Email
 e_contact_method | Sms
 e_contact_method | Phone
 e_contact_method | Facebook
(4 rows)
</pre>

<p>
	يتم حفظ ترتيب القيم داخل التعدادات بنفس الترتيب الذي تم إدخال القيم به، ولكن يمكن إدخال قيم جديدة وتحديد مكانها قبل قيمة معينة أو بعدها، كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# ALTER TYPE e_contact_method
hsoubguide-# ADD VALUE 'Twitter' BEFORE 'Sms';

ALTER TYPE
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT pg_type.typname,pg_enum.enumlabel,pg_enum.enumsortorder
hsoubguide-# FROM pg_type, pg_enum
hsoubguide-# WHERE pg_type.oid = pg_enum.enumtypid
hsoubguide-# ORDER BY pg_enum.enumsortorder;

     typname      | enumlabel | enumsortorder 
------------------+-----------+---------------
 e_contact_method | Email     |             1
 e_contact_method | Twitter   |           1.5
 e_contact_method | Sms       |             2
 e_contact_method | Phone     |             3
 e_contact_method | Facebook  |             4
(5 rows)
</pre>

<p>
	لا تسمح Postgres بإزالة قيم من التعدادات ولا بتغيير ترتيبها، وللقيام بذلك علينا حذف التعداد عن طريق التعليمة <code>DROP TYPE</code>، ولكن انتبه إلى أنه لا يمكنك حذف التعداد إذا كان هناك أعمدة تستخدم هذا النوع، لكن يمكنك حذف التعداد مع جميع الأعمدة المرتبطة به باستخدام الكلمة المفتاحية <code>CASCADE</code>، ولتوضيح ذلك لدينا المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# DROP TYPE e_contact_method CASCADE;

NOTICE:  drop cascades to column contact_method of table contact_method_info
DROP TYPE
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT pg_type.typname, pg_enum.enumlabel
FROM pg_type,pg_enum                     
WHERE pg_type.oid = pg_enum.enumtypid;

 typname | enumlabel 
---------+-----------
(0 rows)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM contact_method_info ;

 contact_name |     value      
--------------+----------------
 Jamil        | jamil@mail.com
(1 row)
</pre>

<h2>
	نوع البيانات HStore
</h2>

<p>
	HStore هو أسلوب تخزين (مفتاح، قيمة) ضمن Postgres يُستخدم مثل القاموس، لكنه مخصص لعمود في سطر ما.
</p>

<h3>
	تفعيل HStore
</h3>

<p>
	لتفعيل HStore في قاعدة البيانات قم بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE EXTENSION hstore;

CREATE EXTENSION
</pre>

<h3>
	إنشاء عمود HStore
</h3>

<p>
	لإنشاء حقل في جدول ذو نوع بيانات HStore استخدم HStore كنوع للعمود ببساطة كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE students (
hsoubguide-# id serial PRIMARY KEY,
hsoubguide-# name varchar,
hsoubguide-# attributes hstore
hsoubguide-# );

CREATE TABLE
</pre>

<h3>
	إدخال بيانات من نوع HStore
</h3>

<p>
	لإدخال البيانات عليك كتابتها ضمن علامات تنصيص مفردة. الفرق في HStore هو بنية إضافية لتوضيح كيفية إنشاء القاموس:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO students (name,attributes) VALUES(
hsoubguide(# 'mostafa',
hsoubguide(# 'nickname =&gt; mayesh,
hsoubguide'# grade =&gt; 12,
hsoubguide'# school =&gt; "Hsoub Academy",
hsoubguide'# weight =&gt; 82'
hsoubguide(# );

INSERT 0 1
</pre>

<p>
	إن استخدام النوع HStore كان من أوائل المحاولات في الخروج عن هيكلة قواعد البيانات، ومن ثم فهو من أوائل أنواع NoSQL التي ظهرت، فليس هناك محددات للعناصر التي يمكننا تخزينها في HStore.
</p>

<h3>
	الوصول إلى بيانات من نوع HStore
</h3>

<p>
	يمكننا استخدام العملية <code>&lt;-</code> للوصول إلى عناصر في داخل العنصر من النوع Hstore، وذلك بتحديد اسم المفتاح كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT name,attributes-&gt;'school'
hsoubguide=# FROM students
hsoubguide=# WHERE attributes-&gt;'nickname' = 'mayesh';

  name   |   ?column?    
---------+---------------
 mostafa | Hsoub Academy
(1 row)
</pre>

<p>
	لتغيير اسم العمود بدلًا من <code>?column?</code> استخدم <code>AS</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT name,attributes-&gt;'school' AS school
FROM students
WHERE attributes-&gt;'nickname' = 'mayesh';

  name   |    school     
---------+---------------
 mostafa | Hsoub Academy
(1 row)
</pre>

<p>
	بما أنه لا توجد قيود على المفاتيح المخزنة بداخل النوع Hstore فإنه من الممكن أن يوجد مفتاحُ ما في سطر ما، ولا يوجد في سطر آخر، وعندها يُتعامل معه على أنه موجود بقيمة خالية، كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO students (name,attributes) VALUES(
hsoubguide(# 'Jamil',
hsoubguide(# 'grade =&gt; 13
hsoubguide'# ,
hsoubguide'# weight =&gt; 72');

INSERT 0 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM students;

 id |  name   |                                   attributes                                   
----+---------+--------------------------------------------------------------------------------
  1 | mostafa | "grade"=&gt;"12", "school"=&gt;"Hsoub Academy", "weight"=&gt;"82", "nickname"=&gt;"mayesh"
  2 | Jamil   | "grade"=&gt;"13", "weight"=&gt;"72"
(2 rows)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT name,attributes-&gt;'school' AS school FROM students;

  name   |    school     
---------+---------------
 mostafa | Hsoub Academy
 Jamil   | 
(2 rows)
</pre>

<p>
	يتيح استخدام Hstore مرونة عالية في قاعدة البيانات، ولكنها أصبحت تقنية قديمة مقارنةً بتقنية النوع JSONB التي سنتحدث عنها في الفقرة التالية.
</p>

<h2>
	بيانات بصيغة JSON
</h2>

<p>
	ظهر استخدام JSON في postgres بدءًا من الإصدار 9.2، لكن الإصدار الحقيقي ظهر باسم JSONB في postgres 9.4.
</p>

<p>
	JSNOB هي الصيغة الثنائية لتعابير JSON للتخزين الدائم، فهي أكثر كفاءة في التخزين والفهرسة.
</p>

<h3>
	إنشاء أعمدة JSONB
</h3>

<p>
	لإنشاء أعمدة من النوع JSONB حدد النوع JSONB ضمن تعليمة <code>CREATE TABLE</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE school (
hsoubguide(#     id serial PRIMARY KEY,
hsoubguide(#     name varchar,
hsoubguide(#     attributes JSONB
hsoubguide(# );

CREATE TABLE
</pre>

<h3>
	إدخال البيانات من النوع JSONB
</h3>

<p>
	يُفترض أن يكون إدخال عمود يحتوي على صيغة JSON سهلًا ومباشرًا، ونوضّحه بالمثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO school (name,attributes) VALUES (
hsoubguide(#     'Hsoub', '{
hsoubguide'#     "manager" : "Agha",
hsoubguide'#     "classes" : 7,
hsoubguide'#     "teachers": 12}'
hsoubguide(# );

INSERT 0 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM school;

 id | name  |                    attributes                     
----+-------+---------------------------------------------------
  1 | Hsoub | {"classes": 7, "manager": "Agha", "teachers": 12}
(1 row)
</pre>

<h3>
	الوصول إلى قيم المفاتيح في JSONB
</h3>

<p>
	يمكننا استخدام العملية <code>&lt;-</code> للوصول إلى القيم عن طريق أسماء مفاتيحها، كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT name,attributes-&gt;'manager' AS manager FROM school;

 name  | manager 
-------+---------
 Hsoub | "Agha"
(1 row)
</pre>

<p>
	ويمكننا استخدامها داخل شروط التصفية كذلك:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM school WHERE attributes-&gt;'classes' = '7';

 id | name  |                    attributes                     
----+-------+---------------------------------------------------
  1 | Hsoub | {"classes": 7, "manager": "Agha", "teachers": 12}
(1 row)
</pre>

<p>
	هناك العديد من الأمور المتقدمة التي يمكن القيام بها في JSONB، ولكن يجب أن نعرف أنها مخصصة لتخزين العناصر والوصول إليها، ولكنها لم تصمم لتعديل العناصر بعد تخزينها.
</p>

<h2>
	التعامل مع التاريخ والوقت
</h2>

<p>
	يمكن تخزين التاريخ والوقت في Postgres باستخدام عدة أنواع، كما تتيح العديد من الطرق للتعامل المرن مع التواريخ والأوقات، النوع الأساسي لتخزين التاريخ هو <code>DATE</code> ولتخزين الوقت <code>TIME</code>، ويمكننا حفظ التاريخ مع الوقت باستخدام النوع <code>TIMESTAMP</code>.
</p>

<p>
	سننشئ جدولًا جديدًا لتعلم التعامل مع هذه الأنواع الجديدة:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE date_example(
hsoubguide(#     mydate DATE NOT NULL DEFAULT CURRENT_DATE,
hsoubguide(#     mytime TIME NOT NULL DEFAULT CURRENT_TIME,
hsoubguide(#     mytimestamp TIMESTAMP NOT NULL DEFAULT NOW()
hsoubguide(# );

CREATE TABLE
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM date_example;
 mydate | mytime | mytimestamp 
--------+--------+-------------
(0 rows)
</pre>

<p>
	أنشأنا في الجدول السابق ثلاث أعمدة، لكل منها قمنا بمنع تخزين القيمة الخالية عن طريق <code>NOT NULL</code>، واستخدمنا القيم الافتراضية التالية:
</p>

<ul>
<li>
		التاريخ الحالي، باستخدام <code>CURRENT_DATE</code>
	</li>
	<li>
		الوقت الحالي، باستخدام <code>CURRENT_TIME</code>
	</li>
	<li>
		التاريخ والوقت الحالي، باستخدام التابع <code>NOW()‎</code>
	</li>
</ul>
<p>
	سندخل الآن سطرًا مميزًا، حيث لن نحدد فيه أي قيمة، بل سنستخدم التوجيه <code>DEFAULT VALUES</code> كي يتم إدخال جميع القيم الافتراضية كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO date_example DEFAULT VALUES;

INSERT 0 1
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM date_example;
   mydate   |     mytime      |        mytimestamp         
------------+-----------------+----------------------------
 2020-08-22 | 01:24:08.241482 | 2020-08-22 01:24:08.241482
(1 row)
</pre>

<p>
	كما يظهر استعلام الجدول السابق، يتم إظهار التاريخ بالتنسيق <code>yyyy-mm-dd</code>.
</p>

<h3>
	استخدام لتابع <code>NOW()‎</code>
</h3>

<p>
	يمكننا استخدام التابع <code>NOW()‎</code> للاستعلام عن التاريخ والوقت كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT NOW();

              now              
-------------------------------
 2020-08-22 01:26:48.875054+03
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT NOW()::DATE;

    now     
------------
 2020-08-22
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT NOW()::TIME;

       now       
-----------------
 01:26:55.072126
(1 row)
</pre>

<h3>
	استخدام التابع <code>TO_CHAR()‎</code>
</h3>

<p>
	كما يمكننا تحديد النسق الذي نرغب بعرض التاريخ فيه من خلال التابع <code>TO_CHAR()‎</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT TO_CHAR(NOW()::DATE,'dd ++ mm ++ yyyy');

     to_char      
------------------
 22 ++ 08 ++ 2020
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT TO_CHAR(NOW()::DATE,'Month dd/mm/yyyy');

       to_char        
----------------------
 August    22/08/2020
(1 row)
</pre>

<p>
	يمكننا استخدام التابع <code>AGE()‎</code> لحساب فارق التاريخ وإظهاره بنفس تنسيق التاريخ كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT AGE(CURRENT_DATE,'25-07-1993');

       age        
------------------
 27 years 28 days
(1 row)
</pre>

<p>
	كما يمكننا استخدام عملية الطرح للتواريخ <code>-</code> للحصول على الفرق بالأيام كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT CURRENT_DATE-'25-07-1993' AS days;

 days 
------
 9890
(1 row)
</pre>

<p>
	للحصول على فارق الوقت كذلك علينا تحديد نوع البيانات التي نقوم بطرحها على أنها بيانات وقت:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT time '10:57:18' - time '02:17:17' AS result;

  result  
----------
 08:40:01
(1 row)
</pre>

<p>
	<strong>ملاحظة</strong>: انتبه إلى إضافة النوع <code>time</code> قبل الوقت المطروح، وإلا سيظهر الخطأ التالي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT '10:57:18' - '02:17:17' AS result;

ERROR:  operator is not unique: unknown - unknown
LINE 1: SELECT '10:57:18' - '02:17:17' AS result;
                          ^
HINT:  Could not choose a best candidate operator. You might need to add explicit type casts.
</pre>

<h3>
	استخدام التابع <code>EXTRACT()‎</code>
</h3>

<p>
	لعل أحد أكثر التوابع فائدةً هو التابع <code>EXTRACT()‎</code> كما يمكننا استخلاص السنة والشهر واليوم من التاريخ كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT EXTRACT(YEAR FROM TIMESTAMP '2016-12-31 13:30:15');

 date_part 
-----------
      2016
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT EXTRACT(MONTH FROM TIMESTAMP '2016-12-31 13:30:15');

 date_part 
-----------
        12
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT EXTRACT(DAY FROM TIMESTAMP '2016-12-31 13:30:15');

 date_part 
-----------
        31
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT EXTRACT(HOUR FROM TIMESTAMP '2016-12-31 13:30:15');

 date_part 
-----------
        13
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT EXTRACT(MINUTES FROM TIMESTAMP '2016-12-31 13:30:15');

 date_part 
-----------
        30
(1 row)
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT EXTRACT(SECONDS FROM TIMESTAMP '2016-12-31 13:30:15');

 date_part 
-----------
        15
(1 row)
</pre>

<h3>
	تخزين المدد الزمنية INTERVAL
</h3>

<p>
	تتيح كذلك Postgres استخدام نوع مميز لتخزين المدة الزمنية <code>INTERVAL</code>، وسننشئ جدولًا صغيرًا لتعلّم كيفية استخدامه:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE date_example2(
hsoubguide(#     myinterval INTERVAL
hsoubguide(# );

CREATE TABLE
</pre>

<p>
	يمكننا تخزين مدة زمنية كسنوات كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO date_example2(myinterval) VALUES ('2 years');

INSERT 0 1
</pre>

<p>
	أو كسنوات وأشهر:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO date_example2(myinterval) VALUES ('2 years 3 months');

INSERT 0 1
</pre>

<p>
	كما يمكن تخزين مدة زمنية في الماضي باستخدام الكلمة <code>ago</code>:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO date_example2(myinterval) VALUES ('2 years 3 months ago');

INSERT 0 1
</pre>

<p>
	يمكننا كذلك تخزين التاريخ مع الوقت كمدة زمنية:
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO date_example2(myinterval) VALUES ('2 years 3 months 5 days 33 minutes');

INSERT 0 1
</pre>

<pre class="ipsCode">
hsoubguide=# INSERT INTO date_example2(myinterval) VALUES ('2 years 3 months 5 days 33 minutes ago');

INSERT 0 1
</pre>

<p>
	وعند الاستعلام عن كل هذه المدد الزمنية سنجد أنها مخزنة كما أدخلناها، باستثناء المدد التي أضفنا لها كلمة <code>ago</code> قد أضيف لها إشارة السالب:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM date_example2;

             myinterval             
------------------------------------
 2 years
 2 years 3 mons
 -2 years -3 mons
 2 years 3 mons 5 days 00:33:00
 -2 years -3 mons -5 days -00:33:00
(5 rows)
</pre>

<p>
	تكمن فائدة استخدام المدد الزمنية عند الحاجة إلى الرجوع بتاريخ معين إلى مدة زمنية محددة كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT NOW() - INTERVAL '1 year 2 months 3 days 4 hours 5 minutes 6 seconds' AS "1 year,2 months,3 days,04h:05m:06s ago";

 1 year,2 months,3 days,04h:05m:06s ago 
----------------------------------------
 2019-06-18 22:36:02.945923+03
(1 row)
</pre>

<h2>
	خلاصة
</h2>

<p>
	تتميز Postgres عن الأصل SQL بوجود أنواع البيانات الخاصة Arrays و JSONB و HSTORE التي تسمح بتخزين مجموعات مرتبة من البيانات ضمن عمود واحد، وقد تعرفنا إلى كل منها في هذا الفصل، مما يعطينا القدرة على تخزين البيانات بطريقة أكثر احترافية باستخدام Postgres، وقد تعرفنا كذلك في هذا الفصل إلى النوع ENUM الذي يحدد القيمة المخزنة ضمن العمود بقيم معرفة مسبقًا.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D9%8A%D8%A7%D8%B7%D9%8A-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r477/" rel="">إدارة النسخ الاحتياطي في قواعد بيانات Postgres</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%85%D8%B2%D8%A7%D9%8A%D8%A7-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-postgres-r475/" rel="">مزايا متقدمة في Postgres</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">476</guid><pubDate>Mon, 05 Oct 2020 13:01:00 +0000</pubDate></item><item><title>&#x645;&#x632;&#x627;&#x64A;&#x627; &#x645;&#x62A;&#x642;&#x62F;&#x645;&#x629; &#x641;&#x64A; Postgres</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%85%D8%B2%D8%A7%D9%8A%D8%A7-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-postgres-r475/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/5.png.7c33345644f0bd684f7f9b466bf8d9a7.png" /></p>

<p>
	نتعرف في هذا الفصل إلى العرض View وتعابير الجداول الشائعة CTE التي تساهم في تحسين طريقة كتابة الاستعلامات، وذلك يجعلها أقصر وأسهل قراءةً، وسنتعلم استخدام دوال النوافذ Window Functions التي تسمح بإجراء عمليات تجميعية على مجموعة جزئية من الأسطر، كما سنتعرف على الفهارس وأهميتها في تسريع البحث ضمن البيانات.
</p>

<h2>
	العرض View
</h2>

<p>
	هو جدول منطقي يقوم بوصل أجزاء البيانات الأساسية تلقائيًا، فهو لا يقوم بتكرار البيانات ولا الاحتفاظ فيها، بل يعيد ترتيبها لعرضها فقط.
</p>

<p>
	وتكمن فوائد استخدام العرض في تبسيط نموذج البيانات عند الحاجة إلى تقديمه للآخرين للعمل عليه، كما يمكن استخدامه لتبسيط العمل بالبيانات الخاصة بك.
</p>

<p>
	وإذا وجدت نفسك تدمج نفس المجموعة من البيانات بشكل متكرر فيمكن للعرض تسهيل هذه العملية بدلًا من تكرارها عدة مرات.
</p>

<p>
	وكذلك عند العمل مع أشخاص غير تقنيين ليسوا على دراية بلغة SQL يكون العرض هو الطريقة المُثلى لتقديم البيانات غير المنتظمة.
</p>

<h3>
	طريقة عمل العرض
</h3>

<p>
	فنلقِ نظرةً على الجداول التالية أولًا:
</p>

<ul>
<li>
		جدول أقسام الشركة:
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51665" data-ss1613715704="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/departments.png.a45191567b58eaa6f0fec13a60422f26.png" rel=""><img alt="departments.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51665" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/departments.png.a45191567b58eaa6f0fec13a60422f26.png" style="width: 450px; height: auto;"></a>
</p>

<ul>
<li>
		الجدول الذي يحدد انتماء الموظف إلى قسم معين:
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51666" data-ss1613715704="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/employee_departmens.png.b24f57acee481197d8191c96a66c9a44.png" rel=""><img alt="employee_departmens.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51666" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/employee_departmens.png.b24f57acee481197d8191c96a66c9a44.png" style="width: 450px; height: auto;"></a>
</p>

<ul>
<li>
		جدول الموظفين:
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51663" data-ss1613715704="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/employees.png.33e0b9cf27add523a06fdedd0be55c6e.png" rel=""><img alt="employees.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51663" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/employees.png.33e0b9cf27add523a06fdedd0be55c6e.png" style="width: 450px; height: auto;"></a>
</p>

<p>
	يمكنك نسخ التعليمات التالية لإنشاء الجداول وإدخال البيانات المذكورة في الصور السابقة.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_10" style="">
<span class="pln">CREATE TABLE departments</span><span class="pun">(</span><span class="pln">
    id serial PRIMARY KEY</span><span class="pun">,</span><span class="pln">
    department VARCHAR </span><span class="pun">(</span><span class="lit">50</span><span class="pun">)</span><span class="pln"> UNIQUE NOT NULL
</span><span class="pun">);</span><span class="pln">


INSERT INTO departments </span><span class="pun">(</span><span class="pln">department</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Accounting'</span><span class="pun">),(</span><span class="str">'Marketing'</span><span class="pun">),(</span><span class="str">'Sales'</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_12" style="">
<span class="pln">CREATE TABLE employees</span><span class="pun">(</span><span class="pln">
id serial PRIMARY KEY</span><span class="pun">,</span><span class="pln">
last_name VARCHAR </span><span class="pun">(</span><span class="lit">50</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
salary </span><span class="kwd">int</span><span class="pln"> NOT NULL
</span><span class="pun">);</span><span class="pln">


INSERT INTO employees </span><span class="pun">(</span><span class="pln">last_name</span><span class="pun">,</span><span class="pln">salary</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Jones'</span><span class="pun">,</span><span class="lit">45000</span><span class="pun">),(</span><span class="str">'Adams'</span><span class="pun">,</span><span class="lit">50000</span><span class="pun">),(</span><span class="str">'Johnson'</span><span class="pun">,</span><span class="lit">40000</span><span class="pun">),(</span><span class="str">'Williams'</span><span class="pun">,</span><span class="lit">37000</span><span class="pun">),(</span><span class="str">'Smith'</span><span class="pun">,</span><span class="lit">55000</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_14" style="">
<span class="pln">CREATE TABLE employee_departments</span><span class="pun">(</span><span class="pln">
employee_id </span><span class="kwd">int</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
department_id </span><span class="kwd">int</span><span class="pln"> NOT NULL
</span><span class="pun">);</span><span class="pln">

INSERT INTO employee_departments VALUES </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">1</span><span class="pun">),(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">3</span><span class="pun">),(</span><span class="lit">3</span><span class="pun">,</span><span class="lit">2</span><span class="pun">),(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">1</span><span class="pun">),(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">3</span><span class="pun">);</span></pre>

<p>
	وللتأكد من أن الجداول أُنشئت على الوجه الصحيح وأُدخلت البيانات كما هو مخطط، فسنستعرض الجداول كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_2402_16">
hsoubguide=# SELECT * FROM departments;

 id | department 
----+------------
  1 | Accounting
  2 | Marketing
  3 | Sales
(3 rows)
</pre>

<pre class="ipsCode" id="ips_uid_2402_18">
hsoubguide=# SELECT * FROM employees;

 id | last_name | salary 
----+-----------+--------
  1 | Jones     |  45000
  2 | Adams     |  50000
  3 | Johnson   |  40000
  4 | Williams  |  37000
  5 | Smith     |  55000
(5 rows)
</pre>

<pre class="ipsCode" id="ips_uid_2402_20">
hsoubguide=# SELECT * FROM employee_departments ;

 employee_id | department_id 
-------------+---------------
           1 |             1
           2 |             3
           3 |             2
           4 |             1
           5 |             3
(5 rows)
</pre>

<p>
	نهدف في المثال التالي إلى عرض أسماء الموظفين مع رواتبهم والقسم الذي ينتمون إليه، وللقيام بذلك سنكتب الاستعلام التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_22" style="">
<span class="pln">SELECT 
  employees</span><span class="pun">.</span><span class="pln">last_name</span><span class="pun">,</span><span class="pln"> 
  employees</span><span class="pun">.</span><span class="pln">salary</span><span class="pun">,</span><span class="pln"> 
  departments</span><span class="pun">.</span><span class="pln">department
FROM 
  employees</span><span class="pun">,</span><span class="pln"> 
  employee_departments</span><span class="pun">,</span><span class="pln">
  departments
WHERE 
  employees</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> employee_departments</span><span class="pun">.</span><span class="pln">employee_id
  AND
  departments</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> employee_departments</span><span class="pun">.</span><span class="pln">department_id</span><span class="pun">;</span></pre>

<p>
	وتكون المخرجات كما يلي:
</p>

<pre class="ipsCode">
 last_name | salary | department 
-----------+--------+------------
 Jones     |  45000 | Accounting
 Adams     |  50000 | Sales
 Johnson   |  40000 | Marketing
 Williams  |  37000 | Accounting
 Smith     |  55000 | Sales
(5 rows)
</pre>

<p>
	إذا أمعنت النظر في الجدول السابق في المخرجات، قد تتمنى لو أنه مخزّن في الذاكرة بالفعل، فبدلًا من القيام بالعديد من عمليات الربط من هذا الجدول أو ذاك، كان يمكن أن نتعامل مع هذا الجدول مباشرةً بدلًا من كتابة الاستعلام الطويل ذاك في كل مرة نريد استعراض الموظفين مع رواتبهم وأقسامهم، ولكن في الحقيقة، يمكننا إنشاء جدول وهمي عن طريق العرض View لتحقيق هذه الأمنية، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_25" style="">
<span class="pln">CREATE OR REPLACE VIEW employee_view AS
SELECT 
  employees</span><span class="pun">.</span><span class="pln">last_name</span><span class="pun">,</span><span class="pln"> 
  employees</span><span class="pun">.</span><span class="pln">salary</span><span class="pun">,</span><span class="pln"> 
  departments</span><span class="pun">.</span><span class="pln">department
FROM 
  employees</span><span class="pun">,</span><span class="pln"> 
  employee_departments</span><span class="pun">,</span><span class="pln">
  departments
WHERE 
  employees</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> employee_departments</span><span class="pun">.</span><span class="pln">employee_id
  AND departments</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> employee_departments</span><span class="pun">.</span><span class="pln">department_id</span><span class="pun">;</span></pre>

<p>
	يمكن الآن القيام باستعلام على الجدول الافتراضي الجديد مباشرًة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_27" style="">
<span class="pln">SELECT </span><span class="pun">*</span><span class="pln">
FROM employee_view</span><span class="pun">;</span></pre>

<p>
	وستظهر البيانات بشكل مشابه لعملية الربط التي قمنا بها سابقًأ كما يلي:
</p>

<pre class="ipsCode">
 last_name | salary | department 
-----------+--------+------------
 Jones     |  45000 | Accounting
 Adams     |  50000 | Sales
 Johnson   |  40000 | Marketing
 Williams  |  37000 | Accounting
 Smith     |  55000 | Sales
(5 rows)
</pre>

<p>
	كما يمكننا التعامل مع هذا الجدول المنطقي وكأنه جدول حقيقي، فمثلًا يمكننا الاستعلام عن أسطر هذا الجدول مع ترشيحها أو القيام بأي عملية أخرى تتم على الجداول العادية المخزنة كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM employee_view WHERE salary &gt; 40000;

 last_name | salary | department 
-----------+--------+------------
 Jones     |  45000 | Accounting
 Adams     |  50000 | Sales
 Smith     |  55000 | Sales
(3 rows)
</pre>

<p>
	والآن صار بالإمكان تبسيط الاستعلامات الطويلة المتكررة والمتداخلة عن طريق استخدام العرض.
</p>

<h2>
	عبارات الجداول الشائعة (CTE)
</h2>

<p>
	تشبه عبارات الجداول الشائعة CTE العرض View في بعض النواحي، فهي نتيجة مؤقتة لاستعلام سابق، يمكننا القيام بعمليات استعلام عليها مرة آخرى دون أن يكون لها وجود دائم في الذاكرة.
</p>

<p>
	فهي تشكل جدولًا افتراضيًّا جديدًا ناتجًا عن الاستعلام الأول، ويمكننا القيام بعمليات على هذا الجدول، دون أن يكون له تخزين دائم في الذاكرة.
</p>

<p>
	الاستخدام الأساسي لها هو تبسيط الاستعلامات المعقدة، أو الاستعلامات التي تربط عدة جداول معًا، وذلك بعمل هذا الجدول الافتراضي الوسيط أولًا، ثم القيام بالعمليات عليه بعد ذلك أو عمل جدول وسيط آخر حتى الوصول إلى النتائج المطلوبة.
</p>

<p>
	سنبدأ باستعلام بسيط من الجدول <code>products</code> عن المنتجات التي توجد ضمن تصنيف <code>Book</code> أو <code>TV</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT title,price
hsoubguide-# FROM products
hsoubguide-# WHERE tags[1]='Book' OR tags[2]='TV';

     title     | price  
---------------+--------
 Dictionary    |   9.99
 Python Book   |  29.99
 Ruby Book     |  27.99
 Baby Book     |   7.99
 Coloring Book |   5.99
 42" LCD TV    | 499.00
 42" Plasma TV | 529.00
 Python Book   |  29.99
(8 rows)
</pre>

<p>
	والآن، لنفترض أننا لما نظرنا إلى الجدول الناتج عن الاستعلام، شعرنا بالحاجة إلى المزيد من التصفية، فأردنا مثلًا الاستعلام عن العناصر التي سعرها أكبر من 10 مع ترتيبها حسب الاسم، وإظهار 5 عناصر فقط.
</p>

<p>
	عندها سنضيف العبارة التالية إلى الاستعلام السابق:
</p>

<pre class="ipsCode">
AND price&gt;10 ORDER BY title LIMIT 5;
</pre>

<p>
	ليصبح الاستعلام الكامل:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT title,price
hsoubguide=# FROM products
hsoubguide=# WHERE (tags[1]='Book' OR tags[2]='TV')
hsoubguide=# AND price&gt;10
hsoubguide=# ORDER BY title
hsoubguide=# LIMIT 5;

     title     | price  
---------------+--------
 42" LCD TV    | 499.00
 42" Plasma TV | 529.00
 Python Book   |  29.99
 Python Book   |  29.99
 Ruby Book     |  27.99
(5 rows)
</pre>

<p>
	يمكننا تحويل الاستعلام السابق إلى مرحلتين، الأولى هي عبارة جداول شائعة CTE، والثانية هي استعلام من الجدول الناتج عن عبارة الجداول الشائعة، وذلك كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# WITH small_cte AS(
hsoubguide-#     SELECT title,price
hsoubguide-#     FROM products
hsoubguide-#     WHERE (tags[1]='Book' OR tags[2]='TV')
hsoubguide-#     )
hsoubguide-#     SELECT * FROM small_cte
hsoubguide-#     WHERE price&gt;10
hsoubguide-#     ORDER BY title
hsoubguide-#     LIMIT 5;

     title     | price  
---------------+--------
 42" LCD TV    | 499.00
 42" Plasma TV | 529.00
 Python Book   |  29.99
 Python Book   |  29.99
 Ruby Book     |  27.99
(5 rows)
</pre>

<p>
	بعد أن فهمنا طريقة استخدام تعابير الجداول الشائعة، لا بد أن سؤالًا مهمًا يخطر لنا، وهو الفرق بينها وبين العرض View، والفرق بسيط، فتعابير الجداول الشائعة تُنشأ أثناء الاستعلام، بينما تُنشأ العروض مسبقًا، وتُخزّن ككائنات في قاعدة البيانات (دون تخزين الجدول الناتج عنها بالطبع كما ذكرنا من قبل) حيث يمكن استخدامها مرات عديدة، لذلك يُطلق على تعابير الجداول الشائعة أحيانًا العروض المؤقتة أو العروض الآنية.
</p>

<h3>
	استخدام عدة تعابير شائعة معًا
</h3>

<p>
	سننشئ جدولين بسيطين لتوضيح هذه الفكرة كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE test_1(
hsoubguide(#     id INT,
hsoubguide(#     value varchar(20)
hsoubguide(# );

CREATE TABLE
</pre>

<pre class="ipsCode">
hsoubguide=# CREATE TABLE test_2(
hsoubguide(#     id INT,
hsoubguide(#     test_1_id INT,
hsoubguide(#     value varchar(20)
hsoubguide(# );

CREATE TABLE
</pre>

<p>
	في كل من الجدولين، عمود رقم معرف، وعمود للقيمة، وفي الجدول الثاني عمود فيه ربط مع أحد أسطر الجدول الأول من خلال الرقم المعرف الخاص به.
</p>

<pre class="ipsCode">
hsoubguide=# INSERT INTO test_1
hsoubguide-# VALUES(1,'aaa'),(2,'bbb'),(3,'ccc');

INSERT 0 3
</pre>

<pre class="ipsCode">
hsoubguide=# INSERT INTO test_2
hsoubguide-# VALUES(1,3,'AAA'),(2,1,'BBB'),(3,3,'CCC');

INSERT 0 3
</pre>

<pre class="ipsCode">
hsoubguide=# SELECT test_1.value as v1,test_2.value as v2
hsoubguide-# FROM test_1,test_2
hsoubguide-# WHERE test_1.id=test_2.test_1_id;

 v1  | v2  
-----+-----
 aaa | BBB
 ccc | CCC
 ccc | AAA
(3 rows)
</pre>

<p>
	يمكن ربط التعابير الشائعة مع بعضها كما، بحيث يكون التعبير الثاني مستخدمًا للجدول الناتج عن التعبير الأول كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# WITH cte1 AS(
hsoubguide-#     SELECT test_1.value AS V1,test_2.value AS v2
hsoubguide-#     FROM test_1,test_2
hsoubguide-#     WHERE test_1.id=test_2.test_1_id)
hsoubguide-#     ,cte2 AS(
Hsoubguide-#     SELECT * FROM cte1
hsoubguide-#     WHERE v1='ccc')
hsoubguide-#     SELECT * FROM cte2 ORDER BY v2 DESC;

 v1  | v2  
-----+-----
 ccc | CCC
 ccc | AAA
(2 rows)
</pre>

<p>
	هناك الكثير مما يمكن الاستفادة منه باستخدام تعابير الجداول الشائعة عند استخدامها مع الربط أو دوال النوافذ التي سنتعرف عليها في الفقرة التالية.
</p>

<h2>
	دوال النوافذ
</h2>

<p>
	تقوم دوال النوافذ (Window Functions) بإجراء عملية حسابية على مجموعة من أسطر الجدول التي لها علاقة محددة مع السطر الحالي، وهذا يشابه إلى حد ما العمليات الحسابية التي قمنا بها باستخدام العمليات التجميعية <code>COUNT</code> و <code>SUM</code> وغيرها، إلا أن استخدام دوال النوافذ لا يسبب تجميع النتيجة في سطر واحد، بل تحافظ الأسطر على ذاتها، وخلف الكواليس تقوم دوال النوافذ بالوصول إلى الأسطر اللازمة للقيام بالعملية الحسابية.
</p>

<p>
	لا بد أن الشرح السابق سيتضح أكثر مع الأمثلة على أي حال.
</p>

<p>
	فلنلقِ نظرة على الجدول التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51664" data-ss1613715704="1" href="https://academy.hsoub.com/uploads/monthly_2020_10/employees2.png.9401ae477402acaeaccd806e70719adc.png" rel=""><img alt="employees2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51664" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/employees2.png.9401ae477402acaeaccd806e70719adc.png" style="width: 450px; height: auto;"></a>
</p>

<p>
	للحصول على جدول مماثل للجدول السابق، يمكنك تطبيق العرض الذي استخدمناه في الفقرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_33" style="">
<span class="pln">CREATE OR REPLACE VIEW employee_view AS
SELECT 
  employees</span><span class="pun">.</span><span class="pln">last_name</span><span class="pun">,</span><span class="pln"> 
  employees</span><span class="pun">.</span><span class="pln">salary</span><span class="pun">,</span><span class="pln"> 
  departments</span><span class="pun">.</span><span class="pln">department
FROM 
  employees</span><span class="pun">,</span><span class="pln"> 
  employee_departments</span><span class="pun">,</span><span class="pln">
  departments
WHERE 
  employees</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> employee_departments</span><span class="pun">.</span><span class="pln">employee_id
  AND departments</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> employee_departments</span><span class="pun">.</span><span class="pln">department_id</span><span class="pun">;</span></pre>

<p>
	ثم الاستعلام عنه كما تعلمنا سابقًا:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT *
hsoubguide-# FROM employee_view;

 last_name | salary | department 
-----------+--------+------------
 Jones     |  45000 | Accounting
 Adams     |  50000 | Sales
 Johnson   |  40000 | Marketing
 Williams  |  37000 | Accounting
 Smith     |  55000 | Sales
(5 rows)
</pre>

<p>
	في المثال التالي، سنحاول استخراج مجموع الرواتب التي تُصرف في كل قسم وذلك باستخدام دالة التجميع <code>SUM</code> والتوجيه <code>GROUP BY</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_35" style="">
<span class="pln">SELECT
department
</span><span class="pun">,</span><span class="pln">sum</span><span class="pun">(</span><span class="pln">salary</span><span class="pun">)</span><span class="pln"> AS department_salary_sum
FROM employee_view
GROUP BY department</span><span class="pun">;</span></pre>

<p>
	وستكون المخرجات كما يلي:
</p>

<pre class="ipsCode">
 department | department_salary_sum 
------------+-----------------------
 Accounting |                 82000
 Sales      |                105000
 Marketing  |                 40000
(3 rows)
</pre>

<p>
	ولكن ماذا لو أردنا استعراض الجدول الأساسي هذا :
</p>

<pre class="ipsCode">
 last_name | salary | department 
-----------+--------+------------
 Jones     |  45000 | Accounting
 Adams     |  50000 | Sales
 Johnson   |  40000 | Marketing
 Williams  |  37000 | Accounting
 Smith     |  55000 | Sales
(5 rows)
</pre>

<p>
	مع إضافة عمودٍ جديد، فيه مجموع الرواتب في القسم الخاص بالموظف المذكور في ذلك السطر، هل يمكننا كتابة الاستعلام التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_37" style="">
<span class="pln">SELECT last_name</span><span class="pun">,</span><span class="pln">salary</span><span class="pun">,</span><span class="pln">department</span><span class="pun">,</span><span class="pln">SUM</span><span class="pun">(</span><span class="pln">salary</span><span class="pun">)</span><span class="pln">
FROM employee_view
GROUP BY department</span><span class="pun">;</span></pre>

<p>
	للأسف، لا يمكننا القيام بذلك، وسيظهر الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_39" style="">
<span class="pln">ERROR</span><span class="pun">:</span><span class="pln">  column </span><span class="str">"employee_view.last_name"</span><span class="pln"> must appear </span><span class="kwd">in</span><span class="pln"> the GROUP BY clause </span><span class="kwd">or</span><span class="pln"> be used </span><span class="kwd">in</span><span class="pln"> an aggregate </span><span class="kwd">function</span><span class="pln">
LINE </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> SELECT last_name</span><span class="pun">,</span><span class="pln">salary</span><span class="pun">,</span><span class="pln">department</span><span class="pun">,</span><span class="pln">SUM</span><span class="pun">(</span><span class="pln">salary</span><span class="pun">)</span></pre>

<p>
	ينص الخطأ على أن أي عمود غير مذكور ضمن عبارة <code>GROUP BY</code> أو ضمن دالة التجميع فإنه لا يمكن عرضه، وهذا منطقي، لأن دالة التجميع والعبارة <code>GROUP BY</code> هدفها التجميع، أي اختصار الأسطر وإظهار نتائج الاختصار.
</p>

<p>
	وهنا تأتي أهمية دوال النوافذ، فالآن سنستخدم التابع <code>SUM</code> ولكن لن نقوم بكتابة <code>GROUP BY</code>، بل سنستبدلها بالعبارة <code>OVER (PARTITION BY department)‎</code> وتعني أن عملية الجمع ستتم على <strong>جزء</strong> من الجدول مقسّم حسب قيمة العمود <code>department</code> كما يلي :
</p>

<pre class="ipsCode">
hsoubguide2=# SELECT
hsoubguide2-#    last_name,
hsoubguide2-#    salary,
hsoubguide2-#    department,
hsoubguide2-#    SUM(salary)
hsoubguide2-# OVER (PARTITION BY department)
hsoubguide2-# FROM employee_view;

 last_name | salary | department |  sum   
-----------+--------+------------+--------
 Jones     |  45000 | Accounting |  82000
 Williams  |  37000 | Accounting |  82000
 Johnson   |  40000 | Marketing  |  40000
 Adams     |  50000 | Sales      | 105000
 Smith     |  55000 | Sales      | 105000
(5 rows)
</pre>

<p>
	تقوم العبارة <code>PARTITION BY</code> بتقسيم الجدول إلى مجموعات حسب العمود المذكور ضمن هذه العبارة، ثم يتم تنفيذ الدالة المذكورة على هذه المجموعات، وحفظ الناتج لعرضه في العمود الخاص بالدالة.
</p>

<h3>
	عدة دوال نوافذ في استعلام واحد
</h3>

<p>
	يمكننا استخدام العديد من توابع النوافذ، ولكن يجب إضافة عبارة <code>OVER</code>خاصة بكل استدعاء من الاستدعاءات، كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide2=# SELECT last_name,salary,department,
hsoubguide2=# AVG(salary) OVER (PARTITION BY department),
hsoubguide2=# SUM(salary) OVER (PARTITION BY salary/10000)
hsoubguide2=# FROM employee_view;

 last_name | salary | department |        avg         |  sum   
-----------+--------+------------+--------------------+--------
 Jones     |  45000 | Accounting | 41000.000000000000 |  82000
 Williams  |  37000 | Accounting | 41000.000000000000 |  82000
 Johnson   |  40000 | Marketing  | 40000.000000000000 |  40000
 Adams     |  50000 | Sales      | 52500.000000000000 | 105000
 Smith     |  55000 | Sales      | 52500.000000000000 | 105000
(5 rows)
</pre>

<p>
	ولكن في حال كنا نرغب في استخدام نفس النافذة لتنفيذ عدة دوال عليها، فيمكننا تعريف النافذة في نهاية الاستعلام لمرة واحدة، واستخدامها عن طريق اسمٍ مستعارٍ لها، كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide2=# SELECT last_name,salary,department,
hsoubguide2=# AVG(salary) OVER my_window,
hsoubguide2=# SUM(salary) OVER my_window
hsoubguide2=# FROM employee_view
hsoubguide2=# WINDOW my_window AS (PARTITION BY department);

 last_name | salary | department |        avg         |  sum   
-----------+--------+------------+--------------------+--------
 Jones     |  45000 | Accounting | 41000.000000000000 |  82000
 Williams  |  37000 | Accounting | 41000.000000000000 |  82000
 Johnson   |  40000 | Marketing  | 40000.000000000000 |  40000
 Adams     |  50000 | Sales      | 52500.000000000000 | 105000
 Smith     |  55000 | Sales      | 52500.000000000000 | 105000
(5 rows)
</pre>

<p>
	ملاحظة: في حال أردنا إعطاء العمود الحاوي على نتائج دالة النافذة اسمًا مستعارًا باستخدام <code>AS</code> فيجب وضعها بعد عبارة <code>OVER</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide2=# SELECT last_name,salary,department,
hsoubguide2=# AVG(salary) OVER (PARTITION BY department) AS avg_department_salary,
hsoubguide2=# SUM(salary) OVER (PARTITION BY department) AS sum_department_salary
hsoubguide2=# FROM employee_view;

 last_name | salary | department | avg_department_salary | sum_department_salary 
-----------+--------+------------+-----------------------+-----------------------
 Jones     |  45000 | Accounting |    41000.000000000000 |                 82000
 Williams  |  37000 | Accounting |    41000.000000000000 |                 82000
 Johnson   |  40000 | Marketing  |    40000.000000000000 |                 40000
 Adams     |  50000 | Sales      |    52500.000000000000 |                105000
 Smith     |  55000 | Sales      |    52500.000000000000 |                105000
(5 rows)
</pre>

<h3>
	مثال ممتع باستخدام دوال النافذة
</h3>

<p>
	سنقوم في هذا المثال بإضافة عمود إلى الجدول، فيه مجموع رواتب الموظفين مجزّأة حسب الحرف الأول من أسمائهم الأخيرة.
</p>

<p>
	فإذا كان هناك موظفان اسماهما الأخيرة بالحرف <code>J</code> سيكونان في نفس النافذة، ويتم حساب مجموع رواتبهما وإخراجه إلى جانب اسميهما.
</p>

<p>
	وللقيام بذلك، سنستخدم التابع <code>LEFT</code> الذي يأخذ وسيطين، الأول هو اسم العمود والثاني هو عدد الحروف بدءًا من اليسار التي نريد اقتطاعها.
</p>

<p>
	وستكون عبارة تجزئة النوافذ كما يلي:
</p>

<pre class="ipsCode">
OVER (PARTITION BY LEFT(last_name,1))
</pre>

<p>
	ولكننا نريد أيضًا أن تكون المخرجات ليست فقط مجموع رواتب الأشخاص المتشابهين في الحرف الأول من اسمهم الأخير، بل نريد إضافة هذا الحرف قبل مجموع الرواتب، كي تكون المخرجات واضحة، فبدلًا من أن يظهر لنا العدد <code>50000</code> مثلًا، نريد أن يخرج <code>A:50000</code>.
</p>

<p>
	وللقيام بذلك، سنستخدم عملية وصل النصوص <code>||</code> وبدلًا من أن نطلب في الاستعلام إخراج ناتج العملية <code>SUM(salary)‎</code> سنطلب في الاستعلام العبارة التالية:
</p>

<pre class="ipsCode">
LEFT(last_name,1) || ':' || SUM(salary)
</pre>

<p>
	وبذلك يكون لدينا الاستعلام التالي:
</p>

<pre class="ipsCode">
hsoubguide2=#  SELECT last_name,salary,department,
hsoubguide2=#  LEFT(last_name,1) || ':' || SUM(salary) hsoubguide2=#  OVER (PARTITION BY LEFT(last_name,1))
hsoubguide2=#  AS Salary_sum_by_letter
hsoubguide2=#  FROM employee_view;

 last_name | salary | department | salary_sum_by_letter 
-----------+--------+------------+----------------------
 Adams     |  50000 | Sales      | A:50000
 Jones     |  45000 | Accounting | J:85000
 Johnson   |  40000 | Marketing  | J:85000
 Smith     |  55000 | Sales      | S:55000
 Williams  |  37000 | Accounting | W:37000
(5 rows)
</pre>

<h3>
	دالة النافذة rank
</h3>

<p>
	يمكننا استخدام دالة النافذة <code>rank</code> لإنتاج رقم ترتيبي للأسطر ضمن التقسيم الذي قمنا به، فلو أردنا مثلًا إنتاج رقم لترتيب الموظفين حسب رواتبهم تصاعديًّا، نكتب الاستعلام التالي:
</p>

<pre class="ipsCode">
hsoubguide2=# SELECT last_name,salary,department,
hsoubguide2=# rank() OVER (ORDER BY salary)
hsoubguide2=# FROM employee_view;

 last_name | salary | department | rank 
-----------+--------+------------+------
 Williams  |  37000 | Accounting |    1
 Johnson   |  40000 | Marketing  |    2
 Jones     |  45000 | Accounting |    3
 Adams     |  50000 | Sales      |    4
 Smith     |  55000 | Sales      |    5
(5 rows)
</pre>

<p>
	ويمكننا إنتاج رقم ترتيبي للموظفين حسب رواتبهم، ولكن لكل قسم على حدة، وذلك باستخدام العبارة <code>PARTITION BY</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide2=# SELECT last_name,salary,department,
hsoubguide2=# rank() OVER (PARTITION BY department ORDER BY salary)
hsoubguide2=# FROM employee_view;

 last_name | salary | department | rank 
-----------+--------+------------+------
 Williams  |  37000 | Accounting |    1
 Jones     |  45000 | Accounting |    2
 Johnson   |  40000 | Marketing  |    1
 Adams     |  50000 | Sales      |    1
 Smith     |  55000 | Sales      |    2
(5 rows)
</pre>

<p>
	نريد الآن إيجاد الموظفين الأعلى راتبًا في كل قسم، ولذلك سنقوم بإنشاء عرض جديد، للحفاظ على الجدول الناتج عن الاستعلام السابق ولكن سنخزّنه بترتيب معكوس، بحيث يكون الموظف الأعلى راتبًا له قيمة <code>rank</code> تساوي <code>1</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide2=# CREATE OR REPLACE VIEW employee_rank AS
hsoubguide2-# SELECT last_name,salary,department,
hsoubguide2-#  rank() OVER (PARTITION BY department ORDER BY salary DESC)
hsoubguide2-#  FROM employee_view;

CREATE VIEW
</pre>

<p>
	أصبح بإمكاننا الآن تنفيذ استعلامات على الجدول الافتراضي الجديد <code>employee_rank</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide2=# SELECT * FROM employee_rank WHERE rank=1;

 last_name | salary | department | rank 
-----------+--------+------------+------
 Jones     |  45000 | Accounting |    1
 Johnson   |  40000 | Marketing  |    1
 Smith     |  55000 | Sales      |    1
(3 rows)
</pre>

<p>
	يمكن استعراض <a data-ss1613715704="1" href="https://www.postgresql.org/docs/12/tutorial-window.html" rel="external nofollow">وثائق Postgres</a> للمزيد من التعمق في دوال النوافذ.
</p>

<h2>
	الفهارس Indexes
</h2>

<p>
	الفهرس Index هو بنية محددة تنظّم مرجعًا للبيانات مما يجعلها أسهل في البحث، وبكون الفهرس في Postgres نسخةً من العنصر المُراد فهرسته مع مرجع إلى موقع البيانات الفعلي.
</p>

<p>
	تقوم Postgres عند استعلام البيانات باستخدام الفهارس إن كانت متاحة وإلا فهي تقوم بمسحٍ متتالٍ (sequential scan)، حيث يتم فيه البحث عبر جميع البيانات قبل إرجاع نتيجة.
</p>

<p>
	يحقق استخدام الفهارس سرعة كبيرة في البحث والاستعلام، فإضافة عمود فهرس إلى الجدول ستسرّع غالبًا الوصول إلى البيانات، إلا أنّه بالمقابل سيؤدي إلى تبطيئ إدخال البيانات، وذلك لأن عملية الإدخال ستتضمن كتابة بيانات في مكانين مختلفين مع المحافظة على ترتيب الفهرس ضمن البيانات السابقة.
</p>

<p>
	يجب الانتباه إلى نوع البيانات المستخدمة كفهرس، فالفهرسة على أساس الأرقام أو الطابع الزمني فعالة، بينما يُعدّ استخدام النصوص كفهارس غير فعّال.
</p>

<p>
	لنأخذ مثالا عمليًّا بوضع فهرس للجدول employees (الذي عرضناه في بداية المقال):
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_43" style="">
<span class="pln">CREATE INDEX idx_salary ON employees</span><span class="pun">(</span><span class="pln">salary</span><span class="pun">);</span></pre>

<p>
	يُمكن استخدام عدة أعمدة كفهارس في الوقت نفسه، فإن كنت تقوم بتصفية نتائج الجداول باستخدام أعمدة محددة، فيمكنك إنشاء فهارس منها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_45" style="">
<span class="pln">CREATE INDEX idx_salary ON employees</span><span class="pun">(</span><span class="pln">last_name</span><span class="pun">,</span><span class="pln"> salary</span><span class="pun">);</span></pre>

<h3>
	نصائح عند استخدام الفهارس
</h3>

<h4>
	إنشاء الفهارس آنيًّا
</h4>

<p>
	عندما تقوم Postgres بإنشاء الفهارس (كما في أنظمة قواعد البيانات الأخرى) فإنها تقوم بقفل الجدول أثناء بناء الفهرس، وهذا يمنع إضافة المزيد من البيانات إلى الجدول. فإن كانت كمية البيانات صغيرة فإن العملية لن تستغرق الكثير من الوقت، ولكنّها ستسبب إعاقةً كبيرة للعمل على هذا الجدول إن كانت كمية البيانات كبيرة جدًا ومن ثمّ فستكون مدة قفل الجدول أطول.
</p>

<p>
	وهذا يعني أنه للحصول على تحسين في كفاءة قاعدة البيانات لا بدّ من إيقاف العمل على قاعدة البيانات لمدة محددة، على الأقل للجدول الذي يتم إنشاء الفهرس له.
</p>

<p>
	إلا أن Postgres تتيح إمكانية إنشاء الفهرس دون قفل الجدول، وذلك باستخدام <code>CREATE INDEX CONCURRENTLY</code> كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_47" style="">
<span class="pln">CREATE INDEX CONCURRENTLY idx_salary ON employees</span><span class="pun">(</span><span class="pln">last_name</span><span class="pun">,</span><span class="pln"> salary</span><span class="pun">);</span></pre>

<h4>
	عندما يكون الفهرس أذكى منك
</h4>

<p>
	إن استخدام الفهرس ليس هو الحل الأسرع دومًا، فمثلًا إن كانت نتيجة الاستعلام ستعيد نسبة كبيرة من بيانات الجدول، فإن المرور على جميع بيانات الجدول أسرع في هذه الحال من استخدام الفهرس، لذا عليك الوثوق بأن Postgres ستقوم بالأمر الصحيح فيما يتعلق بسرعة الاستعلام سواء كان استخدام الفهرس أو غيره.
</p>

<h3>
	فهرسة النوع JSONB
</h3>

<p>
	إن طريقة الفهرسة الأكثر مرونة وقوة هي استخدام فهرس <code>GIN</code>، حيث يقوم GIN بفهرسة كل عمود ومفتاح ضمن مستند JSONB، ويمكن إضافته كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2402_49" style="">
<span class="pln">CREATE INDEX idx_products_attributes ON products USING GIN </span><span class="pun">(</span><span class="pln">attributes</span><span class="pun">);</span></pre>

<h4>
	المفاتيح الخارجية والفهارس
</h4>

<p>
	في بعض أنظمة الربط العلائقي للكائنات Object relational mapping، يؤدي إنشاء مفتاح خارجي (Foreign Key) إلى إنشاء فهرس (index) أيضًا، وننوه هنا إلى أن Postgres لا تقوم تلقائيا بإنشاء فهرس عند إنشاء مفتاح خارجي، فهي خطوة منفصلة عليك الانتباه إليها عندما لا تستخدم ORM.
</p>

<h2>
	الخلاصة
</h2>

<p>
	نجحنا في هذا الفصل بجعل استعلاماتنا أقصر وأسهل قراءةً بفضل العرض View وتعابير الجداول الشائعة CTE، كما تعرفنا على دوال النوافذ Window Functions التي تسمح بالقيام بعمليات تجميعية تحتاج إلى لغة برمجة في العادة، كما تطرقنا إلى الفهارس وكيفية إنشائها.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a data-ss1613715704="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%AE%D8%A7%D8%B5%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r476/" rel="">أنواع بيانات خاصة في قواعد بيانات Postgres</a>
	</li>
	<li>
		المقال السابق: <a data-ss1613715704="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-sql-%D9%81%D9%8A-postgres-r474/" rel="">استخدام أساسيات SQL في Postgres</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a data-ss1613715704="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
	<li>
		<a data-ss1613715704="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-postgresql-%D9%85%D9%86-%D8%A7%D9%84%D9%87%D8%AC%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%A4%D8%AA%D9%85%D8%AA%D8%A9-automated-attacks-r380/" rel="">كيفيّة حماية PostgreSQL من الهجمات المُؤتمتة (Automated Attacks)</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">475</guid><pubDate>Thu, 01 Oct 2020 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; SQL &#x641;&#x64A; Postgres</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-sql-%D9%81%D9%8A-postgres-r474/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.4d270d73e7eea35f70da9b8d2c04e131.png" /></p>

<p>
	يتناول هذا القسم الطرق الأساسية للاستعلام عن البيانات وعرض الجداول، وربط البيانات بين عدة جداول، كما نتعرف فيه على كيفية تعديل البيانات ضمن الجدول أو حذفها، والعديد من التعليمات والتوابع الأكثر أهمية في Postgres.
</p>

<h2>
	إنشاء الجداول
</h2>

<p>
	سنشرح في هذه الفقرة كيفية إنشاء الجداول المذكورة في المثال السابق يدويًّا.
</p>

<p>
	ملاحظة: إن كنت قمت بتنزيل قاعدة البيانات من المقال السابق، <a data-ss1613715533="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-postgres-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%AA%D9%87%D8%A7-%D9%84%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r472/" rel="">تثبيت Postgres والتعرف على أساسيات إدارتها لقواعد البيانات</a>، فيمكنك الاطلاع على التعليمات الحقيقية التي تم من خلالها إنشاء الجداول، وذلك من خلال الأوامر التالية في صدفة bash:
</p>

<pre class="ipsCode">
pg_dump -st products hsoubguide
pg_dump -st purchases hsoubguide
pg_dump -st purchase_items hsoubguide
pg_dump -st users hsoubguide
</pre>

<p>
	تقوم التعليمة السابقة بإظهار جميع التعليمات اللازمة لإنشاء الجدول المذكور بالحالة التي هو عليها الآن، إلا أننا سنركّز في هذه الفقرة على التعليمات الأساسية فقط.
</p>

<p>
	في حال قمت بتنزيل النسخة الكاملة من قاعدة البيانات كما ورد سابقًا، وترغب في إنشاء الجداول من الصفر أيضًا، فسنقوم لذلك بإنشاء قاعدة بيانات جديدة كي لا تتعارض مع الجداول السابقة.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_7" style="">
<span class="pln">CREATE DATABASE hsoubguide2</span><span class="pun">;</span></pre>

<p>
	يمكننا إنشاء جدول جديد في قاعدة البيانات عن طريق التعليمة <code>CREATE TABLE</code> حيث نقوم بتحديد اسم الجدول، وتفصيل أسماء الأعمدة ونوع البيانات المحتواة في كل منها، إلى جانب الصفات الخاصة بكل عمود، كما في الأمثلة التالية التي تشرح نفسها بنفسها:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_9" style="">
<span class="pln">CREATE TABLE products </span><span class="pun">(</span><span class="pln">
    id integer NOT NULL</span><span class="pun">,</span><span class="pln">
    title character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">),</span><span class="pln">
    price numeric</span><span class="pun">,</span><span class="pln">
    created_at timestamp </span><span class="kwd">with</span><span class="pln"> time zone</span><span class="pun">,</span><span class="pln">
    deleted_at timestamp </span><span class="kwd">with</span><span class="pln"> time zone</span><span class="pun">,</span><span class="pln">
    tags character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)[]</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	في التعليمة السابقة، أُنشئ جدول اسمه <code>products</code> وحُدّد فيه الأعمدة التالية:
</p>

<ul>
<li>
		العمود <code>id</code>، يحتوي بيانات نوعها <code>integer</code> أي أعداد صحيحة، وله المواصفة <code>NOT NULL</code>، أي أنه يُمنع إنشاء سطر دون تحديد قيمة لهذا العمود.
	</li>
	<li>
		العمود <code>title</code>، يحتوي بيانات محرفية، طولها متغير، يمكن أن يصل إلى 255 حرفًا، ولذلك نستخدم النوع <code>character varying</code> مع وضع الطول الأكبر بين قوسين.
	</li>
	<li>
		العمود <code>price</code>، يحوي بيانات عددية من النوع <code>numeric</code> وهو نوع عددي مميز، يمكن تخزين أعداد يصل عدد منازلها إلى 131072 منزلة قبل الفاصلة العشرية، و 16383 منزلة بعد الفاصلة! إلا أن العمليات الحسابية عليه تكون أبطأ من النوع <code>integer</code> والسعة التخزينية التي يحتاجها أكبر أيضًا.
	</li>
	<li>
		العمود <code>created_at</code> و العمود <code>deleted_at</code> يحتويان على بيانات التاريخ والوقت مع حفظ المنطقة الزمنية، فهما من النوع <code>timestamp with time zone</code>
	</li>
	<li>
		العمود <code>tags</code> يحتوي بيانات محرفية من النوع <code>character varying</code> إلا أن وجود الرمز <code>[]</code> في تعريف هذا العمود، يعني أنه سيحتفظ بمصفوفة من العبارات المحرفية (أي أنه لن يحتوي عبارة واحدة، بل قائمة من العبارات)
	</li>
</ul>
<p>
	يمكنك الاطلاع على المزيد من التفاصيل عن الأنواع العددية من <a data-ss1613715533="1" href="https://www.postgresql.org/docs/9.1/datatype-numeric.html" rel="external nofollow">توثيق Postgres الرسمي</a>.
</p>

<p>
	يمكننا رؤية تفاصيل الجدول الذي أُنشئ كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_12">
hsoubguide2=# \d products 


                        Table "public.products"
   Column   |           Type           | Collation | Nullable | Default 
------------+--------------------------+-----------+----------+---------
 id         | integer                  |           | not null | 
 title      | character varying(255)   |           |          | 
 price      | numeric                  |           |          | 
 created_at | timestamp with time zone |           |          | 
 deleted_at | timestamp with time zone |           |          | 
 tags       | character varying(255)[] |           |          | 
</pre>

<p>
	بعد أن قُمنا بإنشاء الجدول وتحديد أنواع الأعمدة، سنقوم بتحديد مواصفة هامّة للعمود <code>id</code> هي <code>PRIMARY KEY</code> وتعني أن القيمة المخزنة ضمن هذا العمود ستكون فريدة <code>UNIQUE</code> لا تتكرر في أي سطر من الأسطر، ولا يمكن أن تكون <code>NULL</code>، وستكون القيمة المخزنة في هذا العمود هي التي تميّز الأسطر عن بعضها.
</p>

<p>
	سنتعرف من خلال هذه الخطوة على التعليمة التي تقوم بتعديل تعريف الجداول <code>ALTER TABLE</code>، والتعديل الذي سنقوم به سيكون <code>ADD CONSTRAINT</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_14" style="">
<span class="pln">ALTER TABLE ONLY </span><span class="kwd">public</span><span class="pun">.</span><span class="pln">products
    ADD CONSTRAINT products_pkey PRIMARY KEY </span><span class="pun">(</span><span class="pln">id</span><span class="pun">);</span></pre>

<p>
	حيث قمنا بإضافة <code>CONSTRAINT</code> أسميناه <code>products_pkey</code> ينصّ على جعل العمود <code>id</code> بالمواصفة <code>PRIMARY KEY</code>، وذلك في الجدول <code>products</code>.
</p>

<p>
	يمكننا استخدام التعليمة <code>ALTER</code> لتغيير أي شيء من خصائص الجدول، كتغيير اسمه، أو تغيير اسم أحد الأعمدة، أو إضافة أعمدة جديدة أو حذف أعمدة، ويمكنك الاطلاع على المزيد عن هذه التعلمية من <a data-ss1613715533="1" href="https://www.postgresql.org/docs/9.1/sql-altertable.html" rel="external nofollow">توثيق Postgres الرسمي</a>.
</p>

<p>
	أصبح لديك الآن المعرفة الكافية لفهم كيفية إنشاء الجداول، ويمكنك قراءة التعليمات التالية وتنفيذها بوضوح لإنشاء الجداول التي نحتاجها في أمثلتنا.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5371_6" style="">
<span class="pln">CREATE TABLE purchases </span><span class="pun">(</span><span class="pln">
    id integer NOT NULL</span><span class="pun">,</span><span class="pln">
    created_at timestamp </span><span class="kwd">with</span><span class="pln"> time zone</span><span class="pun">,</span><span class="pln">
    name character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">),</span><span class="pln">
    address character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">),</span><span class="pln">
    state character varying</span><span class="pun">(</span><span class="lit">2</span><span class="pun">),</span><span class="pln">
    zipcode integer</span><span class="pun">,</span><span class="pln">
    user_id integer
</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5371_8" style="">
<span class="pln">CREATE TABLE purchase_items </span><span class="pun">(</span><span class="pln">
    id integer NOT NULL</span><span class="pun">,</span><span class="pln">
    purchase_id integer</span><span class="pun">,</span><span class="pln">
    product_id integer</span><span class="pun">,</span><span class="pln">
    price numeric</span><span class="pun">,</span><span class="pln">
    quantity integer</span><span class="pun">,</span><span class="pln">
    state character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5371_10" style="">
<span class="pln">CREATE TABLE users </span><span class="pun">(</span><span class="pln">
    id integer NOT NULL PRIMARY KEY</span><span class="pun">,</span><span class="pln">
    email character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">),</span><span class="pln">
    password character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">),</span><span class="pln">
    details </span><span class="kwd">public</span><span class="pun">.</span><span class="pln">hstore</span><span class="pun">,</span><span class="pln">
    created_at timestamp </span><span class="kwd">with</span><span class="pln"> time zone</span><span class="pun">,</span><span class="pln">
    deleted_at timestamp </span><span class="kwd">with</span><span class="pln"> time zone
</span><span class="pun">);</span></pre>

<p>
	<strong>ملاحظة</strong>: في الجدول الأخير، يوجد العمود <code>details</code> يحوي بيانات من النوع <code>hstore</code>، وسنتحدث عن هذا النوع الخاص في الفصل التالي، أنواع بيانات خاصة في قواعد بيانات Postgres.
</p>

<p>
	والآن، إذا أردت حذف جدولٍ من الجداول، فاستخدم التعليمة <code>DROP TABLE</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_18" style="">
<span class="pln">DROP TABLE users </span></pre>

<h2>
	تعديل الجداول
</h2>

<p>
	يمكننا التعديل على الجدول بعد إنشائه باستخدام التعليمة الأساسية <code>ALTER</code>، حيث يمكننا من خلالها القيام بتعديل جميع خصائص الجداول، نذكر منها أهم عمليات التعديل التالية:
</p>

<p>
	1- تعديل اسم الجدول:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_20" style="">
<span class="pln">ALTER TABLE users
     RENAME TO our_lovely_users</span><span class="pun">;</span></pre>

<p>
	2- تعديل اسم عمود ما:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_22" style="">
<span class="pln">ALTER TABLE products
    RENAME COLUMN title TO product_name</span><span class="pun">;</span></pre>

<p>
	3- إضافة عمود إلى الجدول:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_24" style="">
<span class="pln">ALTER TABLE users
    ADD COLUMN image_url character varying</span><span class="pun">(</span><span class="lit">1024</span><span class="pun">);</span></pre>

<p>
	4- حذف عمود من الجدول:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_26" style="">
<span class="pln">ALTER TABLE users
    DROP COLUMN IF EXISTS image_url</span></pre>

<p>
	5- تعديل نوع البيانات في عمود ما من الجدول:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_28" style="">
<span class="pln">ALTER TABLE products
    ALTER COLUMN price SET DATA TYPE </span><span class="kwd">float</span><span class="pun">;</span></pre>

<p>
	يمكنك التوسع في إمكانية التعديل على الجداول بالاطلاع على <a data-ss1613715533="1" href="https://www.postgresql.org/docs/9.1/sql-altertable.html" rel="external nofollow">وثائق Postgres الرسمية</a>.
</p>

<h2>
	إدخال البيانات
</h2>

<p>
	بعد أن قمنا بإنشاء الجداول، علينا إدخال البيانات فيها، ويتم ذلك عن طريق التعليمة <code>INSERT INTO</code> ، وسنقوم في المثال بإدخال سطر في الجدول <code>products</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_30" style="">
<span class="pln">INSERT INTO products</span><span class="pun">(</span><span class="pln">
    id</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">,</span><span class="pln">
    price</span><span class="pun">,</span><span class="pln">
    created_at</span><span class="pun">,</span><span class="pln">
    tags
</span><span class="pun">)</span><span class="pln">
VALUES </span><span class="pun">(</span><span class="pln">
    </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'Python Book'</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">29.99</span><span class="pun">,</span><span class="pln">
    NOW</span><span class="pun">(),</span><span class="pln">
    ARRAY</span><span class="pun">[</span><span class="str">'Book'</span><span class="pun">,</span><span class="str">'Programming'</span><span class="pun">,</span><span class="str">'Python'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	توضّح التعليمة السابقة كيفية إدخال سطر في جدول ما، وذلك عن طريق ذكر اسم الجدول، ثم ترتيب الأعمدة التي سنحدد قيمتها بين قوسين، وبعد ذلك نكتب الكلمة المفتاحية <code>VALUES</code> ثم نذكر قيمة كل عمود في السطر الجديد بالترتيب نفسه.
</p>

<p>
	لاحظ استخدامنا للتابع <code>NOW</code> الذي يعطي التاريخ والوقت في لحظة تنفيذ التعليمة.
</p>

<p>
	لاحظ أيضًا كيف قمنا بإدخال مصفوفة في العمود <code>tags</code>، وسنتحدث عن ذلك أكثر لاحقًا في هذا الدليل.
</p>

<p>
	للتأكد من أن السطر تم إدخاله، يمكنك استخدام التعليمة <code>SELECT</code> وهي تعليمة الاستعلام الأساسية، وسنستخدمها هنا دون أي شروط كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_32" style="">
<span class="pln">SELECT </span><span class="pun">*</span><span class="pln"> FROM products</span><span class="pun">;</span></pre>

<p>
	حيث تشير <code>*</code> إلى اختيار جميع الأعمدة لعرضها من الجدول <code>products</code>، وسنحصل على المخرجات التالية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_34" style="">
<span class="pln">hsoubguide2</span><span class="pun">=#</span><span class="pln"> SELECT </span><span class="pun">*</span><span class="pln"> FROM products</span><span class="pun">;</span><span class="pln">


 id </span><span class="pun">|</span><span class="pln">      title       </span><span class="pun">|</span><span class="pln"> price  </span><span class="pun">|</span><span class="pln">          created_at           </span><span class="pun">|</span><span class="pln"> deleted_at </span><span class="pun">|</span><span class="pln">           tags            
</span><span class="pun">----+------------------+--------+-------------------------------+------------+---------------------------</span><span class="pln">
 </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Python</span><span class="pln"> </span><span class="typ">Book</span><span class="pln">      </span><span class="pun">|</span><span class="pln">  </span><span class="lit">29.99</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2020</span><span class="pun">-</span><span class="lit">06</span><span class="pun">-</span><span class="lit">22</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="lit">22</span><span class="pun">:</span><span class="lit">02.281079</span><span class="pun">+</span><span class="lit">03</span><span class="pln"> </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln"> </span><span class="pun">{</span><span class="typ">Book</span><span class="pun">,</span><span class="typ">Programming</span><span class="pun">,</span><span class="typ">Python</span><span class="pun">}</span><span class="pln">
</span><span class="pun">(</span><span class="lit">1</span><span class="pln"> row</span><span class="pun">)</span></pre>

<p>
	يمكننا أيضًا إدخال عدة أسطر في تعليمة <code>INSERT</code> واحدة، وذلك بوضع قوسين <code>()</code> حول البيانات الخاصة بكل سطر، وفصل الأسطر بفاصلة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8183_36" style="">
<span class="pln">INSERT INTO products</span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln">title</span><span class="pun">,</span><span class="pln">price</span><span class="pun">,</span><span class="pln">created_at</span><span class="pun">,</span><span class="pln">tags</span><span class="pun">)</span><span class="pln">
VALUES </span><span class="pun">(</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="str">'Book2'</span><span class="pun">,</span><span class="lit">1.99</span><span class="pun">,</span><span class="pln">NOW</span><span class="pun">(),</span><span class="pln">ARRAY</span><span class="pun">[</span><span class="str">'a1'</span><span class="pun">,</span><span class="str">'b'</span><span class="pun">,</span><span class="str">'q'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">),</span><span class="pln">
       </span><span class="pun">(</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="str">'Book3'</span><span class="pun">,</span><span class="lit">2.99</span><span class="pun">,</span><span class="pln">NOW</span><span class="pun">(),</span><span class="pln">ARRAY</span><span class="pun">[</span><span class="str">'a2'</span><span class="pun">,</span><span class="str">'c'</span><span class="pun">,</span><span class="str">'w'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">),</span><span class="pln">
       </span><span class="pun">(</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="str">'Book4'</span><span class="pun">,</span><span class="lit">3.99</span><span class="pun">,</span><span class="pln">NOW</span><span class="pun">(),</span><span class="pln">ARRAY</span><span class="pun">[</span><span class="str">'a3'</span><span class="pun">,</span><span class="str">'d'</span><span class="pun">,</span><span class="str">'e'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">),</span><span class="pln">
       </span><span class="pun">(</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="str">'Book5'</span><span class="pun">,</span><span class="lit">4.99</span><span class="pun">,</span><span class="pln">NOW</span><span class="pun">(),</span><span class="pln">ARRAY</span><span class="pun">[</span><span class="str">'a4'</span><span class="pun">,</span><span class="str">'e'</span><span class="pun">,</span><span class="str">'r'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	ملاحظة: سنتحدث عن كيفية التعديل على الأسطر المخزّنة أو حذف أسطر من الجدول في فقرات لاحقة.
</p>

<p>
	كانت هذه بداية سريعة في كيفية إنشاء جدول وإدخال البيانات إليه، ثم الاستعلام عنها، وسنتوسع في الفقرات التالية في أنواع الاستعلامات وكيفية القيام بها، وذلك على اعتبار وجود الجداول والبيانات مُسبقًا، واعتبار أن إدخال البيانات يتم تلقائيًّا عن طريق ربط قاعدة البيانات بموقع ويب، أو بواجهة مستخدم ما.
</p>

<h2>
	استعراض الجداول
</h2>

<p>
	نستعرض في المثال التالي، كيفية عرض جميع الجداول المخزنة في قاعدة البيانات باستخدام التعليمة <code>‎\dt</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_38" style="">
<span class="pln">hsoubguide</span><span class="pun">=#</span><span class="pln"> \dt
             </span><span class="typ">List</span><span class="pln"> of relations
             
             
 </span><span class="typ">Schema</span><span class="pln"> </span><span class="pun">|</span><span class="pln">      </span><span class="typ">Name</span><span class="pln">      </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Type</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="typ">Owner</span><span class="pln">   
</span><span class="pun">--------+----------------+-------+----------</span><span class="pln">
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> products       </span><span class="pun">|</span><span class="pln"> table </span><span class="pun">|</span><span class="pln"> postgres
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> purchase_items </span><span class="pun">|</span><span class="pln"> table </span><span class="pun">|</span><span class="pln"> postgres
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> purchases      </span><span class="pun">|</span><span class="pln"> table </span><span class="pun">|</span><span class="pln"> postgres
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> users          </span><span class="pun">|</span><span class="pln"> table </span><span class="pun">|</span><span class="pln"> postgres
</span><span class="pun">(</span><span class="lit">4</span><span class="pln"> rows</span><span class="pun">)</span></pre>

<p>
	ملاحظة: العبارة <code>hsoubguide‎=#‎</code> مولّدة تلقائيًّا من <code>psql</code> وتحوي اسم قاعدة البيانات التي نحن بداخلها، لذلك لا تقم بنسخها في حال كنت ترغب بنسخ التعليمات في هذا الدليل.
</p>

<h2>
	الاستعلام عن البيانات
</h2>

<p>
	كلمة "استعلام" تعني طلب الحصول على أسطر محددة من قاعدة البيانات، ولكننا قد نرغب في تحديد أعمدة محددة من جداول محددة، وقد نحتاج إلى تحديد شروط على الأسطر التي نرغب بالحصول عليها، كأن نطلب الحصول على المستخدمين الذين لم يقوموا بأي تفاعل منذ سنة، أو الحصول على بيانات عن المنتجات التي يتجاوز عدد مبيعاتها قيمة محددة.
</p>

<p>
	ولذلك فالخطوة الأولى في بناء الاستعلامات هي معرفة مصدر البيانات التي تتعامل معها، ثم معرفة البيانات التي يمكننا الحصول عليها، وهي الأعمدة التي يحتويها الجدول.
</p>

<p>
	في مثالنا التالي، سنحاول معرفة بعض المعلومات عن المستخدمين المخزّنين في قاعدة البيانات.
</p>

<p>
	سنستخدم التعليمة <code>‎\d</code> يليها اسم الجدول لاستعراض أسماء الأعمدة ضمن الجدول كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_40">
hsoubguide=# \d users


                                       Table "public.users"
   Column   |           Type           | Collation | Nullable |              Default              
------------+--------------------------+-----------+----------+-----------------------------------
 id         | integer                  |           | not null | nextval('users_id_seq'::regclass)
 email      | character varying(255)   |           |          | 
 password   | character varying(255)   |           |          | 
 details    | hstore                   |           |          | 
 created_at | timestamp with time zone |           |          | 
 deleted_at | timestamp with time zone |           |          | 
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "purchases" CONSTRAINT "purchases_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)
</pre>

<p>
	ظهر لدينا الآن مجموعة متنوعة من البيانات، سنختار منها المعلومات الثلاث التالية الخاصة بالمستخدمين وهي <code>id</code> و <code>email</code> و <code>created_at</code>.
</p>

<p>
	والآن أصبحنا نعرف المعلومات الأساسية لبناء الاستعلام وهي:
</p>

<ul>
<li>
		الجدول الذي نريد استعلام البيانات منه
	</li>
	<li>
		البيانات التي نريدها من ذاك الجدول
	</li>
</ul>
<p>
	يبين المثال التالي التركيب النحوي للقيام بالاستعلام المطلوب، وهو يحوي البيانات المُراد الحصول عليها، يليها اسم الجدول الحاوي عليها، ثم فاصلة منقوطة للدلالة على انتهاء الاستعلام:
</p>

<pre class="ipsCode" id="ips_uid_8183_42">
hsoubguide=# SELECT id,email,created_at
hsoubguide-# FROM users;


 id |             email             |       created_at       
----+-------------------------------+------------------------
  1 | Earlean.Bonacci@yahoo.com     | 2009-12-20 22:36:00+02
  2 | Evelyn.Patnode@gmail.com      | 2010-11-12 23:27:00+02
  3 | Derek.Crenshaw@gmail.com      | 2009-03-08 05:06:00+02
  4 | Shari.Julian@yahoo.com        | 2010-11-20 12:58:00+02
  5 | Zita.Breeding@gmail.com       | 2009-08-12 01:33:00+03
  6 | Samatha.Hedgpeth@yahoo.com    | 2010-07-18 13:40:00+03
  7 | Quinton.Gilpatrick@yahoo.com  | 2010-09-03 00:56:00+03
  8 | Vivian.Westmoreland@yahoo.com | 2009-10-01 14:34:00+03
  9 | Danny.Crays@gmail.com         | 2009-04-22 10:30:00+03
 10 | Edmund.Roles@yahoo.com        | 2009-07-08 00:01:00+03
 11 | Shanell.Lichtenstein@aol.com  | 2009-05-22 03:18:00+03
 12 | Romaine.Birdsell@aol.com      | 2009-01-14 07:07:00+02
 13 | Zita.Luman@yahoo.com          | 2009-02-04 16:49:00+02
 14 | Claud.Cousineau@gmail.com     | 2009-08-17 21:48:00+03
 15 | Kali.Damore@yahoo.com         | 2010-07-07 13:28:00+03
 16 | Graciela.Kubala@yahoo.com     | 2010-08-19 08:42:00+03
 17 | Theresia.Edwin@yahoo.com      | 2010-08-11 11:21:00+03
 18 | Ozella.Yoshimura@gmail.com    | 2010-07-23 19:03:00+03
 19 | Wynona.Greening@aol.com       | 2009-05-24 17:25:00+03
 20 | Kimi.Mcqueeney@gmail.com      | 2010-06-22 18:16:00+03
 21 | Cherryl.Tarnowski@gmail.com   | 2009-01-26 11:56:00+02
 22 | Isabel.Breeding@gmail.com     | 2010-07-11 16:28:00+03
 23 | Ivana.Kurth@yahoo.com         | 2010-06-25 11:36:00+03
 24 | Humberto.Jonson@yahoo.com     | 2009-09-23 16:09:00+03
 25 | Ivana.Sosnowski@aol.com       | 2009-01-16 13:55:00+02
 26 | Cortney.Strayer@gmail.com     | 2009-07-19 09:08:00+03
 27 | Williams.Upson@gmail.com      | 2010-08-10 08:48:00+03
 28 | Jeremiah.Buonocore@yahoo.com  | 2009-03-19 09:49:00+02
 29 | Ozella.Roles@gmail.com        | 2009-10-09 12:44:00+03
 30 | Salvatore.Arends@aol.com      | 2009-09-05 04:55:00+03
 31 | Layne.Sarver@aol.com          | 2010-09-26 11:00:00+03
 32 | Takako.Gilpatrick@aol.com     | 2009-02-22 17:46:00+02
 33 | Russ.Mcclain@yahoo.com        | 2010-01-12 19:27:00+02
 34 | Claud.Westmoreland@aol.com    | 2010-06-11 20:21:00+03
 35 | Derek.Knittel@gmail.com       | 2010-08-17 00:09:00+03
 36 | Eleanor.Patnode@yahoo.com     | 2010-06-06 04:27:00+03
 37 | Carmel.Bulfer@aol.com         | 2009-06-06 23:13:00+03
 38 | Mauro.Pung@yahoo.com          | 2009-08-20 05:34:00+03
 39 | Sherilyn.Hamill@gmail.com     | 2010-04-02 02:39:00+03
 40 | Glen.Lanphear@yahoo.com       | 2010-08-06 18:14:00+03
 41 | Stacia.Schrack@aol.com        | 2010-06-14 22:28:00+03
 42 | Tonette.Alba@gmail.com        | 2009-12-28 12:21:00+02
 43 | Eve.Kump@yahoo.com            | 2009-08-20 12:45:00+03
 44 | Shanell.Maxson@gmail.com      | 2009-11-21 08:28:00+02
 45 | Gudrun.Arends@gmail.com       | 2010-06-30 15:30:00+03
 46 | Angel.Lessley@yahoo.com       | 2009-08-21 20:06:00+03
 47 | Harrison.Puett@yahoo.com      | 2009-07-21 18:20:00+03
 48 | Granville.Hedgpeth@gmail.com  | 2009-08-03 17:54:00+03
 49 | Samatha.Pellegrin@yahoo.com   | 2009-03-25 22:17:00+02
 50 | Wan.Dilks@gmail.com           | 2009-10-09 01:43:00+03
(50 rows)
</pre>

<p>
	<strong>ملاحظة</strong>: يجب إنهاء تعليمات postgres بفاصلة منقوطة، وفي حال عدم القيام بذلك، فعند الضغط على enter لا تعتبر psql أن التعليمة قد انتهت، وتنتظر كتابة الفاصلة المنقوطة في السطر الجديد.
</p>

<p>
	يسمح لنا الأمر السابق بعرض جميع بيانات الجدول، إلا أن هذا لا يناسب عرض الجداول الحاوية على كمية كبيرة من البيانات، ولذلك يتوجب علينا الحد من كمية البيانات وتصفيتها.
</p>

<h3>
	الحد من البيانات المعروضة باستخدام LIMIT
</h3>

<p>
	يمكننا إضافة التوجيه <code>LIMIT</code> يليه عدد الأسطر الأكبر الذي نسمح بعرضه عند الاستعلام، وذلك للحد من الأسطر المعروضة، كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_44">
hsoubguide=# SELECT id,email,created_at
hsoubguide-# FROM users
hsoubguide-# LIMIT 5;


 id |           email           |       created_at       
----+---------------------------+------------------------
  1 | Earlean.Bonacci@yahoo.com | 2009-12-20 22:36:00+02
  2 | Evelyn.Patnode@gmail.com  | 2010-11-12 23:27:00+02
  3 | Derek.Crenshaw@gmail.com  | 2009-03-08 05:06:00+02
  4 | Shari.Julian@yahoo.com    | 2010-11-20 12:58:00+02
  5 | Zita.Breeding@gmail.com   | 2009-08-12 01:33:00+03
(5 rows)
</pre>

<h3>
	ترتيب البيانات باستخدام ORDER BY
</h3>

<p>
	بعد أن تعرفنا على كيفية الحد من البيانات، قد نرغب بإظهار عدد محدود من البيانات ولكن وفق ترتيب معيّن، فمثلًا نريد الاستعلام عن 5 مستخدمين ولكن بعد ترتيبهم حسب البريد الإلكتروني الخاص بهم، وللقيام بذلك سنستخدم التوجيه <code>ORDER BY</code> كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_46">
hsoubguide=# SELECT id,email,created_at
hsoubguide-# FROM users
hsoubguide-# ORDER BY email
hsoubguide-# LIMIT 5;


 id |            email            |       created_at       
----+-----------------------------+------------------------
 46 | Angel.Lessley@yahoo.com     | 2009-08-21 20:06:00+03
 37 | Carmel.Bulfer@aol.com       | 2009-06-06 23:13:00+03
 21 | Cherryl.Tarnowski@gmail.com | 2009-01-26 11:56:00+02
 14 | Claud.Cousineau@gmail.com   | 2009-08-17 21:48:00+03
 34 | Claud.Westmoreland@aol.com  | 2010-06-11 20:21:00+03
(5 rows)
</pre>

<p>
	ماذا لو أردنا القيام بترتيب تنازلي؟ يمكننا استخدام <code>DESC</code> اختصارًا لكلمة "descending" كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_48">
hsoubguide=# SELECT id,email,created_at
hsoubguide-# FROM users
hsoubguide-# ORDER BY email DESC
hsoubguide-# LIMIT 5;


 id |          email           |       created_at       
----+--------------------------+------------------------
 13 | Zita.Luman@yahoo.com     | 2009-02-04 16:49:00+02
  5 | Zita.Breeding@gmail.com  | 2009-08-12 01:33:00+03
 19 | Wynona.Greening@aol.com  | 2009-05-24 17:25:00+03
 27 | Williams.Upson@gmail.com | 2010-08-10 08:48:00+03
 50 | Wan.Dilks@gmail.com      | 2009-10-09 01:43:00+03
(5 rows)
</pre>

<p>
	فلنلقِ نظرةً على جدول المنتجات كي نحظى بفرصة الحصول على مثالٍ جديد:
</p>

<pre class="ipsCode" id="ips_uid_8183_50">
hsoubguide=# SELECT title,price
hsoubguide-# FROM products
hsoubguide-# LIMIT 8;


      title       | price  
------------------+--------
 Dictionary       |   9.99
 Python Book      |  29.99
 Ruby Book        |  27.99
 Baby Book        |   7.99
 Coloring Book    |   5.99
 Desktop Computer | 499.99
 Laptop Computer  | 899.99
 MP3 Player       | 108.00
(8 rows)
</pre>

<p>
	سنقوم في المثال التالي بترتيب الجدول السابق حسب السعر، ثمّ سنقوم بترتيب المنتجات المتشابهة بالسعر بعكس الترتيب الأبجدي لأسماء المنتجات، وذلك كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_52">
hsoubguide=# SELECT title,price
hsoubguide-# FROM products
hsoubguide-# ORDER BY price ASC, title DESC
hsoubguide-# LIMIT 10;


     title     | price 
---------------+-------
 Coloring Book |  5.99
 Baby Book     |  7.99
 Pop CD        |  9.99
 Holiday CD    |  9.99
 Electronic CD |  9.99
 Dictionary    |  9.99
 Country CD    |  9.99
 Classical CD  |  9.99
 Romantic      | 14.99
 Drama         | 14.99
(10 rows)
</pre>

<h3>
	عمليات التجميع Aggregation Functions
</h3>

<p>
	سنتعرف في هذه الفقرة على توابع يمكنها القيام بتجميع قيم الأعمدة في قيمة واحدة، فمثلًا يمكننا الحصول على متوسط أسعار المنتجات في جدول المنتجات، أو عدد المنتجات الموجودة، أو السعر الأكبر أو اﻷصغر، وذلك كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_54">
hsoubguide=# SELECT MAX(price),MIN(price),AVG(price),SUM(price),COUNT(price)
hsoubguide-# FROM products;


  max   | min  |         avg          |   sum   | count 
--------+------+----------------------+---------+-------
 899.99 | 5.99 | 132.0390476190476190 | 2772.82 |    21
(1 row)
</pre>

<p>
	لاحظ كيف اختلفت المخرجات فلم يعد هناك أسماء الأعمدة المعتادة، بل استُبدلت بأسماء التوابع المستخدمة.
</p>

<p>
	تقوم عملية التجميع <code>COUNT</code> بإرجاع عدد الأسطر التي تحتوي قيمة غير خالية، وسيوضّح المثال التالي ما نرمي إليه:
</p>

<pre class="ipsCode" id="ips_uid_8183_56">
hsoubguide=# SELECT COUNT(*),
hsoubguide-# COUNT(email),
hsoubguide-# COUNT(details)
hsoubguide-# FROM users;


 count | count | count 
-------+-------+-------
    50 |    50 |    34
(1 row)
</pre>

<p>
	لاحظ كيف أرجع استدعاء العملية <code>COUNT</code> على العمود <code>details</code> القيمة 34، رغم أنها أرجعت القيمة 50 للعمود <code>email</code>، وقد استخدمنا كذلك <code>‎‎COUNT‎(*)‎</code> لإظهار عدد جميع الأسطر في الجدول بغض النظر عن قيم الأعمدة.
</p>

<p>
	ولكن هل لاحظت أسماء الأعمدة في المخرجات؟ إنها جميعًا <code>count</code>، ولا يبدو ذلك مفيدًا لمن سيطّلع على هذه المخرجات، ولذلك سنستخدم التوجيه <code>AS</code>.
</p>

<p>
	للمزيد عن عمليات التجميع، يمكنك الرجوع إلى <a data-ss1613715533="1" href="https://www.postgresql.org/docs/8.2/functions-aggregate.html" rel="external nofollow">توثيق Postgres الرسمي</a>.
</p>

<h3>
	التوجيه <code>AS</code>
</h3>

<p>
	يسمح لنا هذا التوجيه بإعادة تسمية أعمدة جدول الخرج، وذلك ليتناسب مع الهدف الذي قُمنا بالاستعلام لأجله.
</p>

<p>
	رأينا في المثال السابق كيف قمنا بثلاث عمليات <code>COUNT</code> مختلفة، ولكن الجدول في المخرجات كانت جميع أعمدته بالاسم <code>count</code> دون تمييز، ولذلك سنستخدم التوجيه <code>AS</code> لتغيير أسماء هذه الأعمدة كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_58">
hsoubguide=# SELECT COUNT(*) AS TOTAL_COUNT,
hsoubguide-# COUNT(email) AS EMAIL_COUNT,
hsoubguide-# COUNT(details) AS DETAILS_COUNT
hsoubguide-# FROM users;


 total_count | email_count | details_count 
-------------+-------------+---------------
          50 |          50 |            34
(1 row)
</pre>

<p>
	الآن أصبحت المخرجات مقروءة ومفهومة أكثر، ولكن تجدر بنا الإشارة إلى أن ذكر التوجيه <code>AS</code> هو أمر اختياريّ، فيمكننا تسمية جداول الخرج بدون الحاجة إلى كتابة التوجيه <code>AS</code> كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_60">
hsoubguide=# SELECT COUNT(*) TOTAL_COUNT,
hsoubguide-# COUNT(email) EMAIL_COUNT,
hsoubguide-# COUNT(details) DETAILS_COUNT
hsoubguide-# FROM users;


 total_count | email_count | details_count 
-------------+-------------+---------------
          50 |          50 |            34
(1 row)
</pre>

<p>
	حافظ دومًا على مقروئية الجدول في المخرجات، فقد يكون لديك في العمود عمليات حسابية أو عدة توابع في عبارة واحدة، وهنا سيكون لزامًا استخدام الأسماء المستعارة للأعمدة وإلا ستبدو الجداول في المخرجات غير مفهومة.
</p>

<h3>
	ترشيح البيانات (Filtering)
</h3>

<p>
	قًمنا حتى الآن باستعلام جميع البيانات في الجدول، وأكثر ما استطعنا تحديده هو تقليل عدد الأسطر في المخرجات، وترتيبها بشرط محدد، ولكننا ماذا لو أردنا استعراض جميع الأسطر التي تحقق شرطًا ما؟ كيف يمكننا استعراض المنتجات التي يتجاوز سعرها قيمة محددة؟ أو المستخدمين الذين أنشئت حساباتهم بعد تاريخ محدد؟
</p>

<p>
	يمكننا ترشيح البيانات باستخدام الشرط <code>WHERE</code>، ويبين المثال التالي عملية ترشيح للحصول على المستخدمين الذين أُنشئ حسابهم في تاريخ 30/6/2010 فصاعدًا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_62" style="">
<span class="pln">SELECT email</span><span class="pun">,</span><span class="pln"> created_at
FROM users
WHERE created_at </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="str">'2010-06-30'</span><span class="pun">;</span></pre>

<p>
	كما يمكننا دمج شروط أخرى باستخدام <code>AND</code> أو <code>OR</code>، ويبين المثال التالي استخدام <code>AND</code> للاستعلام عن جميع المستخدمين الذين قاموا بإنشاء حسابات في شهر تموز عام 2010:
</p>

<pre class="ipsCode" id="ips_uid_8183_64">
hsoubguide=# SELECT email, created_at
hsoubguide-# FROM users
hsoubguide-# WHERE created_at &gt;= '2010-07-01'
hsoubguide-#   AND created_at &lt; '2010-08-01';


           email            |       created_at       
----------------------------+------------------------
 Samatha.Hedgpeth@yahoo.com | 2010-07-18 13:40:00+03
 Kali.Damore@yahoo.com      | 2010-07-07 13:28:00+03
 Ozella.Yoshimura@gmail.com | 2010-07-23 19:03:00+03
 Isabel.Breeding@gmail.com  | 2010-07-11 16:28:00+03
(4 rows)
</pre>

<p>
	<strong>ملاحظة</strong>: لاحظ كيف يتغيّر محثّ الأوامر من <code>‎‎hsoubguide=#‎</code> إلى <code>hsoubguide-#‎</code> عندما تتوزع التعليمة على عدة أسطر، وتكون الفاصلة المنقوطة هي نهاية التعليمة.
</p>

<p>
	والآن ما رأيك باستخدام بعض أوامر التجميع مثل SUM و AVG وغيرها للحصول على بعض المعلومات المفيدة!
</p>

<p>
	سنبدأ بالاطلاع على جدول المنتجات المشتراة، لنرى ماذا بإمكاننا أن نستخلص منه من المعلومات:
</p>

<pre class="ipsCode" id="ips_uid_8183_66">
hsoubguide=# SELECT *
hsoubguide-# FROM purchase_items
hsoubguide-# LIMIT 20;


 id | purchase_id | product_id | price  | quantity |   state   
----+-------------+------------+--------+----------+-----------
  2 |           1 |          3 |  27.99 |        1 | Delivered
  3 |           1 |          8 | 108.00 |        1 | Delivered
  4 |           2 |          1 |   9.99 |        2 | Delivered
  5 |           3 |         12 |   9.99 |        1 | Delivered
  6 |           3 |         17 |  14.99 |        4 | Delivered
  7 |           3 |         11 |   9.99 |        1 | Delivered
  8 |           4 |          4 |   7.99 |        3 | Delivered
  9 |           5 |         18 |  14.99 |        1 | Delivered
 10 |           5 |          2 |  29.99 |        4 | Delivered
 11 |           6 |          5 |   5.99 |        1 | Delivered
 12 |           7 |          6 | 499.99 |        3 | Returned
 13 |           8 |         10 | 529.00 |        1 | Delivered
 14 |           8 |          7 | 899.99 |        1 | Delivered
 15 |           9 |         15 |   9.99 |        2 | Delivered
 16 |          10 |          2 |  29.99 |        1 | Delivered
 17 |          11 |          9 | 499.00 |        2 | Delivered
 18 |          12 |         14 |   9.99 |        5 | Delivered
 19 |          12 |         10 | 529.00 |        1 | Delivered
 20 |          13 |          8 | 108.00 |        1 | Delivered
 21 |          14 |         20 |  14.99 |        1 | Delivered
(20 rows)
</pre>

<p>
	هذا الجدول فيه الكثير من المعلومات الهامة، وسنعود إليه في الفقرة التالية، ولكن الآن يمكننا رؤية أن بعض عمليات الشراء يتم إيصالها "Delivered" وبعضها تُرجع للمتجر "Returned"، وسنقوم في المثال التالي بعدّها، وإيجاد مجموع المشتريات التي تم إيصالها بالفعل.
</p>

<pre class="ipsCode" id="ips_uid_8183_73">
hsoubguide=# SELECT COUNT(*)
hsoubguide-# FROM purchase_items
hsoubguide-# WHERE state='Delivered';


 count 
-------
  3888
(1 row)</pre>

<pre class="ipsCode" id="ips_uid_8183_71">
hsoubguide=# SELECT COUNT(*)
hsoubguide-# FROM purchase_items
hsoubguide-# WHERE state='Returned';
 count 
-------
   246
(1 row)
</pre>

<pre class="ipsCode" id="ips_uid_8183_75">
hsoubguide=# SELECT COUNT(*)
hsoubguide-# FROM purchase_items;
 count 
-------
  4371
(1 row)
</pre>

<p>
	سنوجد مجموع المشتريات التي سُلِّمَت بالفعل، وتلك التي أُعيدَت:
</p>

<pre class="ipsCode" id="ips_uid_8183_77">
hsoubguide=# SELECT SUM(price)
hsoubguide-# FROM purchase_items
hsoubguide-# WHERE state='Delivered';

    sum    
-----------
 517787.85
(1 row)</pre>

<pre class="ipsCode" id="ips_uid_8183_81">
hsoubguide=# SELECT SUM(price)
hsoubguide-# FROM purchase_items
hsoubguide-# WHERE state='Returned';

   sum    
----------
 36456.87
(1 row)
</pre>

<h3>
	استخدام عبارة <code>CASE</code> الشرطية
</h3>

<p>
	تسمح لنا عبارة <code>CASE</code> بعمل بنية مشابهة للبنية البرمجية <code>switch</code> الموجودة في معظم لغات البرمجة، أو يمكن تشبيهها أكثر بعبارات <code>if</code> متتابعة، حيث يمكننا إنتاج قِيَم محددة بناءً على اختبارات على قيم أُخرى، ولا بد أنه المثال سيوضّح المقال.
</p>

<p>
	ننشئ جدولًا بسيطًا فيه عمود واحد يحوي أعدادًا صحيحة.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_83" style="">
<span class="pln">hsoubguide</span><span class="pun">=#</span><span class="pln"> CREATE TABLE case_example</span><span class="pun">(</span><span class="pln">
hsoubguide</span><span class="pun">(#</span><span class="pln">      number INT
hsoubguide</span><span class="pun">(#</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
           
CREATE TABLE</span></pre>

<p>
	وسنقوم بإدخال 5 أعداد في هذا الجدول كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_85">
hsoubguide=# INSERT INTO case_example VALUES(1),(2),(3),(4),(5),(6);
INSERT 0 6
hsoubguide=# SELECT * FROM case_example ;

 number 
--------
      1
      2
      3
      4
      5
      6
(6 rows)
</pre>

<p>
	والآن سنقوم بالاستعلام عن عناصر هذا العمود، ولكن بدلًا من طباعة العنصر كما هو، سنطبع عبارات حسوبية بناءً على قيمة هذا العمود.
</p>

<pre class="ipsCode" id="ips_uid_8183_87">
hsoubguide=# SELECT (CASE
    WHEN number=1 THEN 'Hsoub'
    WHEN number=2 OR number=3 THEN 'Khamsat'
    WHEN number&lt;5 THEN 'Mostaql'
    WHEN number&gt;=5 AND number&lt;=6 THEN 'ANA'
    WHEN number=7 THEN 'IO'
    ELSE '.com'
    END) FROM case_example ;

  case   
---------
 Hsoub
 Khamsat
 Khamsat
 Mostaql
 ANA
 ANA
(6 rows)
</pre>

<h2>
	التعديل UPDATE والحذف DELETE
</h2>

<p>
	بعد أن تعرّفنا على كيفية ترشيح البيانات في الاستعلامات، سنستخدم تعليمة الترشيح نفسها <code>WHERE</code> لتحديد الأسطر التي نرغب بالتعديل على محتوياتها أو حذفها.
</p>

<p>
	انتبه: في هذه الفقرة نقوم بالتعديل على محتويات الجدول من البيانات، أو حذف سطر ما من أسطر الجدول، أما لو أردت التعديل على الجدول نفسه بإضافة عمود أو حذف عمود، أو التعديل على اسم عمود ما أو نوع بياناته، فعليك استخدام التعليمة <code>ALTER</code> المذكورة في فقرة تعديل الجداول.
</p>

<p>
	سننشئ أولًا جدولًا جديدًا، كيف لا تؤثر على جداولنا السابقة التي تحوي معلومات مهمة:
</p>

<pre class="ipsCode" id="ips_uid_8183_98">
hsoubguide=# CREATE TABLE test_table(
hsoubguide(# id integer PRIMARY KEY,
hsoubguide(# number integer,
hsoubguide(# name character varying(5)
hsoubguide(# );

CREATE TABLE

</pre>

<pre class="ipsCode" id="ips_uid_8183_100">
hsoubguide=# INSERT INTO test_table VALUES
hsoubguide-# (1,10,'hello'),
hsoubguide-# (2,13,'mosta'),
hsoubguide-# (3,-5,'test2'),
hsoubguide-# (4,22,'hel..'),
hsoubguide-# (5,-9,'test1');

INSERT 0 5
</pre>

<p>
	وهذه هي محتويات الجدول الجديد:
</p>

<pre class="ipsCode" id="ips_uid_8183_102">
hsoubguide=# SELECT * from test_table;

 id | number | name  
----+--------+-------
  1 |     10 | hello
  2 |     13 | mosta
  3 |     -5 | test2
  4 |     22 | hel..
  5 |     -9 | test1
(5 rows)
</pre>

<h3>
	التعديل على الأسطر
</h3>

<p>
	يمكننا باستخدام الأمر <code>UPDATE</code> مع إضافة التوجيه <code>SET</code> تعديل الأسطر التي تحقق الشرط المذكور في تعليمة الترشيح <code>WHERE</code> كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# UPDATE test_table SET name = 'O_O' WHERE id =1;
UPDATE 1

hsoubguide=# SELECT * FROM test_table ;
 id | number | name  
----+--------+-------
  2 |     13 | mosta
  4 |     22 | hel..
  3 |    -50 | test2
  5 |    -90 | test1
  1 |     10 | O_O
(5 rows)
</pre>

<p>
	كما يمكن تعديل عدة أعمدة معًا حسب شرط محدد، كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_104">
hsoubguide=# UPDATE test_table
hsoubguide=# SET name = ('WOW' || id ),
hsoubguide=# number = id*10
hsoubguide=# WHERE id &gt; 3;

UPDATE 2</pre>

<pre class="ipsCode" id="ips_uid_8183_106">
hsoubguide=# SELECT * from test_table ;

 id | number | name  
----+--------+-------
  2 |     13 | mosta
  3 |    -50 | test2
  1 |     10 | O_O
  4 |     40 | WOW4
  5 |     50 | WOW5
(5 rows)
</pre>

<p>
	عدَّلنَا في المثال السابق القيمة في العمود <code>name</code> لتحتوي كلمة <code>WOW</code> موصولة بالرقم المحتوى في العمود <code>id</code> للسطر نفسه. وعدَّلنا القيمة في العمود <code>number</code> لتكون ناتج ضرب الرقم الموجود في العمود <code>id</code> مضروبًا بـ<code>10</code>. وهذه التعديلات تتم على الأسطر التي يتحقق فيها الشرط <code>id&gt;3</code>.
</p>

<p>
	في حال لم نضع أي شرط على القيام بالتعديل، فإن التعديل ينفّذ على جميع الأسطر، كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_108">
hsoubguide=# UPDATE test_table
hsoubguide=# SET number = LENGTH(name);

UPDATE 5
</pre>

<pre class="ipsCode" id="ips_uid_8183_110">
hsoubguide=# SELECT * from test_table ;

 id | number | name  
----+--------+-------
  2 |      5 | mosta
  3 |      5 | test2
  1 |      3 | O_O
  4 |      4 | WOW4
  5 |      4 | WOW5
(5 rows)
</pre>

<p>
	استخدمنا التابع <code>LENGTH</code> الذي يُرجع عدد الحروف للوسيط المُمرَّر له، ثم أسندناها للعمود <code>number</code>، وذلك دون استخدام أي شرط، لذلك تم تنفيذ التعديلات على جميع الأسطر.
</p>

<h3>
	إجراء عمليات حسابية على الأعمدة
</h3>

<p>
	يمكننا استخدام تعليمة التعديل <code>UPDATE</code> لتعديل قيم عمود ما عن طريق عملية حسابية أو أي عملية أخرى، كما في المثال التالي:
</p>

<pre class="ipsCode" id="ips_uid_8183_112">
hsoubguide=# UPDATE test_table
hsoubguide-# SET number = number*10
hsoubguide-# WHERE number &gt;3
hsoubguide-# ;

UPDATE 4
</pre>

<pre class="ipsCode" id="ips_uid_8183_114">
hsoubguide=# SELECT * from test_table 
hsoubguide-# ;

 id | number | name  
----+--------+-------
  1 |      3 | O_O
  2 |     50 | mosta
  3 |     50 | test2
  4 |     40 | WOW4
  5 |     40 | WOW5
(5 rows)
</pre>

<h3>
	تعديل أسطر الجدول مع إظهار التعديلات
</h3>

<p>
	يمكن استخدام الكلمة المفتاحية <code>RETURNING</code> بشكل مشابه للاستعلام SELECT في نهاية عبارة التعديل، بحيث يتم التعديل ثم الاستعلام عن بعض الأعمدة في الجدول المعدّل وعرضها، وذلك كما في المثال التالي:
</p>

<pre class="ipsCode">
hsoubguide=# UPDATE test_table
hsoubguide=# SET name=number
hsoubguide=# WHERE id&lt;3
hsoubguide=# RETURNING id,number,name;

 id | number | name 
----+--------+------
  1 |     10 | 10
  2 |     13 | 13
(2 rows)

UPDATE 2
</pre>

<h3>
	حذف الأسطر
</h3>

<p>
	يمكننا حذف سطر ما عن طريق تحديد شرط ما يشير إلى ذلك السطر بالذات دون سواه، ويُعد المعرّف الخاص بالسطر أفضل ما يمكن تحديده لحذف سطرٍ ما مع ضمان عدم حذف سواه، وذلك لأن له المواصفة <code>PRIMARY KEY</code> التي تمنع إنشاء سطرين بنفس القيمة في العمود <code>id</code>.
</p>

<p>
	أوًلًا سنسترجع الجدول الخاص بنا قبل إجراء عمليات التعديل في الفقرة السابقة، وذلك عن طريق حذف جميع الأسطر، ثم إدخالها مرةً أخرى.
</p>

<p>
	يمكنك حذف جميع محتويات الجدول كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_117">
hsoubguide=# DELETE FROM test_table;

DELETE 5
</pre>

<pre class="ipsCode" id="ips_uid_8183_119">
hsoubguide=# SELECT * FROM test_table;

 id | number | name 
----+--------+------
(0 rows)
</pre>

<p>
	ثم سنعيد إدخال الأسطر كما سبق:
</p>

<pre class="ipsCode" id="ips_uid_8183_121">
hsoubguide=# INSERT INTO test_table VALUES
hsoubguide-# (1,10,'hello'),
hsoubguide-# (2,13,'mosta'),
hsoubguide-# (3,-5,'test2'),
hsoubguide-# (4,22,'hel..'),
hsoubguide-# (5,-9,'test1');

INSERT 0 5
</pre>

<p>
	سنحذف الآن السطر ذا المُعرّف <code>id</code> بقيمة 5:
</p>

<pre class="ipsCode" id="ips_uid_8183_127">
hsoubguide=# DELETE FROM test_table
hsoubguide-# WHERE id=5;

DELETE 1</pre>

<pre class="ipsCode" id="ips_uid_8183_129">
hsoubguide=# SELECT * FROM test_table;

 id | number | name  
----+--------+-------
  1 |     10 | hello
  2 |     13 | mosta
  3 |     -5 | test2
  4 |     22 | hel..
(4 rows)
</pre>

<p>
	<strong>تحذير</strong>: تُعد تعليمة <code>DELETE</code> من التعليمات الخطيرة، فالسطر المحذوف لا يمكن استعادته إلا في حال وجود نسخة احتياطية عن قاعدة البيانات، فاستخدم هذه التعليمة بحذر.
</p>

<p>
	يمكننا طبعًا استخدام تعليمة الترشيح <code>WHERE</code> لتحديد أكثر من سطر، ومن ثمّ سيتم حذف جميع الأسطر التي تحقق الشرط المحدد، فمثلًا يمكننا حذف جميع الأسطر التي تكون قيمة العمود <code>number</code> فيها موجبة كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_131">
hsoubguide=# DELETE FROM test_table
hsoubguide=# WHERE number&gt;0;

DELETE 3
</pre>

<pre class="ipsCode" id="ips_uid_8183_133">
hsoubguide=# SELECT * from test_table;

 id | number | name  
----+--------+-------
  3 |     -5 | test2
(1 row)
</pre>

<h2>
	الربط Join
</h2>

<p>
	سنتعرف في هذه الفقرة على أسلوب أساسي في استخراج البيانات المرتبطة من عدة جداول، وطريقتها الرئيسية ببساطة، هي طلب البيانات من عدة جداول ثم تصفيتها، وسنبدأ بأبسط طرق الربط على الإطلاق، ونتدرج فيها إلى الوصول إلى أنواع الربط المتعددة.
</p>

<h3>
	الاستعلام من عدة جداول معًا
</h3>

<p>
	سننشئ جدولين للاختبار وإدخال بيانات إليهما، كي نتمكن من استعراض المثال الخاص بنا:
</p>

<p>
	الجدول الأول اسمه <code>names</code> فيه عمودان، الأول رقم معرّف للشخص، والثاني فيه اسمه.
</p>

<pre class="ipsCode" id="ips_uid_8183_135">
hsoubguide=# CREATE TABLE names(
hsoubguide(#     id integer PRIMARY KEY,
hsoubguide(#     name character varying(255)
hsoubguide(# );

CREATE TABLE</pre>

<pre class="ipsCode" id="ips_uid_8183_137">
hsoubguide=# INSERT INTO names VALUES
hsoubguide-# (1,'mostafa'),
hsoubguide-# (2,'ali'),
hsoubguide-# (3,'fares');

INSERT 0 3
</pre>

<pre class="ipsCode" id="ips_uid_8183_139">
hsoubguide=# SELECT * FROM names;

 id |  name   
----+---------
  1 | mostafa
  2 | ali
  3 | fares
(3 rows)
</pre>

<p>
	أما الجدول الثاني، ففيه أرقام هواتف نفس الأشخاص، ولكن لن نضع فيه أسماءهم، ففيه الرقم المعرّف بالشخص، ورقم هاتفه:
</p>

<pre class="ipsCode" id="ips_uid_8183_141">
hsoubguide=# CREATE TABLE phones(
hsoubguide(#     id integer PRIMARY KEY,
hsoubguide(#     phone character varying(15)
hsoubguide(# );

CREATE TABLE
</pre>

<pre class="ipsCode" id="ips_uid_8183_143">
hsoubguide=# INSERT INTO phones VALUES
hsoubguide-# (1,'+966123456789'),
hsoubguide-# (2,'+961111111111'),
hsoubguide-# (3,'+962333333333');

INSERT 0 3
</pre>

<pre class="ipsCode" id="ips_uid_8183_145">
hsoubguide=# SELECT * FROM phones;

 id |     phone     
----+---------------
  1 | +966123456789
  2 | +961111111111
  3 | +962333333333
(3 rows)
</pre>

<p>
	فلنبدأ بالاستعلام عن البيانات من الجدولين معًا:
</p>

<pre class="ipsCode" id="ips_uid_8183_147">
hsoubguide=# SELECT * FROM names, phones;

 id |  name   | id |     phone     
----+---------+----+---------------
  1 | mostafa |  1 | +966123456789
  2 | ali     |  1 | +966123456789
  3 | fares   |  1 | +966123456789
  1 | mostafa |  2 | +961111111111
  2 | ali     |  2 | +961111111111
  3 | fares   |  2 | +961111111111
  1 | mostafa |  3 | +962333333333
  2 | ali     |  3 | +962333333333
  3 | fares   |  3 | +962333333333
(9 rows)
</pre>

<p>
	لاحظ كيف تم إظهار جميع أسطر الجدول الأول مرتبطة بسطر واحد من الجدول الثاني، ثم مرةً أخرى، جميع أسطر الجدول الأول مرتبطة بالسطر الثاني من الجدول الثاني وهكذا.
</p>

<p>
	ماذا لو أردنا عرض اسم الشخص مع رقم هاتفه؟ يكفي أن نختار الأسطر التي يتوافق فيها العمود <code>id</code> من الجدول <code>names</code> مع العمود <code>id</code> من الجدول <code>phones</code>، ولكن علينا كتابة اسم الجدول تليه نقطة <code>.</code> ثم اسم العمود <code>id</code> كي نتمكن من تمييز العمود الموجود في الجدول الأول عن الآخر في الجدول الثاني، كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_8183_149">
hsoubguide=# SELECT * FROM phones, names
hsoubguide-# WHERE phones.id = names.id;

 id |     phone     | id |  name   
----+---------------+----+---------
  1 | +966123456789 |  1 | mostafa
  2 | +961111111111 |  2 | ali
  3 | +962333333333 |  3 | fares
(3 rows)
</pre>

<p>
	قمنا لتوّنا بالربط بين جدولين، وسنقوم بتحسين المخرجات الآن قليلًا، بعرض العمود <code>id</code> مرة واحدة:
</p>

<pre class="ipsCode" id="ips_uid_8183_151">
hsoubguide=# SELECT phones.id,phone,name
hsoubguide-# FROM phones,names
hsoubguide-# WHERE phones.id = names.id;

 id |     phone     |  name   
----+---------------+---------
  1 | +966123456789 | mostafa
  2 | +961111111111 | ali
  3 | +962333333333 | fares
(3 rows)
</pre>

<p>
	والآن يمكننا أن نتّجه إلى تطبيق الربط على مثالنا الخاص بالمنتجات المشتراة، هل تتذكر جدول المنتجات المُشتراة:
</p>

<pre class="ipsCode" id="ips_uid_8183_153">
hsoubguide=# SELECT *
hsoubguide-# FROM purchase_items
hsoubguide-# LIMIT 6;

 id | purchase_id | product_id | price  | quantity |   state   
----+-------------+------------+--------+----------+-----------
  2 |           1 |          3 |  27.99 |        1 | Delivered
  3 |           1 |          8 | 108.00 |        1 | Delivered
  4 |           2 |          1 |   9.99 |        2 | Delivered
  5 |           3 |         12 |   9.99 |        1 | Delivered
  6 |           3 |         17 |  14.99 |        4 | Delivered

(6 rows)
</pre>

<p>
	لاحظ الأعمدة الأولى، <code>purchase_id</code> يدل على المعرّف الخاص بعملية الشراء كاملة (التي يقوم بها زبون ما في وقت محدد)، والعمود <code>product_id</code> الذي يحدد المعرف الخاص بالمنتج الذي تم شراؤه.
</p>

<p>
	هذه الأعمدة لا تحتوي بيانات عن المنتجات أو عن عملية الشراء، بل هي تشير إلى المعرّف الخاص بها في الجداول الخاصة بها، فهل يمكننا استخدام هذا المعرّف لجلب تلك البيانات من جداولها ثم دمج تلك البيانات مع بيانات الجدول الحالي؟
</p>

<p>
	ما نحاول الوصول إليه في هذه الفقرة، هو ربط عدة جداول مع بعضها، للحصول على معلومات متكاملة في جدول الخرج، فبدلًا من عرض المعرّف الخاص بالمنتج، نريد عرض اسمه مثلًا، وبدلًا من عرض المعرّف الخاص بعملية الشراء نريد عرض المستخدم الذي قام بالشراء.
</p>

<p>
	فلنلقِ نظرة على مخطط قاعدة البيانات الخاصة بنا:
</p>

<pre class="ipsCode" id="ips_uid_8183_155">
hsoubguide=# \dt
             List of relations
             
 Schema |      Name      | Type  |  Owner   
--------+----------------+-------+----------
 public | products       | table | postgres
 public | purchase_items | table | postgres
 public | purchases      | table | postgres
 public | users          | table | postgres
(4 rows)
</pre>

<p>
	وسنقوم في مثالنا التالي بالاستعلام عن المنتجات التي تم شراؤها مؤخرًا، ونحتاج للقيام بذلك إلى بيانات من جدولي المنتجات والمشتريات معًا، وسنبدأ بأخذ نظرة إلى الجدولين لمعرفة الأعمدة التي سنتحتاج إليها:
</p>

<p>
	يحوي الجدول <code>products</code> على تفاصيل المنتجات، كاسم المنتج وسعره:
</p>

<pre class="ipsCode" id="ips_uid_8183_157">
hsoubguide=# SELECT * from products;

 id |      title       | price  |       created_at       | deleted_at |           tags            
----+------------------+--------+------------------------+------------+---------------------------
  1 | Dictionary       |   9.99 | 2011-01-01 22:00:00+02 |            | {Book}
  2 | Python Book      |  29.99 | 2011-01-01 22:00:00+02 |            | {Book,Programming,Python}
  3 | Ruby Book        |  27.99 | 2011-01-01 22:00:00+02 |            | {Book,Programming,Ruby}
  4 | Baby Book        |   7.99 | 2011-01-01 22:00:00+02 |            | {Book,Children,Baby}
  5 | Coloring Book    |   5.99 | 2011-01-01 22:00:00+02 |            | {Book,Children}
  6 | Desktop Computer | 499.99 | 2011-01-01 22:00:00+02 |            | {Technology}
  7 | Laptop Computer  | 899.99 | 2011-01-01 22:00:00+02 |            | {Technology}
  8 | MP3 Player       | 108.00 | 2011-01-01 22:00:00+02 |            | {Technology,Music}
  9 | 42" LCD TV       | 499.00 | 2011-01-01 22:00:00+02 |            | {Technology,TV}
 10 | 42" Plasma TV    | 529.00 | 2011-01-01 22:00:00+02 |            | {Technology,TV}
 11 | Classical CD     |   9.99 | 2011-01-01 22:00:00+02 |            | {Music}
 12 | Holiday CD       |   9.99 | 2011-01-01 22:00:00+02 |            | {Music}
 13 | Country CD       |   9.99 | 2011-01-01 22:00:00+02 |            | {Music}
 14 | Pop CD           |   9.99 | 2011-01-01 22:00:00+02 |            | {Music}
 15 | Electronic CD    |   9.99 | 2011-01-01 22:00:00+02 |            | {Music}
 16 | Comedy Movie     |  14.99 | 2011-01-01 22:00:00+02 |            | {Movie,Comedy}
 17 | Documentary      |  14.99 | 2011-01-01 22:00:00+02 |            | {Movie}
 18 | Romantic         |  14.99 | 2011-01-01 22:00:00+02 |            | {Movie}
 19 | Drama            |  14.99 | 2011-01-01 22:00:00+02 |            | {Movie}
 20 | Action           |  14.99 | 2011-01-01 22:00:00+02 |            | {Movie}
(20 rows)
</pre>

<p>
	بينما يحوي الجدول <code>purchase_items</code> على تفاصيل عمليات الشراء، ففي كل عملية شراء، يمكن أن يكون هناك عدة منتجات مُشتراة، حيث يحوي السطر الواحد في هذا الجدول على عملية شراء لمنتج واحد، ويخزن العمود <code>purchase_id</code> رقمًا تسلسليًّا لعملية الشراء الكاملة، ويشير العمود <code>product_id</code> إلى الرقم المعرّف للمنتج، وهو نفسه الموجود في الجدول السابق <code>products</code> وبفضل وجوده يمكننا الربط بين الجدولين.
</p>

<pre class="ipsCode" id="ips_uid_8183_159">
hsoubguide=# SELECT * from purchase_items LIMIT 12;

 id | purchase_id | product_id | price  | quantity |   state   
----+-------------+------------+--------+----------+-----------
  2 |           1 |          3 |  27.99 |        1 | Delivered
  3 |           1 |          8 | 108.00 |        1 | Delivered
  4 |           2 |          1 |   9.99 |        2 | Delivered
  5 |           3 |         12 |   9.99 |        1 | Delivered
  6 |           3 |         17 |  14.99 |        4 | Delivered
  7 |           3 |         11 |   9.99 |        1 | Delivered
  8 |           4 |          4 |   7.99 |        3 | Delivered
  9 |           5 |         18 |  14.99 |        1 | Delivered
 10 |           5 |          2 |  29.99 |        4 | Delivered
 11 |           6 |          5 |   5.99 |        1 | Delivered
 12 |           7 |          6 | 499.99 |        3 | Returned
 13 |           8 |         10 | 529.00 |        1 | Delivered
(12 rows)
</pre>

<p>
	الطريقة الأساسية لربط الجداول هي المفاتيح (keys) وسنشرح عنها لاحقًا باستفاضة أكثر، أما ما يهمنا الآن هو معرفة أن العمود <code>product_id</code> في جدول المشتريات يشير إلى العمود <code>id</code> في جدول المنتجات.
</p>

<p>
	والآن يمكننا إنشاء الاستعلام كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_161" style="">
<span class="pln">SELECT 
   products</span><span class="pun">.</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> 
   purchase_items</span><span class="pun">.</span><span class="pln">quantity
FROM 
   products</span><span class="pun">,</span><span class="pln">
   purchase_items
WHERE
   products</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> purchase_items</span><span class="pun">.</span><span class="pln">product_id
LIMIT </span><span class="lit">12</span><span class="pun">;</span></pre>

<p>
	لاحظ كيف يتم طلب عمودين من جدولين مختلفين عن طريق كتابة اسم الجدول تتبعه نقطة <code>.</code> ثم اسم العمود المطلوب.
</p>

<p>
	وستكون المخرجات بالشكل التالي:
</p>

<pre class="ipsCode">
      title       | quantity 
------------------+----------
 Ruby Book        |        1
 MP3 Player       |        1
 Dictionary       |        2
 Holiday CD       |        1
 Documentary      |        4
 Classical CD     |        1
 Baby Book        |        3
 Romantic         |        1
 Python Book      |        4
 Coloring Book    |        1
 Desktop Computer |        3
 42" Plasma TV    |        1
(12 rows)
</pre>

<p>
	نلاحظ في المثال السابق، أنه ليس لدينا تفاصيل عن عملية الشراء، سوى عن الكمية المشتراة من كل منتج، وسنحاول في المثال التالي استعراض المنتج والكمية المشتراة، مع ذكر اسم المشتري وتاريخ الشراء، كي تكون المعلومات المعروضة مفيدة أكثر.
</p>

<p>
	نستعرض أولًا الجدول <code>purchases</code>:
</p>

<pre class="ipsCode" id="ips_uid_8183_163">
hsoubguide=# SELECT * FROM purchases LIMIT 7;

 id |       created_at       |        name        |    address     | state | zipcode | user_id 
----+------------------------+--------------------+----------------+-------+---------+---------
  1 | 2011-03-16 17:03:00+02 | Harrison Jonson    | 6425 43rd St.  | FL    |   50382 |       7
  2 | 2011-09-14 08:00:00+03 | Cortney Fontanilla | 321 MLK Ave.   | WA    |   43895 |      30
  3 | 2011-09-11 08:54:00+03 | Ruthie Vashon      | 2307 45th St.  | GA    |   98937 |      18
  4 | 2011-02-27 22:53:00+02 | Isabel Wynn        | 7046 10th Ave. | NY    |   57243 |      11
  5 | 2011-12-20 14:45:00+02 | Shari Dutra        | 4046 8th Ave.  | FL    |   61539 |      34
  6 | 2011-12-10 15:29:00+02 | Kristofer Galvez   | 2545 8th Ave.  | WA    |   83868 |      39
  7 | 2011-06-19 06:42:00+03 | Maudie Medlen      | 2049 44th Ave. | FL    |   52107 |       8
(7 rows)
</pre>

<p>
	وجدنا الأعمدة التي كنا نبحث عنها في ما أردنا الوصول إليه قبل قليل، إنها الأعمدة <code>name</code> و <code>created_at</code>، ويمكننا الآن ربط هذين العمودين بالاستعلام السابق للحصول على مخرجات أكثر فائدة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_165" style="">
<span class="pln">SELECT 
   products</span><span class="pun">.</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> 
   purchase_items</span><span class="pun">.</span><span class="pln">quantity</span><span class="pun">,</span><span class="pln">
   purchases</span><span class="pun">.</span><span class="pln">name</span><span class="pun">,</span><span class="pln">
   purchases</span><span class="pun">.</span><span class="pln">created_at
FROM 
   products</span><span class="pun">,</span><span class="pln">
   purchase_items</span><span class="pun">,</span><span class="pln">
   purchases
WHERE
   products</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> purchase_items</span><span class="pun">.</span><span class="pln">product_id AND
   purchases</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> purchase_items</span><span class="pun">.</span><span class="pln">purchase_id
LIMIT </span><span class="lit">12</span><span class="pun">;</span></pre>

<p>
	لاحظ في المثال السابق عبارة <code>WHERE</code> المرشِّحة، حيث وضعنا فيها شرطين. وسنحصل على المخرجات التالية:
</p>

<pre class="ipsCode">
      title       | quantity |        name        |       created_at       
------------------+----------+--------------------+------------------------
 Ruby Book        |        1 | Harrison Jonson    | 2011-03-16 17:03:00+02
 MP3 Player       |        1 | Harrison Jonson    | 2011-03-16 17:03:00+02
 Dictionary       |        2 | Cortney Fontanilla | 2011-09-14 08:00:00+03
 Holiday CD       |        1 | Ruthie Vashon      | 2011-09-11 08:54:00+03
 Documentary      |        4 | Ruthie Vashon      | 2011-09-11 08:54:00+03
 Classical CD     |        1 | Ruthie Vashon      | 2011-09-11 08:54:00+03
 Baby Book        |        3 | Isabel Wynn        | 2011-02-27 22:53:00+02
 Romantic         |        1 | Shari Dutra        | 2011-12-20 14:45:00+02
 Python Book      |        4 | Shari Dutra        | 2011-12-20 14:45:00+02
 Coloring Book    |        1 | Kristofer Galvez   | 2011-12-10 15:29:00+02
 Desktop Computer |        3 | Maudie Medlen      | 2011-06-19 06:42:00+03
 42" Plasma TV    |        1 | Isabel Crissman    | 2011-05-28 04:19:00+03
(12 rows)
</pre>

<p>
	في المثال السابق، ربطنا ثلاثة جداول للحصول على معلومات مترابطة وإظهارها في جدول مخرجات واحد، ولكن ربما لاحظت كيف أصبح الاستعلام طويلًا، ومعقّدًا بعض الشيء، ولذلك وُجد العرض View كطريقة لحفظ الاستعلام كجدول منطقي جديد، لا يُخزّن في الذاكرة، ولكن يمكننا التعامل معه كأنه كذلك، وهو ما سنتحدث عنه بعد استعراض أنواع الربط المختلفة.
</p>

<h3>
	أنواع الربط
</h3>

<p>
	سنستعرض أنواعًا أخرى من الربط الذي قمنا به في الفقرات السابقة، وسنستخدم لذلك مثالًا جديدًا، ننشئ فيه جدولين، الأول لتخزين اسم الطالب وكنيته، والثاني نخزّن فيه اسم الطالب وعلامته في مادة الرياضيات.
</p>

<p>
	ملاحظة: للاستفادة الكاملة من هذا الدليل، نتمنّى أن تطبِّق عزيزي القارئ الأمثلة بنفسك، كي يحصل على الخبرة العملية إلى جانب الفهم النظري للمحتوى.
</p>

<pre class="ipsCode" id="ips_uid_8183_170">
hsoubguide=# CREATE TABLE student(
hsoubguide(#     id integer PRIMARY KEY,
hsoubguide(#     name character varying(255),
hsoubguide(#     last_name character varying (255)
hsoubguide(# );

CREATE TABLE
</pre>

<pre class="ipsCode" id="ips_uid_8183_172">
hsoubguide=# CREATE TABLE marks(
hsoubguide(#     id integer PRIMARY KEY,
hsoubguide(#     name character varying(255),
hsoubguide(#     marks integer
hsoubguide(# );

CREATE TABLE
</pre>

<pre class="ipsCode" id="ips_uid_8183_174">
hsoubguide=# INSERT INTO student VALUES
hsoubguide-# (1,'mostafa','ayesh'),
hsoubguide-# (2,'ali','badawi'),
hsoubguide-# (3,'samer','khateeb'),
hsoubguide-#  (4,'amer','masre');

INSERT 0 4
</pre>

<pre class="ipsCode" id="ips_uid_8183_176">
hsoubguide=# INSERT INTO marks VALUES
hsoubguide-# (1,'ali',14),
hsoubguide-# (2,'ramez',20),
hsoubguide-# (3,'amer',16),
hsoubguide-# (4,'fadi',18);

INSERT 0 4
</pre>

<p>
	لاحظ أن جدول العلامات لا يحتوي جميع الطلاب المذكورة أسمائهم في جدول الطلاب، وكذلك يحتوى طلابًا غير مذكورين في جدول الطلاب، ولاحظ كذلك أن المعرّف <code>id</code> لطالب ما، ليس من الضروري أن يطابق المعرّف الخاص به في جدول العلامات ! ولذلك فلن نتمكن من ربط الجدولين عن طريق المعرّف الخاص بالسطر.
</p>

<h4>
	الربط الداخلي INNER JOIN
</h4>

<p>
	نستعرض فيه التقاطع بين جدولين دون أي معلومات إضافية:
</p>

<pre class="ipsCode" id="ips_uid_8183_178">
hsoubguide=# SELECT student.name,marks.mark
hsoubguide-# FROM student
hsoubguide-# INNER JOIN marks
hsoubguide-# ON student.name = marks.name;

 name | mark 
------+------
 ali  |   14
 amer |   16
(2 rows)
</pre>

<p>
	يبدو ذلك مشابهًا لما رأيناه في الفقرة السابقة:
</p>

<pre class="ipsCode" id="ips_uid_8183_180">
hsoubguide=# SELECT student.name,marks.mark
hsoubguide-# FROM student,marks
hsoubguide-# WHERE student.name = marks.name;

 name | mark 
------+------
 ali  |   14
 amer |   16
(2 rows)
</pre>

<h4>
	الربط اليساري LEFT JOIN
</h4>

<p>
	في هذا الربط، يتم عرض جميع أسطر الجدول اليساري (أي الجدول المرتبط بالتوجيه <code>FROM</code>) ويتم عرض الأسطر التي تقابلها أو NULL في حال عدم وجود ما يقابلها:
</p>

<pre class="ipsCode" id="ips_uid_8183_182">
hsoubguide=# SELECT student.name,marks.mark
hsoubguide-# FROM student      
hsoubguide-# LEFT JOIN marks
hsoubguide-# ON student.name = marks.name;

  name   | mark 
---------+------
 ali     |   14
 amer    |   16
 samer   |     
 mostafa |     
(4 rows)
</pre>

<h4>
	الربط اليساري الخرجي LEFT OUTER JOIN
</h4>

<p>
	نستخدمه للحصول على الأسطر التي ليس لها ما يقابلها في الجدول اليميني كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT student.name,marks.mark
hsoubguide-# FROM student
hsoubguide-# LEFT JOIN marks
hsoubguide-# ON student.name = marks.name
hsoubguide-# WHERE mark IS NULL;

  name   | mark 
---------+------
 samer   |     
 mostafa |     
(2 rows)
</pre>

<h4>
	الربط اليميني RIGHT JOIN
</h4>

<p>
	كما في الربط اليساري، إلا أن الربط اليميني يظهر جميع أسطر الجدول المرتبط بالتعليمة JOIN (في مثالنا هو الجدول <code>marks</code>)، بينما يظهر الأسطر التي لها مقابل فقط من الجدول الأول (اليساري) أو NULL في حال عدم وجود تقابل، كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT student.name,marks.mark
hsoubguide-# FROM student
hsoubguide-# RIGHT JOIN marks
hsoubguide-# ON student.name = marks.name;

 name | mark 
------+------
 ali  |   14
      |   20
 amer |   16
      |   18
(4 rows)
</pre>

<p>
	من الواضح في المثال السابق أن العبارة <code>SELECT student.name, marks.mark</code> غير مناسبة لهذا النوع من الربط، وذلك لأن العلامات التي ليس لها مقابل لأسماء أصحابها في الجدول <code>names</code> ستظهر بلا أسماء، وهذا أمر غير منطقي في العرض، لذلك سنضيف إضافةً بسيطة لحل هذه المشكلة:
</p>

<pre class="ipsCode" id="ips_uid_8183_185">
hsoubguide=# SELECT COALESCE(student.name,marks.name) AS student_name, hsoubguide=# marks.mark
hsoubguide=# FROM student
hsoubguide=# RIGHT JOIN marks
hsoubguide=# ON student.name = marks.name;

 student_name | mark 
--------------+------
 ali          |   14
 ramez        |   20
 amer         |   16
 fadi         |   18
(4 rows)
</pre>

<p>
	استخدمنا التابع <code>COALESCE</code> الذي يؤدي إلى عرض قيمة السطر من الجدول الأول له إن لم يكن قيمته NULL، وإلا فإنه يعرض قيمة السطر من الجدول الثاني، كما استخدمنا التوجيه AS كي لا يظهر اسم التابع في جدول المخرجات، ويظهر بدلًا منه العبارة <code>student_name</code>.
</p>

<h4>
	الربط اليميني الخارجي RIGHT OUTER JOIN
</h4>

<p>
	هنا يتم استثناء الأسطر التي لها مقابل في الجدول الأول، ونستعرض الأسطر التي ليس لها مقابل من الجدول الأول فقط.
</p>

<pre class="ipsCode" id="ips_uid_8183_187">
hsoubguide=# SELECT COALESCE(student.name,marks.name) AS Student_name, hsoubguide-# marks.mark
hsoubguide-# FROM student
hsoubguide-# RIGHT JOIN marks
hsoubguide-# ON student.name = marks.name
hsoubguide-# WHERE student.name IS NULL;

 student_name | mark 
--------------+------
 ramez        |   20
 fadi         |   18
(2 rows)
</pre>

<h4>
	الربط الخارجي الكامل FULL OUTER JOIN
</h4>

<p>
	يتم فيه إظهار جميع الأسطر من جميع الجداول، سواء كان لها مقابل (عندها تُعرض قيمته) أو لم يكن لها مقابل (يُعرض NULL).
</p>

<pre class="ipsCode" id="ips_uid_8183_189">
hsoubguide=# SELECT COALESCE(student.name,marks.name) AS Student_name, hsoubguide-# marks.mark
hsoubguide-# FROM student
hsoubguide-# FULL OUTER JOIN marks
hsoubguide-# ON student.name = marks.name;

 student_name | mark 
--------------+------
 ali          |   14
 ramez        |   20
 amer         |   16
 fadi         |   18
 samer        |     
 mostafa      |     
(6 rows)
</pre>

<p>
	ما رأيكم لو نضع علامة الصفر لكل من لم يقدم الامتحان؟ نترك لكم تنفيذ الاستعلام التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_191" style="">
<span class="pln">SELECT COALESCE</span><span class="pun">(</span><span class="pln">student</span><span class="pun">.</span><span class="pln">name</span><span class="pun">,</span><span class="pln">marks</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> AS </span><span class="typ">Student_name</span><span class="pun">,</span><span class="pln"> COALESCE</span><span class="pun">(</span><span class="pln">marks</span><span class="pun">.</span><span class="pln">mark</span><span class="pun">,</span><span class="lit">0</span><span class="pun">)</span><span class="pln"> AS mark
FROM student
FULL OUTER JOIN marks
ON student</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> marks</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span></pre>

<h4>
	الربط الخارجي الكامل حصًرا FULL OUTER JOIN-only
</h4>

<p>
	نستخدم هذا الربط لاستعراض جميع الأسطر من الجدولين باستثناء الأسطر المرتبطة ببعضها من الجدولين معًا حسب شرط الربط، فهو بذلك يعطي نتائج الربط الخارجي الكامل، مستثنى منها نتائج الربط الداخلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_8183_193" style="">
<span class="pln">hsoubguide</span><span class="pun">=#</span><span class="pln"> SELECT COALESCE</span><span class="pun">(</span><span class="pln">student</span><span class="pun">.</span><span class="pln">name</span><span class="pun">,</span><span class="pln">marks</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> AS </span><span class="typ">Student_name</span><span class="pun">,</span><span class="pln"> hsoubguide</span><span class="pun">-#</span><span class="pln"> COALESCE</span><span class="pun">(</span><span class="pln">marks</span><span class="pun">.</span><span class="pln">mark</span><span class="pun">,</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
hsoubguide</span><span class="pun">-#</span><span class="pln"> FROM student
hsoubguide</span><span class="pun">-#</span><span class="pln"> FULL OUTER JOIN marks
hsoubguide</span><span class="pun">-#</span><span class="pln"> ON student</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> marks</span><span class="pun">.</span><span class="pln">name
hsoubguide</span><span class="pun">-#</span><span class="pln"> WHERE student</span><span class="pun">.</span><span class="pln">name IS NULL OR marks</span><span class="pun">.</span><span class="pln">name IS NULL</span><span class="pun">;</span><span class="pln">

 student_name </span><span class="pun">|</span><span class="pln"> coalesce 
</span><span class="pun">--------------+----------</span><span class="pln">
 ramez        </span><span class="pun">|</span><span class="pln">       </span><span class="lit">20</span><span class="pln">
 fadi         </span><span class="pun">|</span><span class="pln">       </span><span class="lit">18</span><span class="pln">
 samer        </span><span class="pun">|</span><span class="pln">        </span><span class="lit">0</span><span class="pln">
 mostafa      </span><span class="pun">|</span><span class="pln">        </span><span class="lit">0</span><span class="pln">
</span><span class="pun">(</span><span class="lit">4</span><span class="pln"> rows</span><span class="pun">)</span></pre>

<h2>
	خلاصة
</h2>

<p>
	تعرفنا في هذا الفصل على كيفية إنشاء وتعديل وحذف الجداول، وكذلك تعرفنا على كيفية إدخال البيانات فيها ثم الاستعلام عنها مع ترشيحها والاستفادة من العديد من الأوامر للحصول على المخرجات المطلوبة، كما تعرفنا على عمليات التجميع وعلى طرق ربط الجداول للحصول على النتائج المستخلصة من عدة مصادر.
</p>

<p>
	ومع ازدياد خبرتك في التعامل مع الاستعلامات، وخصوصًا بعد تعرفك على طرق ربط الجداول في هذا الفصل، ربما تكون قد لاحظت أن بعض الاستعلامات قد أصبحت طويلة، وصعبة القراءة، وبعضها يتكرر كثيرًا مع بعض التعديلات، ولذا فقد آن الأوان أن نتعرف إلى العرض View وبعض المزايا المتقدمة في Postgres في الفصل التالي، ليسهل علينا استخدام الاستعلامات الطويلة.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a data-ss1613715533="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%85%D8%B2%D8%A7%D9%8A%D8%A7-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-postgres-r475/" rel="">مزايا متقدمة في Postgres</a>
	</li>
	<li>
		المقال السابق: <a data-ss1613715533="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B5%D8%AF%D9%81%D8%A9-psql-r473/" rel="">أساسيات استخدام صدفة psql</a>
	</li>
	<li>
		النسخة الكاملة من كتاب <a data-ss1613715533="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
	<li>
		<a data-ss1613715533="1" href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D9%82%D8%AF%D9%85-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-sql-r961/" rel="">المرجع المتقدم إلى لغة SQL</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">474</guid><pubDate>Mon, 28 Sep 2020 13:00:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x635;&#x62F;&#x641;&#x629; psql</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B5%D8%AF%D9%81%D8%A9-psql-r473/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_09/3.png.8ed845e36a2ee503ff3526876a17a2f5.png" /></p>

<p>
	سنستخدم صدفة <code>psql</code> طوال الوقت في هذا الدليل، وسنستخدم بعض الرايات فيها أيضًا، لذا سنخصص هذا المقال للتعرف على بعض أهم الأوامر فيها.
</p>

<p>
	صدفة psql هي برنامج الواجهة التفاعلية للاتصال بـ Postgres ولها العديد من الرايات للتحكم بالاتصال منها:
</p>

<ul>
<li>
		الراية <code>‎-h</code> لتحديد المضيف المراد الاتصال به (سواء عن طريق عنوان IP أو عن طريق اسم المضيف إن كان يمكن لخادوم DNS التعرف إليه)
	</li>
	<li>
		الراية <code>‎-U</code> لتحديد اسم المستخدم المراد الاتصال من خلاله
	</li>
	<li>
		الراية <code>‎-p</code> المنفَذ port المراد الاتصال عبره (المنفذ الافتراضي هو 5423)
	</li>
</ul>
<pre class="ipsCode">
psql -h localhost -U username hsoubguide
</pre>

<p>
	كما يمكن استخدام سلسلة نصية كاملة كوسيط واحد، تحتوي محددات الدخول إلى قاعدة البيانات:
</p>

<pre class="ipsCode">
psql "dbname=hsoubguide host=10.11.108.107 user=postgres password=pass123456 port=5432 sslmode=require"
</pre>

<p>
	بعد نجاح الاتصال يمكن البدء بتطبيق الاستعلامات، كما يمكن استخدام أوامر معينة، ويمكن تنفيذ الأمر <code>‎\?‎</code> للحصول على قائمة بجميع الأوامر المتاحة، والتي سنشرح بعضًا من أهمها في الفقرات التالية.
</p>

<h2>
	أوامر استعراض قاعدة البيانات والجداول
</h2>

<h3>
	استعراض جميع قواعد البيانات الموجودة
</h3>

<p>
	استخدم الأمر '‎\l' لاستعراض قائمة بجميع قواعد البيانات المخزّنة:
</p>

<pre class="ipsCode">
hsoubguide=# \l

                                  List of databases
    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
------------+----------+----------+-------------+-------------+-----------------------
 hsoubguide | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | 
 postgres   | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | 
 template0  | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres          +
            |          |          |             |             | postgres=CTc/postgres
 template1  | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres          +
            |          |          |             |             | postgres=CTc/postgres
(4 rows)
</pre>

<h3>
	استعراض جميع قواعد البيانات مع معلومات إضافية
</h3>

<p>
	بإضافة الرمز <code>+</code> إلى الأمر <code>‎\l</code> يمكن عرض قائمة لجميع قواعد البيانات المخزنة مع معلومات إضافية عن كل منها.
</p>

<pre class="ipsCode">
hsoubguide=# \l+

                                                                    List of databases
    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   |  Size   | Tablespace |                Description             

------------+----------+----------+-------------+-------------+-----------------------+---------+------------+----------------------------------------
----
 hsoubguide | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 |                       | 8273 kB | pg_default | 
 postgres   | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 |                       | 8345 kB | pg_default | default administrative connection datab
ase
 template0  | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres          +| 8049 kB | pg_default | unmodifiable empty database
            |          |          |             |             | postgres=CTc/postgres |         |            | 
 template1  | postgres | UTF8     | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres          +| 8049 kB | pg_default | default template for new databases
            |          |          |             |             | postgres=CTc/postgres |         |            | 
(4 rows)
</pre>

<h3>
	استعراض الجداول في قاعدة البيانات
</h3>

<p>
	لاستعراض قائمة بالجداول الموجودة في قاعدة البيانات، نستخدم الأمر <code>‎\dt</code> كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# \dt

                List of relations
 Schema |         Name         | Type  |  Owner   
--------+----------------------+-------+----------
 public | basket_a             | table | postgres
 public | basket_b             | table | postgres
 public | departments          | table | postgres
 public | employee_departments | table | postgres
 public | employees            | table | postgres
 public | marks                | table | postgres
 public | names                | table | postgres
 public | phones               | table | postgres
 public | products             | table | postgres
 public | purchase_items       | table | postgres
 public | purchases            | table | postgres
 public | size_calc            | table | postgres
 public | student              | table | postgres
 public | table1               | table | postgres
 public | table2               | table | postgres
 public | test_explain         | table | postgres
 public | test_table           | table | postgres
 public | users                | table | postgres
 public | users2               | table | postgres
(19 rows)
</pre>

<h3>
	وصف جدول
</h3>

<p>
	لوصف جدول، نستخدم الأمر <code>‎\d</code> مع اسم الجدول كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# \d employees

                      Table "public.employees"
  Column   |         Type          | Collation | Nullable | Default 
-----------+-----------------------+-----------+----------+---------
 id        | integer               |           | not null | 
 last_name | character varying(55) |           |          | 
 salary    | integer               |           |          | 
Indexes:
    "employees_pkey" PRIMARY KEY, btree (id)
</pre>

<h3>
	استعراض الجداول مع بعض المعلومات الإضافية
</h3>

<p>
	بإضافة الرمز <code>+</code> إلى أي أمر من أوامر الاستعراض، فإنها تضيف إلى المخرجات المزيد من المعلومات، فعند إضافة الرمز <code>+</code> إلى الأمر <code>‎\dt</code> يمكننا استعراض المزيد من المعلومات عن الجداول الموجودة في قاعدة البيانات:
</p>

<pre class="ipsCode">
hsoubguide=# \dt+

                              List of relations
 Schema |         Name         | Type  |  Owner   |    Size    | Description 
--------+----------------------+-------+----------+------------+-------------
 public | basket_a             | table | postgres | 8192 bytes | 
 public | basket_b             | table | postgres | 8192 bytes | 
 public | departments          | table | postgres | 8192 bytes | 
 public | employee_departments | table | postgres | 8192 bytes | 
 public | employees            | table | postgres | 8192 bytes | 
 public | marks                | table | postgres | 8192 bytes | 
 public | names                | table | postgres | 8192 bytes | 
 public | phones               | table | postgres | 8192 bytes | 
 public | products             | table | postgres | 16 kB      | 
 public | purchase_items       | table | postgres | 304 kB     | 
 public | purchases            | table | postgres | 96 kB      | 
 public | size_calc            | table | postgres | 0 bytes    | 
 public | student              | table | postgres | 16 kB      | 
 public | table1               | table | postgres | 8192 bytes | 
 public | table2               | table | postgres | 8192 bytes | 
 public | test_explain         | table | postgres | 8192 bytes | 
 public | test_table           | table | postgres | 8192 bytes | 
 public | users                | table | postgres | 16 kB      | 
 public | users2               | table | postgres | 8192 bytes | 
(19 rows)
</pre>

<h3>
	وصف جدول مع معلومات إضافية
</h3>

<p>
	للحصول على المزيد من المعلومات عن جدول ما، يمكننا استخدام الرمز <code>+</code> مع الأمر '‎\d' وبعدها اسم الجدول:
</p>

<pre class="ipsCode">
hsoubguide=# \d+ users

                                                           Table "public.users"
   Column   |           Type           | Collation | Nullable |              Default              | Storage  | Stats target | Description 
------------+--------------------------+-----------+----------+-----------------------------------+----------+--------------+-------------
 id         | integer                  |           | not null | nextval('users_id_seq'::regclass) | plain    |              | 
 email      | character varying(255)   |           |          |                                   | extended |              | 
 password   | character varying(255)   |           |          |                                   | extended |              | 
 details    | hstore                   |           |          |                                   | extended |              | 
 created_at | timestamp with time zone |           |          |                                   | plain    |              | 
 deleted_at | timestamp with time zone |           |          |                                   | plain    |              | 
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "purchases" CONSTRAINT "purchases_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)
Access method: heap
</pre>

<h3>
	استعراض المستخدمين وخصائصهم
</h3>

<p>
	بتنفيذ الأمر <code>‎\dg</code> يمكننا استعراض قائمة الأدوار، وهي قائمة المستخدمين وخصائص كل منهم، كما يلي:
</p>

<pre class="ipsCode">
hsoubguide=# \dg

                                   List of roles
 Role name |                         Attributes                         | Member of 
-----------+------------------------------------------------------------+-----------
 mostafa   |                                                            | {}
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
</pre>

<h2>
	أوامر أخرى أساسية
</h2>

<h3>
	تحرير الاستعلامات في محرر النصوص
</h3>

<p>
	يمكن فتح مخزن الاستعلامات ضمن محرر النصوص الافتراضي (مثل vi أو nano) داخل صدَفَة <code>psql</code> باستخدام الأمر <code>‎\e</code> وهو مفيد لكتابة الاستعلامات الطويلة وتحريرها قبل تنفيذها، وعند فتحه سنجده يحوي آخر استعلام تمت كتابته، مما يسمح لنا بتعديله لإعادة تنفيذه.
</p>

<p>
	كما يمكن استعراض آخر محتويات هذا المخزن باستخدام الأمر <code>‎\p</code>.
</p>

<pre class="ipsCode">
hsoubguide=# SELECT *
hsoubguide-# FROM products
hsoubguide-# LIMIT
hsoubguide-# 1
hsoubguide-# ;
 id |   title    | price |       created_at       | deleted_at |  tags  
----+------------+-------+------------------------+------------+--------
  1 | Dictionary |  9.99 | 2011-01-01 22:00:00+02 |            | {Book}
(1 row)

hsoubguide=# \p
SELECT *
FROM products
LIMIT
1
;
</pre>

<h3>
	تشغيل توقيت الاستعلام
</h3>

<p>
	في الحالة الافتراضية لا يكون توقيت تنفيذ الاستعلام مُتاحًا للعرض، ولكن يمكننا تفعيله من خلال الأمر التالي:
</p>

<pre class="ipsCode">
hsoubguide=# SELECT * FROM products LIMIT 1;
 id |   title    | price |       created_at       | deleted_at |  tags  
----+------------+-------+------------------------+------------+--------
  1 | Dictionary |  9.99 | 2011-01-01 22:00:00+02 |            | {Book}
(1 row)

Time: 0.723 ms
</pre>

<p>
	حيث سيتيح ذلك الأمر إظهار توقيت الاستعلام بالميلي ثانية.
</p>

<h3>
	الحصول على مساعدة بخصوص تعليمات SQL
</h3>

<p>
	يمكن استخدام الأمر '‎\h' يليه اسم التعليمة في SQL لعرض التوثيق الخاص بهذه التعليمة:
</p>

<pre class="ipsCode">
hsoubguide=# \h VACUUM 
Command:     VACUUM
Description: garbage-collect and optionally analyze a database
Syntax:
VACUUM [ ( option [, ...] ) ] [ table_and_columns [, ...] ]
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ table_and_columns [, ...] ]

where option can be one of:

    FULL [ boolean ]
    FREEZE [ boolean ]
    VERBOSE [ boolean ]
    ANALYZE [ boolean ]
    DISABLE_PAGE_SKIPPING [ boolean ]
    SKIP_LOCKED [ boolean ]
    INDEX_CLEANUP [ boolean ]
    TRUNCATE [ boolean ]

and table_and_columns is:

    table_name [ ( column_name [, ...] ) ]

URL: https://www.postgresql.org/docs/12/sql-vacuum.html
</pre>

<h3>
	الخروج من صدفة postgres
</h3>

<p>
	قد تقضي وقتًا طويلًا داخل صدفة psql، ليس حبًّا بها، ولكن لعدم معرفة كيفية الخروج منها، لذلك لا تنسَ أن الأمر <code>‎\q</code> هو الذي يُخرجك من صدفة psql.
</p>

<pre class="ipsCode">
hsoubguide=# \q
bash-4.2$ 
</pre>

<h2>
	الخلاصة
</h2>

<p>
	تعرفنا في هذا الفصل على الأوامر الأكثر استخدامًا في صدفة <code>psql</code>، ولكن لا يزال هناك العديد من الأوامر الأخرى التي يمكنك استعراضها من خلال الأمر <code>‎\?‎</code>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-sql-%D9%81%D9%8A-postgres-r474/" rel="">استخدام أساسيات SQL في Postgres</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-postgres-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%AA%D9%87%D8%A7-%D9%84%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r472/" rel="">تثبيت Postgres والتعرف على أساسيات إدارتها لقواعد البيانات</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">473</guid><pubDate>Sat, 26 Sep 2020 13:06:00 +0000</pubDate></item><item><title>&#x62A;&#x62B;&#x628;&#x64A;&#x62A; Postgres &#x648;&#x627;&#x644;&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x625;&#x62F;&#x627;&#x631;&#x62A;&#x647;&#x627; &#x644;&#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-postgres-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%AA%D9%87%D8%A7-%D9%84%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r472/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_09/2.png.f0c2769c3a8411b00aac3f753c258f31.png" /></p>

<p>
	سنتعرف في هذا الفصل على طريقة تثبيت Postgres على مختلف أنظمة التشغيل، كما سنهيئ قاعدة البيانات للعمل، ونتعلم كيفية إعطاء الصلاحيات للمستخدمين، ثم نبدأ باستخدام قاعدة البيانات الخاصة بنا.
</p>

<h2>
	تثبيت Postgres
</h2>

<p>
	سنذكر في هذه الفقرة الخطوات الأساسية لتثبيت Postgres على أنظمة التشغيل المختلفة.
</p>

<h3>
	التثبيت على لينكس
</h3>

<p>
	تختلف طريقة التثبيت حسب نوع التوزيعة، ولذلك سنذكر طريق التثبيت في التوزيعات الرئيسية.
</p>

<h4>
	التثبيت باستخدام أداة yum (فيدورا، ريد هات، سنتوس، لينكس العلمي …)
</h4>

<p>
	يشرح المثال التالي كيفية تثبيت PostgreSQL 12 على نظام CentOS 7.6 x64:
</p>

<ul>
<li>
		توجه إلى <a data-ss1613715381="1" href="http://yum.postgresql.org/" rel="external nofollow">PostgresSQL Yum Repository</a> واختر إصدار PostgreSQL الذي تريد تثبيته ومن ثم حدد نظام التشغيل الخاص بك وإصداره والمعمارية، في هذا الدليل قمنا باستخدام نظام centos/redhat الإصدار 7، والمعمارية x86_64.
	</li>
	<li>
		نزّل حزمة RPM للمنصة الخاصة بك من الموقع أو نفّذ الأمر التالي من الطرفية Terminal:
	</li>
</ul>
<pre class="ipsCode">
curl -O https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
</pre>

<ul>
<li>
		ثبّت الحزمة كما يلي:
	</li>
</ul>
<pre class="ipsCode">
rpm -ivh pgdg-redhat-repo-latest.noarch.rpm
</pre>

<p>
	ملاحظة: قد تحتاج إلى استخدام <code>sudo</code> لتنفيذ الأمر السابق.
</p>

<ul>
<li>
		ابحث سريعًا لعرض الحزم المتاحة لـ postgres باستخدام الأمر التالي:
	</li>
</ul>
<pre class="ipsCode">
yum list postgres*
</pre>

<p>
	ملاحظة: من الممكن أن يُظهر لك الأمر السابق إصدارات قديمة، لذا تأكد من اختيار النسخة المناسبة التي تريد تثبيتها ومن توافق جميع الحزم في رقم الإصدار للخادوم والعميل وأداة contrib (قد لا يكون ذلك ضروريًّا دومًا ولكن لأخذ الاحتياط من المشاكل التي قد تظهر).
</p>

<ul>
<li>
		ثبّت الحزمة التي تختارها بشكل مشابه للأمر التالي:
	</li>
</ul>
<pre class="ipsCode">
sudo yum install postgresql12 postgresql12-devel postgresql12-libs postgresql12-server postgresql12-contrib
</pre>

<p>
	ثبَّتنا في الأمر السابق عدة حزم مرتبطة بالإصدار 12، ففيها كلا برنامجي الخادم والعميل، وكذلك المكاتب والملفات الرأسية headers، وكذلك المكاتب والإضافات للمساهمين في هذا المشروع مفتوح المصدر، إذ فضّلنا تثبيتها جميعًا كي تتمكن لاحقًا من استخدام أي منها.
</p>

<p>
	نصيحة: في حال ظهور خطأ ما أثناء التثبيت فلا تيأس، ابحث عن الخطأ الذي قد يظهر لك ولا شك أنك ستجد إجابة لسؤالك.
</p>

<h4>
	الأنظمة التي تستخدم apt (أوبنتو، ديبيان، مينت…)
</h4>

<p>
	يمكنك تطبيق الأمر التالي باستخدام <code>apt-get</code>:
</p>

<pre class="ipsCode">
sudo apt-get install postgresql
</pre>

<h4>
	في نظام Arch Linux
</h4>

<p>
	نستخدم الأمر <code>pacman</code> كما يلي:
</p>

<pre class="ipsCode">
sudo pacman -S postgresql
</pre>

<p>
	يمكنك أيضًا الرجوع إلى هذا الفيديو، <a data-ss1613715381="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-r400/" rel="">تثبيت وإعداد قاعدة بيانات PostgreSQL</a> لمزيد من التفاصيل حول عملية التثبيت على أنظمة لينكس.
</p>

<h3>
	التثبيت على نظام ويندوز
</h3>

<p>
	يمكنك استخدام <a data-ss1613715381="1" href="http://www.enterprisedb.com/postgresql-tutorial-resources-training?cid=48" rel="external nofollow">أداة التثبيت لنظام ويندوز</a> (ستحتاج إلى <abbr title="Virtual Private Network | الشبكة الخاصة الافتراضية">VPN</abbr> إذا كنت في سوريا أو السودان، كالعادة)، وبعد أن تحمّل أداة التثبيت اتبع خطوات التثبيت المعروفة.
</p>

<h3>
	التثبيت على نظام ماك
</h3>

<p>
	يمكنك تحميل أداة التثبيت <a data-ss1613715381="1" href="https://www.enterprisedb.com/postgres-tutorials/installation-postgresql-mac-os" rel="external nofollow">لنظام ماك من هذا الرابط</a>. واتباع خطوات التثبيت المعروفة كذلك.
</p>

<h2>
	أساسيات إدارة قواعد بيانات Postgres
</h2>

<p>
	بعد تثبيت Postgres، سنبدأ العمل عليها مباشرةً وإنشاء أول قاعدة بيانات لنا بوساطتها، فهل أنت مستعد؟ لننطلق!
</p>

<h3>
	إنشاء عنقود جديد لقواعد بيانات Postgres
</h3>

<p>
	بعد أن ثبَّت خادم قواعد بيانات Postgres على جهازك، يمكننا الآن البدء باستخدامه، ولكن يجب إنشاء ما يُسمّى بعنقود قواعد البيانات (Database Cluster) أولًا.
</p>

<p>
	عنقود قواعد البيانات هو مجموعة من قواعد البيانات المُدارة عبر خادوم واحد، ولإنشائه علينا إنشاء المسارات التي ستُخزّن فيها بيانات قاعدة البيانات، كما علينا توليد جداول الإعدادات المشتركة وإنشاء قاعدتي البيانات <code>template1</code> و <code>postgres</code>، يتم ذلك بشكل تلقائي كما سنرى بعد قليل، فلا تقلق.
</p>

<p>
	قاعدة البيانات <code>template1</code> تُمثّل قالبًا يتم استخدامه عند إنشاء أي قاعدة بيانات جديدة، أما قاعدة البيانات postgres` فهي قاعدة بيانات افتراضية مصممة ليتم استخدامها من المستخدمين والأدوات والتطبيقات الأخرى.
</p>

<p>
	أولًا نقوم بإنشاء عنقود قاعدة بيانات باستخدام التوجيه <code>initdb</code> ضمن صدفة <code>bash</code> كما يلي:
</p>

<pre class="ipsCode">
sudo /usr/pgsql-12/bin/postgresql-12-setup initdb
</pre>

<p>
	ملحوظة: قمنا بكتابة المسار الكامل لبرمجية الإعداد والتهيئة (postgres-setup ) الخاصة بقواعد بيانات Postgres، ففي حال لم يتم العثور عليها في جهازك، فتأكد من أنك قمت بتثبيتها بطريقة صحيحة، ثم تأكد من أن مسار التثبيت الخاص بها.
</p>

<p>
	يُظهر تنفيذ الأمر السابق المخرجات التالية:
</p>

<pre class="ipsCode">
Initializing database ... OK
</pre>

<p>
	ثم يمكنك بدء وتفعيل PostgreSQL باستخدام الأمرين التاليين:
</p>

<pre class="ipsCode">
sudo systemctl start postgresql-12
sudo systemctl enable postgresql-12
</pre>

<p>
	سنحصل من الأمر السابق على المخرجات التالية:
</p>

<pre class="ipsCode">
Created symlink from /etc/systemd/system/multi-user.target.wants/postgresql-12.service to /usr/lib/systemd/system/postgresql-12.service.
</pre>

<p>
	والآن أصبح خادم قاعدة بيانات PostgreSQL مفعّلًا ويمكننا استخدامه.
</p>

<h3>
	إدارة المستخدمين وإنشاء قاعدة بيانات بدائية
</h3>

<p>
	بعد أن قُمنا بتثبيت قواعد بيانات Postgres وإنشاء عنقود قواعد البيانات، ستكون الخطوة القادمة هي إضافة وإدارة صلاحيات مستخدمي قواعد البيانات المخزنة، حيث يمكن إنشاء مستخدمين والسماح لهم باستخدام قاعدة بيانات محددة دون الأخرى، أو السماح لهم بتنفيذ أوامر معيّنة، ومنعهم من تنفيذ غيرها.
</p>

<p>
	للدخول إلى الصَّدَفَة (shell) الرئيسية الخاصة بPostgres نشغّل برنامج الصدفة بالأمر <code>psql</code>، ولكن علينا أولا الانتقال من حساب المستخدم العادي إلى الحساب <code>postgres</code> وذلك عن طريق الأمر التالي:
</p>

<pre class="ipsCode">
sudo -i -u postgres
</pre>

<p>
	لتتأكد من المستخدم الذي تعمل عليه، استخدم الأمر <code>whoami</code> وقد تظهر لك مخرجات مشابهة لما يلي:
</p>

<pre class="ipsCode">
[mostafa@hsoub ~]$ whoami
mostafa
</pre>

<p>
	وعندما تُبدّل المستخدم نعود وننفّذ الأمر <code>whoami</code> مرة أخرى كما يلي:
</p>

<pre class="ipsCode">
[mayesh@hsoub ~]$ sudo -i -u postgres
[sudo] password for mostafa:

-bash-4.2$ whoami
postgres
</pre>

<p>
	يمكنك الآن الدخول إلى قاعدة البيانات بتنفيذ الأمر <code>psql</code> للبدء بالعمل، ثم سنقوم بإنشاء حساب مستخدم لك، باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6179_7" style="">
<span class="pln">CREATE USER mostafa WITH PASSWORD </span><span class="str">'password'</span><span class="pun">;</span></pre>

<p>
	أُنشئ الآن حساب جديد باسم <code>mostafa</code> وبكلمة مرور <code>password</code>، والخطوة التالية هي إنشاء قاعدة بيانات ومنح المستخدم <code>mostafa</code> صلاحية الوصول لها.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6179_9" style="">
<span class="pln">CREATE DATABASE hsoubguide</span><span class="pun">;</span></pre>

<p>
	أُنشئت الآن قاعدة بيانات اسمها <code>hsoubguide</code>، وسنقوم الآن بمنح الوصول إليها للمستخدم <code>mostafa</code> بالأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6179_11" style="">
<span class="pln">GRANT ALL PRIVILEGES ON DATABASE hsoubguide TO mostafa</span><span class="pun">;</span></pre>

<p>
	مُنح الآن المستخدم <code>mostafa</code> كل الصلاحيات في قاعدة البيانات، حيث أن هنالك عدة أنواع مختلفة من الصلاحيات:
</p>

<pre class="ipsCode" id="ips_uid_6179_13">
SELECT, INSERT, UPDATE, DELETE, RULE, REFERENCES, TRIGGER, CREATE, TEMPORARY, EXECUTE, USAGE.

</pre>

<p>
	أما إذا أردنا منح واحدة منها فقط، فيمكننا تنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6179_15" style="">
<span class="pln">GRANT SELECT ON DATABASE hsoubguide TO mostafa</span><span class="pun">;</span></pre>

<p>
	تسمح <code>GRANT SELECT</code> في هذا الأمر للمستخدم <code>mostafa</code> باستخدام استعلامات <code>SELECT</code> فقط في قاعدة البيانات <code>hsoubguide</code>.
</p>

<h2>
	مثال عن قاعدة بيانات
</h2>

<p>
	قد يكون اهتمام بعض قرّاء هذا الدليل في Postgres منصبًّا على الاستعلامات أكثر من اهتمامهم بتصميم الجداول الخاصة بهم، ولذلك فقد قدّمنا مثالًا عن قاعدة بيانات جاهزة يمكنك تحميلها، لتتمكن من المتابعة مع هذا الدليل دون الحاجة إلى إنشاء الجداول الخاصة بك وإدراج البيانات الواردة ضمنها.
</p>

<h3>
	التثبيت المحلي
</h3>

<p>
	سيتعيّن عليك أوّلًا تنزيل البيانات، ثم تحميلها في قاعدة البيانات.
</p>

<p>
	ملاحظة: تُنفّذ التعليمات التالية في صَدَفة <code>bash</code> المُعتادة، وليس ضمن <code>psql</code>.
</p>

<pre class="ipsCode">
curl -L -O http://cl.ly/173L141n3402/download/example.dump
createdb hsoubguide
pg_restore --no-owner --dbname hsoubguide example.dump
</pre>

<p>
	سنتحدث عن الأمر <code>pg_restore</code> في فقرة لاحقة، وهو مسؤول عن استرجاع قاعدة بيانات من ملف، أما الأمر <code>createdb</code> فهو يُنشئ قاعدة بيانات في Postgres اسمها <code>hsoubguide</code>.
</p>

<h3>
	الاتصال بقاعدة البيانات
</h3>

<p>
	بعد أن أنشأت قاعدة البيانات الخاصة بك <code>hsoubguide</code> فعليك الآن الدخول إلى <code>psql</code> والاتصال بقاعدة البيانات هذه، ويمكنك القيام بذلك بطريقتين:
</p>

<ul>
<li>
		تحديد قاعدة البيانات عن عن طريق التوجيه <code>dbname</code> كما يلي:
	</li>
</ul>
<pre class="ipsCode">
psql --dbname hsoubguide
</pre>

<ul>
<li>
		تحديد قاعدة البيانات من داخل صَدفة <code>psql</code> باستخدام الأمر <code>‎\c</code> كما يلي:
	</li>
</ul>
<pre class="ipsCode">
postgres=# \c hsoubguide
You are now connected to database "hsoubguide" as user "postgres".
</pre>

<h2>
	الخلاصة
</h2>

<p>
	ثبَّتنا في هذا الفصل Postgres، وتعرفنا على كيفية الدخول إلى صدفة <code>psql</code> ثم أنشأنا قاعدة بيانات بدائية، وتعرفنا على كيفية تحديد صلاحية المستخدمين، وسنتعرف في الفصل التالي على بعض الأوامر التي يمكننا تنفيذها داخل صدفة<code>psql</code>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a data-ss1613715381="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B5%D8%AF%D9%81%D8%A9-psql-r473/" rel="">أساسيات استخدام صدفة psql</a>
	</li>
	<li>
		المقال السابق: <a data-ss1613715381="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D8%B9%D9%84%D9%89-postgres-%D9%88%D8%AA%D8%A7%D8%B1%D9%8A%D8%AE%D9%87%D8%A7-r471/" rel="">نظرة عامة على Postgres وتاريخها</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a data-ss1613715381="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
	<li>
		<a data-ss1613715381="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-r400/" rel="">فيديو - تثبيت وإعداد قاعدة بيانات PostgreSQL</a>
	</li>
	<li>
		<a data-ss1613715381="1" href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D8%AA-postgresql-%D9%88%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%87-%D8%B9%D9%84%D9%89-ubuntu-1404-r147/" rel="">كيف تثبت PostgreSQL وتستخدمه على Ubuntu 14.04</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">472</guid><pubDate>Wed, 23 Sep 2020 13:09:00 +0000</pubDate></item><item><title>&#x646;&#x638;&#x631;&#x629; &#x639;&#x627;&#x645;&#x629; &#x639;&#x644;&#x649; Postgres &#x648;&#x62A;&#x627;&#x631;&#x64A;&#x62E;&#x647;&#x627;</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D8%B9%D9%84%D9%89-postgres-%D9%88%D8%AA%D8%A7%D8%B1%D9%8A%D8%AE%D9%87%D8%A7-r471/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_09/1.png.fd8157f3ea08b57ac9629e954bf97e7b.png" /></p>

<p>
	يجدر بنا معرفة بعض المزايا الأساسية لقواعد بيانات Postgres في مقدمة هذا الدليل، وذلك كي يكون واضحًا للقارئ الفوائد التي سيجنيها من التعرف إليها، وتطوير قدراته في التعامل معها.
</p>

<p>
	إن أردت فهم أي موضوع فهمًا جيدًا، فيجب أن تملك معرفة تاريخية جيدة عنه خصوصًا بداية نشأته وسببها وآثار ذلك وحتى الحاضر؛ وبناءً على ذلك، سنطلع أولًا على تاريخ Postgres منذ بداية ظهورها وحتى يومنا هذا.
</p>

<h2>
	لمحة تاريخية
</h2>

<h3>
	الولادة الأولى لقواعد بيانات Postgres
</h3>

<p>
	في عام 1986 نشر Michael Stonebraker ورقة بحثية في جامعة بيركلي، كاليفورنيا بعنوان <a href="https://dsf.berkeley.edu/papers/ERL-M85-95.pdf" rel="external nofollow">the design of Postgres</a> ليعلن ولادة قواعد بيانات Postgres الأولى، ذكر في ورقته أن قاعدة البيانات هذه هي النسخة المحسنة المطورة من قواعد بيانات سابقة لها اسمها INGRES (أُنشئت عام 1975)، ومن هنا جاءت التسمية POST inGRES أي أنها لاحقة لقواعد INGRES، كما ذكر أن أهم أهداف إنشائها هو دعم تخزين أنواع معقدة، والسماح للمستخدمين بإنشاء امتدادات للغة، وغيره من الأهداف المتعلقة بالتخزين والمعالجة، وكانت في ولادتها هذه من أوائل أنظمة قواعد البيانات التي تتيح استخدام أنواع البيانات المتعددة، مع إمكانية شرح العلاقات بين الجداول بشكل كامل، إلا أنها كانت في ذلك الوقت لا تستخدم لغة الاستعلامات المُهيكلة SQL بل لغة مشابهة خاصة بها.
</p>

<p>
	نُشرت بعد ذلك في عام 1989 النسخة الأولى من اللغة لعدد قليل من المستخدمين، تبعتها النسخة 2 عام 1990 مع بعض التحسينات، والنسخة 3 في عام 1991 مع تحسينات في إدارة التخزين وتحسينات على محرك الاستعلام الأساسي، ولكن في عام 1993 بلغت كمية طلبات الدعم والتحسينات حدا تجاوز إمكانيات فريق التطوير في ذلك الوقت،فتم إيقاف المشروع في 30 حزيران 1994.
</p>

<h3>
	الولادة الثانية
</h3>

<p>
	قامت جامعة بيركلي بفتح مصدر Postgres مما سمح لجميع المستخدمين باستخدام الشيفرة البرمجية والتعديل عليها، فقام Andrew Yu و Jolly Chen المتخرجَين من جامعة بيركلي في عام 1994 بجعل Postgres تستخدم لغة الاستعلامات المُهيكلة SQL وتم إنشاء صدفة psql ونُشرت النسخة الجديدة Postgres95 عام 1995 بعد فترة تجريبية قصيرة، وبرخصة مفتوحة المصدر أيضًا.
</p>

<h3>
	ظهور PostgreSQL و postgresql.org
</h3>

<p>
	تم تغيير اسم نظام قواعد البيانات Postgres95 إلى PostgreSQL للدلالة على أنها تستخدم لغة SQL عام 1996 وظهر أخيرًا الموقع postgresql.org في ذلك العام لتظهر النسخة 6 من النظام عام 1997 ثم تبدأ مسيرة التطوير مفتوحة المصدر من خلال المطورين المتطوعين حول العالم تحت مسمّى (مجموعة تطوير Postgres العالمية).
</p>

<h2>
	أهم خصائص قواعد بيانات Postgres
</h2>

<p>
	تتصف قواعد بيانات Postgres بالخصائص التالية:
</p>

<h3>
	أكثر قواعد البيانات تقدّمًا
</h3>

<p>
	إن هذا هو شعار قواعد بيانات Postgres (وليس تقييمًا حقيقيًّا) ولكنها ظلّت ملتزمة به منذ نشأتها عام 1986، وذلك عن طريق التحسين المستمر وإضافة المزايا الجديدة وتلافي الأخطاء القديمة.
</p>

<h3>
	الأسرع نموًّا
</h3>

<p>
	حسب إحصائيات موقع db-engines حيث يعطي علامة score لكل نظام قاعدة بيانات حسب عدة عوامل، منها وتيرة الأسئلة التقنية على المواقع التقنية المشهورة مثل Stack Overflow وكذلك عدد عروض العمل المطلوبة على مواقع شهيرة مثل Indeed، وغيرها من العوامل التي تشير إلى ازدياد الاهتمام وعدد المستخدمين والمحترفين لهذه الأنظمة.
</p>

<p>
	ربما يمكنك أن ترى النمو المتسارع لقواعد بيانات PostgreSQL من الشكل التالي بوضوح:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51338" href="https://academy.hsoub.com/uploads/monthly_2020_09/DB-RANKING.PNG.7a7b6613605669afe201b38d5d1948f9.PNG" rel=""><img alt="DB-RANKING.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="51338" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/DB-RANKING.thumb.PNG.8d8d4af96421b858cbea28459410b378.PNG"></a>
</p>

<p>
	إن ميزة النمو في الأنظمة تعني أن تعلّمك اليوم لقواعد البيانات PostgreSQL هو استثمار صحيح للمستقبل سواء للعمل في وظيفة تطلب منك خبرة Postgres أو لكي تستخدمها في موقعك الخاص.
</p>

<h3>
	نموذج تخزين البيانات فيها من النوع SQL
</h3>

<p>
	نقصد في هذه الفقرة تثبيت فكرة كون Postgres من النوع SQL وليس NoSQL، وذلك يعني باختصار أن قواعد بيانات Postgres تخزّن البيانات ضمن جداول لها قوالب معدّة مسبقًا، ويمكنك الاطلاع على مقال <a href="%5Bhttps://academy.hsoub.com/devops/servers/databases/%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D9%81%D8%B1%D9%88%D9%82%D8%A7%D8%AA-%D8%A8%D9%8A%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-sql-%D9%88%D9%86%D8%B8%D9%8A%D8%B1%D8%A7%D8%AA%D9%87%D8%A7-nosql-r71/%5D(https://academy.hsoub.com/devops/servers/databases/%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D9%81%D8%B1%D9%88%D9%82%D8%A7%D8%AA-%D8%A8%D9%8A%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-sql-%D9%88%D9%86%D8%B8%D9%8A%D8%B1%D8%A7%D8%AA%D9%87%D8%A7-nosql-r71/)" rel="">شرح الفروقات بين قواعد بيانات SQL ونظيراتها NoSQL</a> للمزيد من المعلومات عن هذا الموضوع.
</p>

<h3>
	تسمح بأنواع بيانات غير مُهيكلة
</h3>

<p>
	قام المبرمجون المشاركون في تطوير قواعد بيانات Postgres بإضافة النوع JSONB الذي يسمح بتخزين كائنات JSON ضمن الجداول، وبذلك تكون قد استحوذت أيضًا على بعض مزايا قواعد بيانات NoSQL رغم كونها قواعد بيانات مهيكلة.
</p>

<h3>
	مفتوحة المصدر
</h3>

<p>
	يمكن تحميل الشيفرة المصدرية لقواعد بيانات Postgres من <a href="https://github.com/postgres/postgres" rel="external nofollow">المستودع الرسمي على موقع github</a> وهي مكتوبة بلغة C، ولكونها مفتوحة المصدر فيمكن للمبرمج فهم آلية العمل الدقيقة لأي تفصيل يبحث عنه، كما يمكنه تحسينه وتطويره ونشره إن أراد ليكون جزءًا من نسخة مستقبلية من قواعد البيانات Postgres، أو ليكون رقعة Patch لنسخة حالية موجودة.
</p>

<h3>
	قابلة للتوسيع
</h3>

<p>
	ذكرنا قبل قليل أنه يمكن تعديل الشيفرة المصدرية لقواعد بيانات Postgres، ولكننا الآن نتحدث عن إمكانية كتابة امتدادات لها، دون المساس بالشيفرة المصدرية أو الحاجة إلى الاطلاع عليها، وهذا يعني أنه بإمكانك كتابة توابع جديدة خاصة بك وربطها بقاعدة البيانات لاستخدامها لاحقا.
</p>

<h3>
	ذات توثيق تفصيلي
</h3>

<p>
	يمكنك الاطلاع على <a href="https://www.postgresql.org/docs/current/" rel="external nofollow">توثيق قواعد بيانات Postgres</a> الذي يشرح كافة التفاصيل مع تقديم أمثلة لكل منها ودليل تدريبي للمبتدئين كذلك، وهو يشمل كافة المواضيع المتعلقة بها بدءًا من أبسط عبارات SQL وانتهاءً بكيفية تمديد اللغة وكتابة شيفرات برمجية لتحسينها وتطويرها.
</p>

<h2>
	متى تختار Postgres؟
</h2>

<p>
	للإجابة على هذا السؤال، من المهم التفريق بين المبتدئ والمتوسط، فبالنسبة للمبتدئ، فإن أهم ما يحتاجه للبدء هو سهولة التثبيت وسهولة التعلم ووجود المصادر العربية، وهذا من أهم ميزات Postgres بالنسبة للمبرمج العربي المبتدئ فأكاديمية حسوب تعتني بإغناء المحتوى العربي الخاص بها نظرًا لسرعة نموها وانتشارها المستمر.
</p>

<p>
	أما لمن تجاوز الأساسيات وبدأ يهتم بالخطوة التالية، فإنك الآن قادر على كتابة استعلامات SQL بمهارة، وترغب الآن بتحسين كفاءة الاستعلامات، أو زيادة موثوقية قاعدة البيانات لديك لمنع حدوث ضياع للبيانات أو لتسريع عمل قاعدة البيانات أو تخفيض حجم قاعدة البيانات في الذاكرة، وفي هذه الحالة فإن Postgres تتيح لك إدارة سهلة وفعالة للأداء، للذاكرة ولكتابة استعلامات أوضح وأكثر سرعة في التنفيذ، كما أن الأدوات المرفقة مع قاعدة بيانات Postgres سهلة التثبيت والاستخدام، ستكون بداية قوية لك في إدارة قواعد البيانات.
</p>

<p>
	في حال كنت متقدمًا في استخدام قواعد البيانات، فقد تضطر لإنشاء توابع خاصة بك، أو لتعديل أمور جوهرية في محرك قواعد البيانات نفسه لعمل تعديلات مخصصة لتطبيقك أو لمنتج مميز له مزايا خاصة، فهناك العديد من الشركات اعتمدت على Postgres لتطوير قواعد بياناتها الخاصة مثل Sun وRed Hat وAmazon وYahoo و<a href="https://wiki.postgresql.org/wiki/PostgreSQL_derived_databases" rel="external nofollow">القائمة تطول</a>.
</p>

<h2>
	نظرة عامة على نموذج الخادم/عميل في Postgres
</h2>

<p>
	من المفيد قبل البدء التعرف على بنية نظام قواعد بيانات PostgreSQL وفهم كيفية ارتباط أجزاء النظام ببعضها.
</p>

<p>
	تستخدم PostgreSQL نموذج خادم/عميل (client/server) بحيث تتكون الجلسة من الجزئين التاليين:
</p>

<ul>
<li>
		عملية الخادم، اسمها <code>postgres</code> تدير ملفات قاعدة البيانات، وتستقبل اتصالات التطبيقات من طرف العميل، وتنفّذ العمليات التي يطلبها العميل على قاعدة البيانات.
	</li>
	<li>
		تطبيق العميل الخاص بالمستخدم، (الواجهة الأمامية)، هو التطبيق الذي يريد القيام بعمليات على قاعدة البيانات، ويمكن أن يكون بأشكال عديدة: واجهة سطر أوامر <code>psql</code>، تطبيق رسومي، خادوم ويب أو أداة صيانة قواعد بيانات ما، بعض هذه الأدوات تأتي مرفقة مع نظام قواعد بيانات PostgreSQL كما يمكن أن تكون من تطوير المستخدمين.
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="51337" href="https://academy.hsoub.com/uploads/monthly_2020_09/client_server.PNG.93e06ed7d0081e07c4bab086425aed8a.PNG" rel=""><img alt="client_server.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="51337" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/client_server.thumb.PNG.e8fb55e7bf6c737dfa63d1870ebc0ba6.PNG"></a>
</p>

<p>
	يتواصل البرنامج العميل مع الخادم عن طريق الشبكة بواسطة بروتوكول TCP/IP كما هو حال تطبيقات الخادم/عميل المعتادة، وهذا يعني أن العميل لا يمكنه الوصول إلى الملفات الموجودة على الجهاز الخاص بالخادم إذا كان كل منهما على جهاز مختلف.
</p>

<p>
	يمكن للخادم استقبال عدة اتصالات بآن واحد من العملاء، حيث تقوم العملية الأساسية للخادم <code>postgres</code> بعمل <code>fork</code> بحيث تتفرع لعدة عمليات كل منها يعالج أحد هذه الاتصالات لتبقى العملية الأساسية متحررة طوال الوقت من الطلبات وتنتظر استقبال الطلبات الجديدة، وعند انتهاء تنفيذ الطلب يتم تحرير العملية المرتبطة بها وإزالتها (طبعا يبقى كل ذلك غير مرئي للعميل).
</p>

<h2>
	الخلاصة
</h2>

<p>
	أخذت في هذا المقال لمحة تاريخية عن Postgres وتعرفت على خصائصها والمزايا التي تقدمها كما أجبنا عن سؤال مهم يُسأَل دومًا قبل استخدام أي شيء وهو متى نستخدم Postgres ثم ألقينا نظرة على نموذج الاتصال الذي تتبعه Postgres. حان الآن وقت بدء العمل مع Postgres.
</p>

<p>
	 
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-postgres-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%AA%D9%87%D8%A7-%D9%84%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r472/" rel="">تثبيت Postgres والتعرف على أساسيات إدارتها لقواعد البيانات</a>
	</li>
	<li>
		النسخة الكاملة من كتاب: <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">471</guid><pubDate>Thu, 17 Sep 2020 13:00:00 +0000</pubDate></item><item><title>[&#x641;&#x64A;&#x62F;&#x64A;&#x648;] &#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x648;&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x642;&#x627;&#x639;&#x62F;&#x629; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; PostgreSQL</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-r400/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_03/PostgreSQL.png.9093b6cae4c4e4e9f39e6cb61aaac614.png" /></p>

<iframe width="560" height="400" src="https://www.youtube.com/embed/eZlLwNAHwsk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>
	نشرح طريقة تثبيت وإعداد خادم PostgreSQL على نظام أوبنتو 18.04. مع إعداد كلمة مرور للمستخدم root؛ وإنشاء قاعدة بيانات جديدة ومستخدم جديد لديه الصلاحيات الكاملة عليها.<br>
	قسم PostgreSQL في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها:<br><a href="https://academy.hsoub.com/devops/servers/databases/postgresql/" ipsnoembed="true" rel="">https://academy.hsoub.com/devops/servers/databases/postgresql/</a>
</p>

<p>
	نوفر توثيقًا كاملًا لجميع تعليمات SQL على موسوعة حسوب:
</p>

<p>
	<a href="https://wiki.hsoub.com/SQL" rel="external">https://wiki.hsoub.com/SQL</a>
</p>
]]></description><guid isPermaLink="false">400</guid><pubDate>Tue, 26 Mar 2019 11:15:42 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; PostgreSQL &#x645;&#x639; &#x62A;&#x637;&#x628;&#x64A;&#x642; Django &#x639;&#x644;&#x649; &#x62E;&#x627;&#x62F;&#x645; &#x64A;&#x639;&#x645;&#x644; &#x628;&#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 16.04</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-postgresql-%D9%85%D8%B9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-django-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D9%8A%D8%B9%D9%85%D9%84-%D8%A8%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r381/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_01/5a68c59c3ab11_27-2(2).png.6d84190940247b9bf936115535282783.png" /></p>

<p>
	Django هو إطار عمل مرن يستخدم ﻹنشاء تطبيقات بلغة بايثون، وهذه التطبيقات مُجهزة تلقائيًا لتخزين البيانات في ملف قاعدة بيانات SQLite خفيف ويعمل بشكل جيد في الاستعمالات العادية والصغيرة، لكن استخدام نظام إدارة قواعد بيانات تقليدي سيطوِّر أداء التطبيق تحت ضغط زيادة المستخدمين أو زيادة حجم البيانات. وسنستعرض في هذا الدرس كيفية تثبيت وتهيئة PostgreSQL لاستخدامها مع تطبيقات Django، وسنثبّت الحزم اللازمة وننشئ اعتماديات قاعدة البيانات للتطبيق، ثم نبدأ مشروع Django جديد ونجهّزه ليستخدم هذه اﻹعدادات.
</p>

<h3>
	المتطلبات
</h3>

<p>
	خادم يعمل بتوزيعة أوبنتو 16.04 مع مستخدم -غير الجذر- له صلاحية sudo.
</p>

<h2 id="تثبيت-الحزم-من-مستودعات-أوبنتو">
	تثبيت الحزم من مستودعات أوبنتو
</h2>

<p>
	سنثبّت أولًا pip -مدير حزم بايثون- لتثبيت وإدارة حزم بايثون، وسنثبّت أيضًا برنامج قاعدة البيانات والمكتبات اللازمة للتفاعل معهم. يحتاج إصدار بايثون 2 و3 إلى حزم مختلفة قليلًا عن بعضها، لذا اختر الأوامر التي تتوافق مع إصدار بايثون لديك.
</p>

<ul>
<li>
		انسخ الأوامر التالية إن كنت تستخدم بايثون 2:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
$ sudo apt-get update
$ sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib</pre>

<ul>
<li>
		وهذه إن كنت تستخدم بايثون 3:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>$ sudo apt-get update
$ sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib
</code></pre>

<p>
	يمكننا الآن إنشاء قاعدة البيانات بما أننا أنهينا تثبيت هذه الحِزّم.
</p>

<h2 id="إنشاء-قاعدة-البيانات-والمستخدم-الخاص-بها">
	إنشاء قاعدة البيانات والمستخدم الخاص بها
</h2>

<p>
	يستخدم Postgres نظام توثيق للاتصالات المحلية اسمه "توثيق النِّدّ Peer Authentication”. وهذا يعني أنه إذا كان اسم المستخدم في نظام التشغيل يطابق اسم Postgres صالح، فإن هذا المستخدم يمكنه الولوج دون الحاجة إلى توثيق. وقد أُنشئ مستخدم للنظام اسمه postgres ليتوافق مع مستخدم postgres المدير لنظام PostgreSQL، وسنحتاج هذا المستخدم لتنفيذ مهام إدارية، ويمكننا أيضًا أن نستخدم sudo وندخل اسم المستخدم من خلال لاحقة u-.
</p>

<ul>
<li>
		سجل الدخول إلى جلسة Postgres تفاعلية عبر كتابة الأمر التالي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>$ sudo -u postgres psql
</code></pre>

<p>
	وسننشئ أولًا قاعدة بيانات لمشروع Django، ويجب أن يكون لكل مشروع قاعدة البيانات الخاصة به للدواعي الأمنية. وسنسمّي قاعدة البيانات في هذا المقال باسم <code>myproject</code>، لكن من اﻷفضل طبعًا أن تختار اسمًا يصلح لمشروع حقيقي.<br><strong>ملاحظة:</strong> تذكر أن تنهي كل الأوامر في محث SQL بفاصلة منقوطة ;
</p>

<pre class="ipsCode" id="ips_uid_6355_7">
<code>postgres=# CREATE DATABASE myproject;
</code></pre>

<ul>
<li>
		أنشئ مستخدمًا لقاعدة البيانات، وسنستعمله للاتصال بقاعدة البيانات والتفاعل معها، وﻻ تنسَ أن تستبدل <code>myprojectuser</code> باسم قاعدة البيانات الذي اخترته، وتغيّر <code>password</code> بكلمة سر قوية:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>postgres=# CREATE USER myprojectuser WITH PASSWORD 'password';
</code></pre>

<p>
	واﻵن سنعدّل بعض معاملات الاتصال لهذا المستخدم لتسريع عمليات قاعدة البيانات بما أن القيم الصحيحة لن تضطر إلى أن تمر بعمليات استعلام وضبط في كل مرة يحدث اتصال.
</p>

<ul>
<li>
		فسنضبط الترميز الافتراضي على UTF-8 وهو الترميز الافتراضي الذي يتوقعه Django.
	</li>
	<li>
		وسنضبط النظام الافتراضي لعزل التعاملات "default transactio isolation scheme” على <code>read committed</code>، وذلك لحظر القراءة من التعاملات غير المرسلة "uncommitted transactions”.
	</li>
	<li>
		وأخيرًا، سنضبط المنطقة الزمنية الافتراضية لمشاريع Django على UTC. وهذه الإعدادات <a href="https://docs.djangoproject.com/en/1.9/ref/databases/#optimizing-postgresql-s-configuration" rel="external nofollow">يُنصح بها في التوثيق الرسمي لمشروع Django</a>، دعنا نكتب ذلك الآن:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>postgres=# ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
postgres=# ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
postgres=# ALTER ROLE myprojectuser SET timezone TO 'UTC';
</code></pre>

<ul>
<li>
		وكل ما نحتاجه الآن هو إعطاء مستخدم قاعدة البيانات صلاحيات الوصول لقاعدة البيانات التي أنشأناها للتو:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>postgres=# GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
</code></pre>

<ul>
<li>
		اخرج الآن من محث SQL:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>postgres=# \q
</code></pre>

<h2 id="تثبيت-django-في-بيئة-افتراضية">
	تثبيت Django في بيئة افتراضية
</h2>

<p>
	يمكننا تثبيت Django الآن بما أن قاعدة بياناتنا قد صارت جاهزة، وسنثبته وكل اعتمادياته داخل بيئة بايثون افتراضية لتحقيق مرونة أكثر، وستتيح لنا حزمة <code>virtualenv</code> إنشاء هذه البيئات بسهولة.
</p>

<ul>
<li>
		اكتب هذا السطر في الطرفية لتثبيت <code>virtualenv</code> إن كنت تستخدم Python 2:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>$ sudo pip install virtualenv
</code></pre>

<ul>
<li>
		وهذا إن كنت تستخدم Python 3:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>$ sudo pip3 install virtualenv
</code></pre>

<ul>
<li>
		أنشئ مجلدًا جديدًا باسم مشروعك (استبدل اسم مشروعك بـ <code>myproject</code> الذي اخترناه هنا لغرض المثال فقط)، ثم انتقل داخله:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>$ mkdir ~/myproject
$ cd ~/myproject
</code></pre>

<ul>
<li>
		اكتب السطر التالي لإنشاء بيئة افتراضية لتخزين متطلبات بايثون لمشروع Django الخاص بنا:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>$ virtualenv myprojectenv
</code></pre>

<p>
	وذلك سيثبّت نسخة محلية من بايثون وأمر pip محلي داخل مجلد اسمه <code>myprojectenv</code> داخل مجلد مشروعك.
</p>

<ul>
<li>
		نحتاج الآن إلى تفعيل البيئة الافتراضية قبل تثبيت البرامج داخلها، ويمكننا فعل ذلك عبر الأمر التالي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>$ source myprojectenv/bin/activate
</code></pre>

<p>
	سيتغير المحثّ الآن ليشير إلى أنك تعمل الآن داخل بيئة افتراضية وسيبدو شبيهًا بهذا:
</p>

<pre class="ipsCode" id="ips_uid_6355_7">
<code>(myprojectenv)user@host:~/myproject$
</code></pre>

<ul>
<li>
		ويمكننا الآن تثبيت Django باستخدام pip، ثم سنثبت psycopg2 التي ستتيح لنا استخدام قاعدة البيانات التي أعددناها:
	</li>
</ul>
<p>
	(ﻻحظ أنه يجب استخدام أمر pip وليس pip3 داخل البيئة الافتراضية بغض النظر عن نسخة بايثون التي لديك)
</p>

<pre class="ipsCode" id="ips_uid_6355_7">
<code>(venv) $ pip install django psycopg2
</code></pre>

<ul>
<li>
		يمكننا الآن أن نبدأ مشروع Django داخل مجلد المشروع (<code>myproject</code> في حالتنا)، وسينشئ هذا مجلدًا فرعيًا بنفس اسم مجلد المشروع ليحتوي الشفرة البرمجية، إضافة إلى مخطوطة إدارية "management script” داخل المجلد الحالي، ﻻ تنس إضافة النقطة التي في آخر الأمر التالي كي ﻻ يُنشأ مستوى فرعي جديد في المجلد:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>(venv) $ django-admin.py startproject myproject .
</code></pre>

<p>
	سنضبط الآن مشروعنا ليستخدم قاعدة البيانات التي أنشأناها،
</p>

<ul>
<li>
		افتح ملف الإعدادات الرئيسية لمشروع Django الموجود في المجلد الفرعي للمشروع:
	</li>
</ul>
<p>
	(ملاحظة: استبدل مشروعك بـ<code>myproject</code>)
</p>

<pre class="ipsCode" id="ips_uid_6355_7">
<code>(myprojectenv) $ nano ~/myproject/myproject/settings.py
</code></pre>

<p>
	ستجد قسم DATABASE في نهاية الملف، وسيبدو مشابهًا لهذا:
</p>

<pre class="ipsCode" id="ips_uid_6355_7">
<code>. . .

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

. . .
</code></pre>

<p>
	هذا القسم يستخدم SQLite كقاعدة بيانات، ونريد تعديل هذه لكي يستخدم قاعدة بيانات PostgreSQL الخاصة بنا.
</p>

<ul>
<li>
		فأول ما نفعله هو تغيير المحرك كي يستخدم محوّل <code>postgresql_psycopg2</code> بدلًا من <code>sqlite3</code>، ثم نستخدم اسم قاعدة بياناتنا (myproject في مثالنا) في خانة NAME، ونضيف بعض بيانات تسجيل الدخول مثل اسم المستخدم وكلمة المرور، والمضيف الذي سيتصل به، وسنضيف خانة Port ونتركها فارغة كي يتم اختيار المنفذ الافتراضي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>. . .

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
    }
}

. . .
</code></pre>

<p>
	وبما أننا في الملف، فقد تحتاج إلى تعديل تعليمة <code>ALLOWED_HOSTS</code> التي تحدد قائمة عناوين أو أسماء نطاقات مسموح باستخدامها للاتصال مع مشروع Django، فأي طلب اتصال بترويسة HOST ليس في هذه القائمة سيتم اعتراضه. ويتطلّب Django أن تعدّل هذه التعليمة كي يمنع فئة معينة من الاختراقات الأمنية. ولتعديل هذه التعليمة، أدخل -بين قوسين مربعيْن- عناوين IP أو أسماء النطاقات المرتبطة بخادم Django الخاص بك ويجب أن يكون كل نطاق أو عنوان IP داخل علامتي تنصيص مفردتيْن، وتفصل بين كل واحد منهم فاصلة ",”. وإن رغبت في الاستجابة لطلبات من نطاق ما إضافة إلى النطاقات الفرعية له فضع نقطة قبله أثناء كتابته.
</p>

<ul>
<li>
		إليك أمثلة تعرض لك الطريقة الصحيحة لصيغة هذه التعليمة، استبدل النطاقات وعناوين الـ IP التي تريدها بالأمثلة الموجودة هنا:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>. . .
# أبسط حالة: اكتب العناوين وأسماء النطاقات لخادم چانجو الخاص بك  
# ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']
# ابدأ اسم النطاق بنقطة للاستجابة له ولأي نطاق فرعي
# ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .]
</code></pre>

<p>
	واﻵن احفظ الملف وأغلقه.
</p>

<h2 id="نقل-قاعدة-البيانات-واختبار-مشروعك">
	نقل قاعدة البيانات واختبار مشروعك
</h2>

<p>
	يمكننا الآن نقل هياكل البيانات -بما أننا أنهينا ضبط إعدادات Django- إلى قاعدة بياناتنا واختبار الخادم.
</p>

<ul>
<li>
		سنبدأ بإنشاء هيكل ابتدائي لقاعدة البيانات بما أننا ﻻ نملك أي بيانات حقيقية بعد:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>(myprojectenv) $ cd ~/myproject
(myprojectenv) $ python manage.py makemigrations
(myprojectenv) $ python manage.py migrate
</code></pre>

<ul>
<li>
		أنشئ حسابًا إداريًا:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>(myprojectenv) $ python manage.py createsuperuser
</code></pre>

<p>
	وسيطلب منك النظام اختيار اسم لمستخدم هذا الحساب وعنوان بريد وكلمة مرور له.<br>
	انتبه هنا إلى أنه يجب فتح المنفذ الذي سنستخدمه في الجدار الناري كي نتمكن من الدخول إلى خادم تطوير Django،
</p>

<ul>
<li>
		إن كنت تستخدم UFW فإن فتح المنفذ المناسب يتم بكتابة هذا الأمر:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>(myprojectenv) $ sudo ufw allow 8000
</code></pre>

<ul>
<li>
		وبمجرد أن تفتح المنفذ يمكنك اختبار عمل قاعدة البيانات بتشغيل خادم Django:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6355_7">
<code>http://server_domain_or_IP:8000
</code></pre>

<p>
	يجب أن ترى صفحة index الافتراضية:
</p>

<p style="text-align: center;">
	<img alt="django_index.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26703" data-unique="02s5byqjx" src="https://academy.hsoub.com/uploads/monthly_2018_01/django_index.png.f42f35170480918b56e6344901d4349b.png"></p>

<ul>
<li>
		ضع<code>admin</code>/ في نهاية الرابط، يجب أن يدخلك هذا لشاشة تسجيل الدخول إلى واجهة التحكم:
	</li>
</ul>
<p style="text-align: center;">
	<img alt="admin_login.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26702" data-unique="h5x65a5oo" src="https://academy.hsoub.com/uploads/monthly_2018_01/admin_login.png.36b2d8882f617b81a7c0aafa0be6d464.png"></p>

<ul>
<li>
		أدخل اسم المستخدم وكلمة المرور اللتان أنشأتهما قبل قليل باستخدام <code>createsuperuser</code>، فتدخل إلى لوحة التحكم:
	</li>
</ul>
<p style="text-align: center;">
	<img alt="admin_interface.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26701" data-unique="jwjtm8mhm" src="https://academy.hsoub.com/uploads/monthly_2018_01/admin_interface.png.340664f97ca2373db7995fc68a83831d.png"></p>

<p>
	وبدخولنا للوحة التحكم نكون قد تأكدنا أن قاعدة البيانات قد خزّنت معلومات حساب المستخدم الخاص بنا ويمكننا الدخول إليه دون مشاكل. يمكنك الآن إيقاف الخادم حين تنتهي من تحققك بالضغط على ctrl-c داخل شاشة الطرفية.
</p>

<h2 id="الخلاصة">
	الخلاصة
</h2>

<p>
	قد عرضنا في هذا الدليل كيفية تثبيت وإعداد PostgreSQL كقاعدة بيانات في النهاية الخلفية لمشروع Django، إذ تستفيد أغلب المشاريع من استخدام نظم إدارة متطورة لقواعد البيانات، رغم أن SQLite تتعامل بشكل جيد أثناء تطوير المشروع وأثناء الاستخدام الخفيف له.
</p>

<p>
	ترجمة -بتصرف- لمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-django-application-on-ubuntu-16-04" rel="external nofollow">How To Use PostgreSQL with your Django Application on Ubuntu 16.04</a> لصاحبه Justin Ellingwood.
</p>
]]></description><guid isPermaLink="false">381</guid><pubDate>Sat, 27 Jan 2018 13:02:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x651;&#x629; &#x62D;&#x645;&#x627;&#x64A;&#x629; PostgreSQL &#x645;&#x646; &#x627;&#x644;&#x647;&#x62C;&#x645;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x64F;&#x624;&#x62A;&#x645;&#x62A;&#x629; (Automated Attacks)</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-postgresql-%D9%85%D9%86-%D8%A7%D9%84%D9%87%D8%AC%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%A4%D8%AA%D9%85%D8%AA%D8%A9-automated-attacks-r380/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_01/25-2.png.9c34280a208d4c36a3764eab08f2199c.png" /></p>

<h1 id="كيفيّة-حماية-postgresql-من-الهجمات-المُؤتمتة-automated-attacks-">
	مقدّمة
</h1>

<p>
	من الممكن أن ننخدع بفكرة أنّ الخوادم لن تُهاجَم ما دام الخادوم جديدا، زواره قلائل أو أنّ المخترقين لن يستفيدوا شيئا من اختراقه. لكنّ العديد من الهجمات تكون مُؤتمتة وتُصمَّمُ خصيصا للبحث عن الأخطاء الشّائعة التي تُرتَكب عند ضبط الخادوم. تقوم هذه البرمجيات بفحص الشبكات لاكتشاف الخوادم فقط، ولا تكثرت بمحتواها.<br>
	تمكين الاتصالات الخارجيّة من أكثر الحالات الشّائعة التي قد تُؤدي إلى وصول غير مُصرّح إلى قاعدة بيانات PostgreSQL. يُمكن أن يحدث هذا لأنّ الإعدادات تسمح للبرمجيات باستكشاف الخوادم الضعيفة بسهولة.<br>
	في هذا الدّرس، سنلقي نظرة على كيفيّة تقليل خطر الوصول غير المُصرّح الذي يطرحه تفعيل الاتّصالات البعيدة (remote connections). ورغم أنّ هذه خطوة أولى بغاية الأهميّة، وبما أنّ الخوادم قد تتعرّض للاختراق بطرق أخرى، فإنّنا ننصح باتّخاذ إجراءات إضافيّة لحماية بياناتك، والتي يُمكنك أن تجدها في جزء "إجراءات إضافيّة لمزيد من الحماية” من هذا الدّرس.
</p>

<h2 id="الوضعيّة">
	الوضعيّة
</h2>

<p>
	لفهم الخطر الذي نحاول تخفيفه، تخيّل الخادوم على أنّه متجر صغير. إن كان المتجر يُنصت (listening) على أي منفذ (port)، فهذا يُكافئ قلب لافتة تُشير إلى أنّ المتجر "مفتوح”. أي أنّ الخادوم يكون مرئيّا على الشّبكة، ما يُمكّن البرمجيات المؤتمتة من إيجاده.<br>
	يُمكننا أن نتخيّل بأنّ كلّ منفذ عبارة عن طريقة للدّخول إلى المتجر، مثل باب أو نافذة مثلا. يُمكن لهذه المداخل أن تكون مفتوحة، مُغلقة، مُقفلة أو مُعطّلة حسب حالة البرمجيّة التي تقوم بالإنصات، لكنّ الإنصات على واجهة عامّة يعني بأنّ البرمجيات الخبيثة تستطيع مُحاولة الدّخول. فمثلا، يُمكن أن تُحاول البرمجيّة استعمال كلمة مرور افتراضيّة على أمل أنّها لم تتغيّر. يُمكن لها كذلك استغلال ثغرات أمنيّة موجودة في البرنامج الذي يُنصِتُ على أمل أنّها لم تُصلَح بعد. يُمكن مُحاولة العديد من الأساليب، إن تمكّنت البرمجيّة الخبيثة من إيجاد نقطة ضعف وقامت باستغلالها، فهذا يعني بأنّ الوصول إلى الخادوم سيتمّ بنجاح وسيتمكّن الهجوم من تخليف خسائر كبيرة.<br>
	إن قُمنا بتقييد عفريت (daemon) معيّن مثل <code>postgresql</code> ليُنصت محليّا فقط، فهذا مُشابه لمحو الباب الذي يوصل إلى الخارج. ولن يُمكن مُحاولة أي شيء آخر للوصول إلى Postgres. تحمي الجدران النّاريّة (Firewalls) وشبكات <abbr title="Virtual Private Network | الشبكة الخاصة الافتراضية">VPN</abbr> بطريقة مُشابهة. في هذا الدّرس، سنُركّز على حذف الباب العمومي الذي يوصل إلى PostgreSQL. لحماية العفريت أو البيانات أثناء نقلها أو تخزينها، انظر فقرة "إجراءات إضافيّة لمزيد من الحماية” من هذا الدّرس.
</p>

<h2 id="المُتطلّبات">
	المُتطلّبات
</h2>

<p>
	سنستعمل في هذا الدّرس خادومي Ubuntu، الأول لمُضيف قاعدة البيانات والآخر ليعمل كعميل يتّصل بالمُضيف عن بُعد. يجب على كلّ خادوم أن يُجهَّز بمُستخدم <code>sudo</code> وجدار ناري مُفعّل. يُمكنك الاستعانة بدرس <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/" rel="">الإعداد البدئي لخادوم Ubuntu</a>.
</p>

<h3 id="مُضيف-قاعدة-البيانات-postgresql-ubuntu-16.04">
	مُضيف قاعدة البيانات PostgreSQL (Ubuntu 16.04)
</h3>

<p>
	إن لم تقم بتنصيب PostgreSQL بعد، يُمكنك القيام بذلك باستخدام الأوامر التّاليّة:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib</pre>

<h3 id="آلة-العميل-ubuntu-16.04">
	آلة العميل (Ubuntu 16.04)
</h3>

<p>
	لاختبار تمكين الاتصالات البعيدة، سنستعمل عميل PostgreSQL <code>psql</code>. لتنصيبها، استعمل الأوامر التّاليّة:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo apt-get update
sudo apt-get install postgresql-client
</code></pre>

<p>
	عند استيفاء هذه المُتطلبات، ستكون جاهزا لاتّباع هذا الدّرس.
</p>

<h2 id="فهم-الإعداد-الافتراضيّ">
	فهم الإعداد الافتراضيّ
</h2>

<p>
	عند تنصيب PostgreSQL من مستودع حزم Ubuntu، فالخيار الافتراضيّ هو الانصات على المُضيف المحليّ (localhost). يُمكن تغيير هذا الخيار الافتراضي عبر تعديل مقطع <code>listen_addresses</code> على ملفّ <code>postgresql.conf</code>، لكنّ هذا الإعداد الافتراضي يمنع الخادوم من الانصات آليّا على واجهة عموميّة (public interface).<br>
	علاوة على ما سبق، فالملفّ <code>pg_hba.conf</code> لا يسمح سوى لاتّصالات من مقابس أسماء نطاقات Unix/Linux (Unix/Linux domain sockets)، وعنوان الاسترجاع (loopback address) الخاصّ بالخادوم المحلي، ما يعني بأنّ الاتّصالات من مُضيفات خارجيّة لن تُقبَل:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code># Put your actual configuration here
# ----------------------------------
#
# If you want to allow non-local connections, you need to add more
# "host" records.  In that case you will also need to make PostgreSQL
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.

# DO NOT DISABLE!
# If you change this first entry you will need to make sure that the
# database superuser can access the database using some other method.
# Noninteractive access to all databases is required during automatic
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local   all             postgres                                peer

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5
</code></pre>

<p>
	هذه الإعدادات الافتراضيّة تُحقّق هدف منع الانصات على واجهة عموميّة. إن تركناها على حالها وأبقينا الجدار النّاري مُفعّلا، فهذا كلّ ما في الأمر! يُمكننا الآن الانتقال إلى قسم "إجراءات إضافيّة لمزيد من الحماية” للتّعرف على كيفيّة حماية البيانات أثناء نقلها.<br>
	إن أردت الاتصال من مُضيف بعيد، فسنتطرّق إلى كيفيّة تعديل الإعدادات الافتراضيّة إضافة إلى الخطوات التي يجب اتّخاذها فورا لحماية الخادوم في الفقرة التّاليّة.
</p>

<h2 id="إعداد-الاتّصالات-البعيدة-remote-connections">
	إعداد الاتّصالات البعيدة (Remote Connections)
</h2>

<p>
	لإعداد بيئة إنتاج قويّة، وقبل بدء العمل مع بيانات حسّاسة، من المُفضّل تشفير مرور (traffic) PostgreSQL باستخدام <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>، إضافة إلى حماية باستخدام جدار ناري خارجي أو شبكة افتراضيّة خاصّة (<abbr title="Virtual Private Network | الشبكة الخاصة الافتراضية">VPN</abbr>). قبل القيام بالأمور السابقة ذكرها، يُمكننا اتّخاذ طريق أقل تعقيدا عبر تفعيل جدار ناريّ على خادوم قاعدة البيانات الخاص بنا وتقييد الوصول لتقبل فقط المُضيفات التي تحتاج إلى الوصول إلى الخادوم.
</p>

<h2 id="الخطوة-الأولى-–-إضافة-مُستخدم-وقاعدة-بيانات">
	الخطوة الأولى – إضافة مُستخدم وقاعدة بيانات
</h2>

<p>
	سنبدأ بإضافة مُستخدم وقاعدة بيانات لأغراض تجريبيّة. للقيام بذلك، سنستعمل عميل PostgreSQL <code>psql</code> للاتصال بصفة المُستخدم الإداري <code>postgres</code>. عبر تمرير الخيار <code>-i</code> للأمر <code>sudo</code> سيتمّ تشغيل صدفة تسجيل الدّخول (login shell) الخاصّة بالمُستخدم <code>postgres</code>، ما يضمن بأنّ الخيارات في ملفّ <code>.profile</code> أو في موارد أخرى مُتعلّقة بتسجيل الدّخول ستُحمَّل. يقوم الخيار <code>-u</code> بتحديد المُستخدم <code>postgres</code>:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo -i -u postgres psql
</code></pre>

<p>
	بعدها، سنقوم بإنشاء مُستخدم بكلمة مرور. تأكّد من استعمال كلمة مرور جيّدة عوضا عن المقطع <code>mypassword</code> في المثال أسفله:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>CREATE USER sammy WITH PASSWORD 'mypassword';
</code></pre>

<p>
	إن تمّ إنشاء المُستخدم بنجاح، فسنستقبل المُخرج التّالي:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>CREATE ROLE
</code></pre>

<p>
	<strong>مُلاحظة:</strong> منذ الإصدار 8.1 من PostgreSQL، فالأدوار (ROLES) والمُستخدمون (USERS) يشتركون في المعنى.لكنّ هناك اتّفاقا يقول بأنّه إن كان لدور كلمة مرور فإنّنا نُسمّيه مُستخدما، ونُسمّي الدّور عديم كلمة المرور دورا، لذا أحيانا ستحصل على <code>ROLE</code> في المُخرج رغم أنّك تتوقّع أن ترى <code>USER</code>.<br>
	تاليّاََ، سنُنشئ قاعدة بيانات وسنمنح كامل صلاحيّات الوصول لمُستخدمنا الجديد. تقول أفضل الممارسات بمنح المُستخدمين صلاحيّات الوصول التي يجتاجونها فقط، وعلى الموارد التي يجب أن يحصلوا عليها فقط، لذا فاعتمادا على حالة الاستخدام ( use case)، قد يُفضّل تقييد أحقيّة الوصول للمُستخدم. .
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>CREATE DATABASE sammydb OWNER sammy;
</code></pre>

<p>
	عند إنشاء قاعدة البيانات بنجاح، سنستقبل التّأكيد التّالي:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>CREATE DATABASE
</code></pre>

<p>
	بعد إنشاء المُستخدم وقاعدة البيانات، سنقوم بالخروج من سطر أوامر PostgreSQL:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>\q
</code></pre>

<p>
	بعد الضغط على مفتاح ENTER، سنرجع إلى سطر الأوامر وسنكون جاهزين للمُتابعة.
</p>

<h2 id="الخطورة-الثّانيّة-–-إعداد-ufw">
	الخطورة الثّانيّة – إعداد UFW
</h2>

<p>
	في درس <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/" rel="">الإعداد البدئي لخادوم Ubuntu</a> ، قمنا بتفعيل UFW وسمحنا لاتّصالات <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> فقط. قبل بدء الإعداد، لنتحقّق من حالة UFW:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo ufw status
</code></pre>

<p>
	<strong>مُلاحظة:</strong> إن كان المخرج يدُلّ على أنّ الجدار النّاري غير مُفعّل (inactive)، يُمكننا تفعيله بالأمر التّالي:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo ufw enable
</code></pre>

<p>
	بعد التّفعيل، فإنّ إعادة تنفيذ الأمر <code>sudo ufw status</code> سيستعرض القواعد الحاليّة. فعّل <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> إن كان ذلك مطلوبا:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo ufw allow OpenSSH
</code></pre>

<p>
	في حالة لم تُغيِّر من المُتطلّبات، فمُخرج الأمر <code>sudo ufw status</code> سيُشير إلى أنّ OpenSSH هي الخدمة الوحيدة المُفعّلة:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
</code></pre>

<p>
	بعد التّحقّق من حالة الجدار النّاري، سنقوم بالسماح بالوصول إلى منفذ PostgreSQL وسنُقيّد الوصول لنسمح فقط للمُضيف أو المُضيفات المرغوبة.<br>
	سيُضيف الأمر أسفله قاعدة للمنفذ الافتراضيّ لـPostgreSQL، أي المنفذ رقم 5432. إن غيّرت هذا المنفذ، فتأكّد من تعديل الأمر أسفله. تأكّد من استعمال عنوان IP الخاص بالخادوم الذي يحتاج إلى الوصول. أعد تنفيذ الأمر لإضافة كلّ عميل من العملاء الذين ترغب بإعطائهم أحقيّة الوصول إن كان ذلك لازما:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo ufw allow from client_ip_address to any port 5432
</code></pre>

<p>
	استبدل <code>client_ip_address</code> بعنوان IP الخاصّ بالعميل.<br>
	للتّحقّق من أنّ القاعدة قد طُبِّقت، يُمكنك تنفيذ الأمر <code>ufw status</code> مُجدّدا:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo ufw status
</code></pre>

<p>
	المُخرج:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
5432                       ALLOW       client_ip_address
OpenSSH (v6)               ALLOW       Anywhere (v6)
</code></pre>

<p>
	<strong>مُلاحظة:</strong> إن لم تكن لديك دراية مُسبقة بأساسيّات UFW، يُمكنك تعلّم المزيد في درس <a href="https://academy.hsoub.com/devops/security/firewalls/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-ufw-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D9%88%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AC%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%A7%D8%B1%D9%8A-r121/" rel=""> أساسيات UFW: قواعد وأوامر شائعة للجدار الناري </a>.
</p>

<p>
	بعد تجهيز قاعدة الجدار النّاريّ هذه، سنقوم الآن بإعداد PostgreSQL لتُنصت على عنوان IP العمومي. سنقوم بهذا عبر تعديل إعدادَيْن، خانة للمُضيف المُتصل في <code>pg_hba.conf</code> وإعداد <code>listen_addresses</code> في <code>postgresql.conf</code>.
</p>

<h2 id="الخطوة-الثّالثة-–-إعداد-المُضيفات-المسموح-لها-allowed-hosts">
	الخطوة الثّالثة – إعداد المُضيفات المسموح لها (Allowed Hosts)
</h2>

<p>
	سنبدأ عبر إضافة خانة المُضيف في ملفّ <code>pg_hba.conf</code>. إن كنت تستعمل نسخة أخرى غيْرَ النُّسخةِ 9.5 من PostgreSQL فتأكّد من تعديل الأمر أسفله قبل تنفيذه:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo nano /etc/postgresql/9.5/main/pg_hba.conf
</code></pre>

<p>
	سنضع أسطر <code>host</code> تحت مقطع التّعليقات الذي يصف كيفيّة السّماح للاتصالات غير المحليّة. سنُضيف سطرا يحمل العنوان العمومي الخاص بخادوم قاعدة البيانات لاختبار ما إذا كان الجدار النّاري مُعدّا بشكل صحيح. استبدل المقطع <code>client_ip_address</code> بعنوان IP الخاص بآلة العميل الخاصّ بك:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code># If you want to allow non-local connections, you need to add more
# "host" records.  In that case you will also need to make PostgreSQL
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.
host  sammydb  sammy   client_ip_address/32   md5
</code></pre>

<p>
	قبل حفظ التغييرات، لننظر إلى كل قيمة من قيم السّطر الذي أضفناه في حالة كنت ترغب تعديل أي منها:
</p>

<ul>
<li>
		المُضيف، المُعامل <code>host</code> يُحدّد بأنّ اتّصال TCP/IP سيُستَعمَل.
	</li>
	<li>
		قاعدة البيانات، العمود الثّاني، <code>sammydb</code>، يُحدّد أي قاعدة بيانات يُمكن للمُضيف أن يتّصل بها، يُمكنك تعيين أكثر من قاعدة بيانات واحدة عبر تفرقة أسمائها بالفاصلة <code>,</code>.
	</li>
	<li>
		المُستخدم، <code>sammy</code>، يُحدّد المُستخدم المسموح له بالاتّصال. وكما مع عمود قاعدة البيانات، فتستطيع تحديد أكثر من مستخدم واحد باستعمال علامة الفاصلة.
	</li>
	<li>
		العنوان، يُحدّد عنوان آلة العميل ويُمكن أن يكون عبارة عن اسم مُضيف (hostname)، مجال عناوين IP (IP address range) أو <a href="https://www.postgresql.org/docs/9.5/static/auth-pg-hba-conf.html" rel="external nofollow">كلمات مفتاحيّة خاصّة</a>. في المثال أعلاه، قمنا بالسماح لعنوان IP الخاصّ بالعميل فقط.
	</li>
	<li>
		طريقة الاستيثاق (auth-method)، في الأخير، يُمكن تحديد طريقة استيثاق، يُشير <code>md5</code> إلى كلمة مرور مزدوجة التّشفير بـMD5 (<a href="https://www.postgresql.org/docs/9.5/static/auth-methods.html#AUTH-PASSWORD" rel="external nofollow"> double-MD5-hashed password </a>) لن تحتاج سوى كلمة المرور التي تم إنشاؤها للمُستخدم الذي سيقوم بالاتّصال.<br>
		للمزيد من المعلومات وإعدادات إضافيّة راجع التوثيق الرّسمي لـPostgreSQL حول <a href="https://www.postgresql.org/docs/9.5/static/auth-pg-hba-conf.html" rel="external nofollow">ملفّ pg_hba.conf</a>.
	</li>
</ul>
<p>
	بعد الانتهاء من التّعديلات، احفظ وأغلق الملف.
</p>

<h2 id="الخطوة-الرّابعة-–-إعداد-عنوان-الإنصات-listening-address">
	الخطوة الرّابعة – إعداد عنوان الإنصات (Listening Address)
</h2>

<p>
	سنقوم الآن بضبط عنوان الإنصات في ملفّ <code>postgresql.conf</code> (تأكّد من تصحيح رقم النّسخة):
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo nano /etc/postgresql/9.5/main/postgresql.conf
</code></pre>

<p>
	أضف عناوين الإنصات تحت سطر <code>listen_addresses</code>، تأكّد من استبدال <code>server_ip_address</code> بعنوان IP أو اسم مُضيف قاعدة البيانات الخاصّة بك وليس عنوان العميل الذي سيقوم بالاتصال:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>#listen_addresses = 'localhost'         # what IP address(es) to listen on;
listen_addresses = 'localhost,server_ip_address'
</code></pre>

<p>
	احفظ وأغلق الملفّ عند الانتهاء من إجراء التّعديلات.
</p>

<h2 id="الخطوة-الخامسة-–-إعادة-تشغيل-postgresql">
	الخطوة الخامسة – إعادة تشغيل PostgreSQL
</h2>

<p>
	لن تُطبَّق التعديلات حتى نُعيد تشغيل عفريت (daemon) PostgreSQL، لذا سنقوم بهذا قبل أن نبدأ بالتجربة:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo systemctl restart postgresql
</code></pre>

<p>
	وبما أنّ <code>systemctl</code> لا يوفّر تغذيّة راجعة (feedback)، فسنتحقّق من نجاح إعادة تشغيل العفريت:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo systemctl status postgresql
</code></pre>

<p>
	إن احتوى المُخرج على <code>Active: active</code> وانتهى بمقطع مُشابه لما يلي، فهذا يعني بأنّ عفريتPostgreSQL مُفعّل.
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>...
Jan 10 23:02:20 PostgreSQL systemd[1]: Started PostgreSQL RDBMS.
</code></pre>

<p>
	بعد إعادة تشغيل العفريت، يُمكننا الآن التّجربة.
</p>

<h2 id="الخطوة-السّادسة-–-تجربة-الاتّصال">
	الخطوة السّادسة – تجربة الاتّصال
</h2>

<p>
	لنتحقّق من أنّنا نستطيع الاتّصال من جهاز العميل الخاص بنا. للقيام بهذا، سنستعمل الأمر <code>psql</code> مع الخيّار <code>-U</code> لتحديد المُستخدم، الخيار <code>-h</code> لتحديد عنوان IP الخاصّ بالعميل و <code>-d</code> لتحديد قاعدة البيانات، وذلك لأنّنا ضيّقنا الحماية لكي يتمكّن <code>sammy</code> فقط من الاتّصال بقاعدة بيانات واحدة فقط.
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>psql -U sammy -h postgres_host_ip -d sammydb
</code></pre>

<p>
	استبدل <code>postgres_host_ip</code> بعنوان IP الخاصّ بمُضيف PostgreSQL.<br>
	إن تمّ إعداد كل شيء بشكل صحيح، فيجب أن تستقبل المحثَّ (prompt) التّالي:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>Password for user sammy:
</code></pre>

<p>
	أدخل كلمة المرور التّي حدّدتها مسبقا عندما أضفت المُستخدم <code>sammy</code> في مرقاب (monitor) PostgreSQL.<br>
	إن حصلت على المحثّ التّالي، فهذا يعني بأنّ الاتصال قد تمّ بنجاح:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sammydb=&gt;
</code></pre>

<p>
	هذا يُؤكّد على أنّنا نستطيع تجاوز الجدار النّاري وأن نتّصل بقاعدة البيانات. سنقوم الآن بالخروج من المحثّ:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>\q
</code></pre>

<p>
	بعد التّحقّق من أنّ الإعدادات قد ضُبِطت بنجاح، سنقوم بتنظيف مُخلّفات التّجربة.
</p>

<h2 id="الخطوة-السّابعة-–-حذف-قاعدة-البيانات-والمُستخدم-التّجريبيّين">
	الخطوة السّابعة – حذف قاعدة البيانات والمُستخدم التّجريبيّين
</h2>

<p>
	بعد اختبار الاتّصال، يُمكننا الآن العودة إلى المُضيف واستخدام الأمر التّالي لحذف قاعدة البيانات والمُستخدم.
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo -i -u postgres psql
</code></pre>

<p>
	لحذف قاعدة البيانات:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>DROP DATABASE sammydb;
</code></pre>

<p>
	عند نجاح العمليّة، ستستقبل المُخرج التّالي:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>DROP DATABASE
</code></pre>

<p>
	لحذف المُستخدم:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>DROP USER sammy;
</code></pre>

<p>
	المُخرج عند نجاح العمليّة:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>DROP ROLE
</code></pre>

<p>
	سنقوم بإنهاء عمليّة التّنظيف بحذف خانة المُضيف الخاصّة بقاعدة البيانات <code>sammydb</code> من ملفّ <code>pg_hba.conf</code> لأنّنا لم نعد نحتاج إليها:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo nano /etc/postgresql/9.5/main/pg_hba.conf
</code></pre>

<p>
	استبدل <code>9.5</code> برقم النّسخة الخاصّة بك.<br>
	السّطر الذي يجب عليك حذفه:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>host  sammydb  sammy   client_ip_address/32   md5
</code></pre>

<p>
	ليُطبَّقَ التّعديل، سنقوم بحفظ وإغلاق الملفّ ومن ثمّ نُعيد تشغيل خادوم قاعدة البيانات:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo systemctl restart postgresl
</code></pre>

<p>
	للتحقّق من أنّ إعادة التّشغيل قد تمّت بنجاح، سنطّلع على الحالة:
</p>

<pre class="ipsCode" id="ips_uid_1590_7">
<code>sudo systemctl status postgres
</code></pre>

<p>
	إن كان المُخرج يحتوي على <code>Active: active</code> فهذا يعني بأنّ إعادة التّشغيل قد تمّت بنجاح.<br>
	يُمكنك الآن ضبط التّطبيق أو الخدمة على العميل التي تحتاج إلى إمكانيّة الاتصال عن بعد.
</p>

<h2 id="إجراءات-إضافيّة-لمزيد-من-الحماية">
	خاتمة
</h2>

<p>
	اتّخذنا في هذا الدّرس الخطوات الأساسيّة لحماية PostgreSQL عبر إعداد الجدار النّاريّ الخاصّ بالخادوم ليسمح فقط للاتصالات من المُضيفات التي تحتاج إلى صلاحيّات الوصول وعبر ضبط PostgreSQL لتقبل الاتصالات من هذه المُضيفات فقط. هذا يُخفّف من خطر بعض من أنواع الهجمات. تعتبر هذه الإجراءات الخطوة الأولى فقط لحماية البيانات، وننصح بمراجعة واتّخاذ الإجراءات الأمنية الإضافيّة المذكورة أعلاه.
</p>

<p>
	ترجمة -بتصرّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-secure-postgresql-against-automated-attacks" rel="external nofollow">How To Secure PostgreSQL Against Automated Attacks </a> لصاحبته Melissa Anderson.
</p>
]]></description><guid isPermaLink="false">380</guid><pubDate>Wed, 24 Jan 2018 10:32:46 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x633;&#x62A;&#x62E;&#x62F;&#x645; &#x62A;&#x642;&#x646;&#x64A;&#x629; &#x628;&#x62D;&#x62B; &#x627;&#x644;&#x646;&#x635;&#x648;&#x635; &#x627;&#x644;&#x643;&#x627;&#x645;&#x644;&#x629; Full-Text Search &#x641;&#x64A; PostgreSQL &#x639;&#x644;&#x649; &#x62E;&#x627;&#x62F;&#x645; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 16.04</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-%D8%A8%D8%AD%D8%AB-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D9%83%D8%A7%D9%85%D9%84%D8%A9-full-text-search-%D9%81%D9%8A-postgresql-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r369/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_12/18.png.aa5cde7c1160ea273b5776387dcc369d.png" /></p>

<p>
	تستخدِم محركات البحث تقنية بحث النصوص الكاملة (Full-Text Search (FTS للبحث عن نتائج في قاعدة بيانات ما، وهي تقنية مفيدة في تقوية نتائج البحث في مواقع مثل المتاجر الرقمية ومحركات البحث والجرائد وغيرها. ويتلخص ما تفعله FTS في جلب المستندات “documents” وهي وحدات من قواعد البيانات تحتوي بيانات نصية ﻻ تتطابق بشكل كامل مع نصوص البحث، فمثلًا حين يبحث مستخدم ما عن “cats and dogs” فإن التطبيق المزوّد بـتقنية بحث النصوص الكاملة سيُظهر نتائج تحتوي الكلمتين dogs وcats بشكل منفصل، أو بترتيب معكوس “dogs and cats”، أو صور مختلفة من هذه الكلمات (cat أو dog)، وذلك يعطي أفضلية للتطبيقات في تخمين قصد المستخدم وإظهار نتائج بحث مرتبطة بما يريده وبسرعة أكبر. وتسمح أنظمة إدارة قواعد البيانات مثل PostgreSQL بعمليات بحث نصية بشكل جزئي باستخدام بنود <code>LIKE</code>، لكن هذه العمليات تعطي عادةً أداء دون المستوى مع البيانات الكبيرة، كما أنها مقيَّدة بمطابقة مدخلات المستخدم الحرفية، وهذا يعني أن استعلامًا ما أو بحثًا عن بيانات معينة قد ﻻ يعطي أي نتائج، حتى لو كانت هناك مستندات عن معلومات مرتبطة بهذا البحث. أما باستخدام FTS فيمكنك بناء محرك بحث قوي للنصوص دون الحاجة لاعتماديات جديدة على أدوات أكثر تطورًا، وسنستخدم نظام PostgreSQL في هذا المقال لتخزين بيانات تحتوي مقالات لموقع أخبار افتراضي، ثم نتعلم كيف نبحث في قاعدة البيانات باستخدام FTS، واختيار أفضل النتائج فقط. ثم سنقوم ببعض التحسينات في الأداء لعمليات بحث النصوص الكاملة.
</p>

<h2 id="المتطلبات">
	المتطلبات
</h2>

<ul>
<li>
		خادم مثبت عليه أوبنتو 16.04 به مستخدم يملك صلاحيات `sudo`، ﻻ أن يكون هو المستخدم الجذر.
	</li>
	<li>
		خادمPostgreSQL، وسنستخدم نحن قاعدة بيانات ومستخدم باسم `sammy` كمثال.
	</li>
</ul>
<p>
	<strong>ملاحظة</strong>: تأكد أن يكون لديك حزمة <code>postgresql-conrib</code> عبر تنفيذ الأمر التالي في الطرفية:
</p>

<pre class="ipsCode" id="ips_uid_1711_10">
sudo apt-get list postgresql-contrib</pre>

<h3 id="الخطوة-الأولى-إنشاء-بيانات-وهمية-من-أجل-الشرح">
	الخطوة الأولى: إنشاء بيانات وهمية من أجل الشرح
</h3>

<p>
	سنحتاج إلى بعض البيانات من أجل استخدامها في اختبار إضافة FTS، لكن إن كان لديك جدول به قيم نصية جاهزة فيمكنك أن تنتقل إلى الخطوة التالية مباشرة وتستبدل قيمك بالقيم الموجودة هنا، أما إن لم يكن لديك فاتبع ما يلي:
</p>

<ul>
<li>
		اتصل بقاعدة بيانات PostgreSQL من خلال الخادم الخاص بها، ولن تحتاج كلمة مرور لأنك تتصل من نفس المضيف “host”:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
sudo -u postgres psql sammy</pre>

<p>
	وهذا الأمر سيفتح جلسة PostgreSQL تفاعلية ظاهر بها اسم قاعدة البيانات الذي نعمل عليها <code>-sammy</code> في حالتنا-، فيجب أن ترى <code>=#sammy</code> في محث قاعدة البيانات.
</p>

<ul>
<li>
		أنشئ جدولًا وسمّه <code>news</code>، وسيمثِّل كل مدخل في هذا الجدول مقالًا بعنوان وجزء من المحتوى والكاتب، إضافة إلى معرّف فريد:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs sql"><span class="pln">sammy</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">CREATE</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">TABLE</span></span><span class="pln"> news </span><span class="pun">(</span><span class="pln">
sammy</span><span class="pun">=#</span><span class="pln">   id SERIAL </span><span class="hljs-keyword"><span class="pln">PRIMARY</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">KEY</span></span><span class="pun">,</span><span class="pln">
sammy</span><span class="pun">=#</span><span class="pln">   title TEXT </span><span class="hljs-keyword"><span class="pln">NOT</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">NULL</span></span><span class="pun">,</span><span class="pln">
sammy</span><span class="pun">=#</span><span class="pln">   content TEXT </span><span class="hljs-keyword"><span class="pln">NOT</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">NULL</span></span><span class="pun">,</span><span class="pln">
sammy</span><span class="pun">=#</span><span class="pln">   author TEXT </span><span class="hljs-keyword"><span class="pln">NOT</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">NULL</span></span><span class="pln">
sammy</span><span class="pun">=#</span><span class="pln"> </span><span class="pun">);</span></span></code></pre>

<p>
	إن نظرنا للجدول السابق، فإن id هو معرّف الجدول الأساسي مع النوع الخاص <code>SERIAL</code> المسؤول عن زيادة هذا المعرف بشكل تلقائي للجدول، وذلك معرّف فريد سنتحدث عنه أكثر في الخطوة الثالثة حين ننظر في تحسينات الأداء.
</p>

<ul>
<li>
		واﻵن أضف بعض البيانات للجدول باستخدام أمر <code>INESRT</code>، ستمثل هذه البيانات الوهمية بالأسفل بعض مقالات الأخبار:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs vhdl"><span class="pln">sammy</span><span class="pun">=#</span><span class="pln"> INSERT INTO news </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">,</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> author</span><span class="pun">)</span><span class="pln"> VALUES 
sammy</span><span class="pun">=#</span><span class="pln">     </span><span class="pun">(</span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Pacific</span></span><span class="str"> Northwest high-speed rail line'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Currently</span></span><span class="str"> there are only a few options </span><span class="hljs-keyword"><span class="str">for</span></span><span class="str"> traveling the </span><span class="hljs-number"><span class="str">140</span></span><span class="str"> miles between Seattle </span><span class="hljs-keyword"><span class="str">and</span></span><span class="str"> Vancouver </span><span class="hljs-keyword"><span class="str">and</span></span><span class="str"> none </span><span class="hljs-keyword"><span class="str">of</span></span><span class="str"> them are ideal.'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Greg</span></span><span class="str">'</span><span class="pun">),</span><span class="pln">
sammy</span><span class="pun">=#</span><span class="pln">     </span><span class="pun">(</span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Hitting</span></span><span class="str"> the beach was voted the best part </span><span class="hljs-keyword"><span class="str">of</span></span><span class="str"> life </span><span class="hljs-keyword"><span class="str">in</span></span><span class="str"> the region'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Exploring</span></span><span class="str"> tracks </span><span class="hljs-keyword"><span class="str">and</span></span><span class="str"> trails was second most popular, followed by visiting the shops </span><span class="hljs-keyword"><span class="str">and</span></span><span class="str"> </span><span class="hljs-keyword"><span class="str">then</span></span><span class="str"> checking </span><span class="hljs-keyword"><span class="str">out</span></span><span class="str"> local parks.'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Ethan</span></span><span class="str">'</span><span class="pun">),</span><span class="pln">
sammy</span><span class="pun">=#</span><span class="pln">     </span><span class="pun">(</span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Machine</span></span><span class="str"> Learning from scratch'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Bare</span></span><span class="str"> bones implementations </span><span class="hljs-keyword"><span class="str">of</span></span><span class="str"> some </span><span class="hljs-keyword"><span class="str">of</span></span><span class="str"> the foundational models </span><span class="hljs-keyword"><span class="str">and</span></span><span class="str"> algorithms.'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Jo</span></span><span class="str">'</span><span class="pun">);</span></code></pre>

<p>
	سنجرب الآن بعض عمليات البحث بما أننا أدخلنا بعض البيانات التي يمكن البحث والاستعلام عنها.
</p>

<h3 id="الخطوة-الثانية-تجهيز-المستندات-والبحث-فيها">
	الخطوة الثانية: تجهيز المستندات والبحث فيها
</h3>

<p>
	أول خطوة هنا هي بناء مستند واحد بأعمدة نصوص متعددة من جدول قاعدة البيانات، ثم يمكننا تحويل النتائج بعدها إلى متَّجَه من الكلمات نستخدمه في عمليات البحث.<br><strong>ملاحظة</strong>: يستخدم خرج psql في هذا الدليل تهيئة <code>expanded display</code> والتي تعرض كل عمود من الخرج في سطر جديد لتسهيل عرضها على الشاشة. يمكننا تفعيلها كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs bash"><span class="pln">sammydb</span><span class="pun">=</span><span class="hljs-comment"><span class="pun">#</span><span class="pln"> \x</span></span></code></pre>

<p>
	يجب أن يكون الخرج هكذا:
</p>

<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs applescript"><span class="typ">Expanded</span><span class="pln"> display </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> </span><span class="hljs-function_start"><span class="hljs-keyword"><span class="pln">on</span></span><span class="pun">.</span></span></code></pre>

<ul>
<li>
		سنحتاج أولًا إلى جمع كل الأعمدة معًا باستخدام دالتي التسلسل `||` والتحويل `()to_tsvector` في PostgreSQL:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs sql"><span class="pln">sammy</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">SELECT</span></span><span class="pln"> title </span><span class="pun">||</span><span class="pln"> </span><span class="hljs-string"><span class="str">'. '</span></span><span class="pln"> </span><span class="pun">||</span><span class="pln"> content </span><span class="hljs-keyword"><span class="kwd">as</span></span><span class="pln"> document</span><span class="pun">,</span><span class="pln"> to_tsvector</span><span class="pun">(</span><span class="pln">title </span><span class="pun">||</span><span class="pln"> </span><span class="hljs-string"><span class="str">'. '</span></span><span class="pln"> </span><span class="pun">||</span><span class="pln"> content</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">as</span></span><span class="pln"> metadata </span><span class="hljs-keyword"><span class="pln">FROM</span></span><span class="pln"> news </span><span class="hljs-keyword"><span class="pln">WHERE</span></span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">;</span></span></code></pre>

<p>
	سيخرج لنا هذا أول سجلّ كمستند كامل باﻹضافة إلى نسخته التي سنستخدمها في البحث:
</p>

<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs livecodeserver"><span class="pun">-[</span><span class="pln"> RECORD </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="pun">]</span><span class="hljs-comment"><span class="pun">-----------------------------------------------------</span></span><span class="pln">
document    </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Pacific</span><span class="pln"> </span><span class="typ">Northwest</span><span class="pln"> high</span><span class="pun">-</span><span class="pln">speed rail </span><span class="hljs-built_in"><span class="pln">line</span></span><span class="pun">.</span><span class="pln"> </span><span class="typ">Currently</span><span class="pln"> there are only </span><span class="hljs-operator"><span class="pln">a</span></span><span class="pln"> few options </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> traveling </span><span class="hljs-operator"><span class="pln">the</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">140</span></span><span class="pln"> miles between </span><span class="typ">Seattle</span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">and</span></span><span class="pln"> </span><span class="typ">Vancouver</span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">and</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">none</span></span><span class="pln"> </span><span class="hljs-operator"><span class="pln">of</span></span><span class="pln"> them are ideal</span><span class="pun">.</span><span class="pln">

metadata    </span><span class="pun">|</span><span class="pln"> </span><span class="hljs-string"><span class="str">'140'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">18</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'current'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">8</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'high'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">4</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'high-spe'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">3</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'ideal'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">29</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'line'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">7</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'mile'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">19</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'none'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">25</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'northwest'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">2</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'option'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">14</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'pacif'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'rail'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">6</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'seattl'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">21</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'speed'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">5</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'travel'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">16</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'vancouv'</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">23</span></span></code></pre>

<p>
	ربما تلاحظ أن هناك كلمات أقل في النسخة المحوّلة <code>metadata</code> في الخرج السابق عن النسخة الأصلية <code>document</code>، وبعض الكلمات مختلفة، وكل كلمة لديها فاصلة منقوطة ; ورقم ملحق بها، وذلك ﻷن دالة <code>()to_tsvector</code> تنسّق كل كلمة كي نستطيع إيجاد صور مختلفة منها، ثم تصنف النتائج أبجديًا، وذلك الرقم هو موضع الكلمة في <code>document</code>، قد تكون هناك مواضع أخرى للكلمة بينها فواصل , إن كانت الكلمة المنسّقة تظهر أكثر من مرة.
</p>

<ul>
<li>
		يمكننا الآن استغلال إمكانيات FTS عبر استخدام هذا المستند المحوّل في البحث عن كلمة “Explorations”:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs sql"><span class="pln">sammy</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">SELECT</span></span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">FROM</span></span><span class="pln"> news </span><span class="hljs-keyword"><span class="pln">WHERE</span></span><span class="pln"> to_tsvector</span><span class="pun">(</span><span class="pln">title </span><span class="pun">||</span><span class="pln"> </span><span class="hljs-string"><span class="str">'. '</span></span><span class="pln"> </span><span class="pun">||</span><span class="pln"> content</span><span class="pun">)</span><span class="pln"> </span><span class="pun">@@</span><span class="pln"> to_tsquery</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Explorations'</span></span><span class="pun">);</span></span></code></pre>

<p>
	وسنقوم الآن بتحليل الدوال والمشغِّلات التي استخدمناها في اﻷمر أعلاه:<br>
	تترجم دالةُ <code>()to_tsquery</code> المعاملَ “parameter” -الذي يمكن أن يكون تعديلًا مباشرًا أو طفيفًا في بحث المستخدم- إلى معيار بحث نصي يقلل المدخلات بنفس طريقة <code>()to_tsvector</code>. وإضافة إلى ذلك فإن الدالة تتيح لك تحديد اللغة التي تريد استخدامها وما إن يجب أن تكون كل الكلمات موجودة في النتائج أو واحدة منهم فقط.<br>
	ويحدد مشغِّل @@ ما إن كان <code>tsvector</code> مماثلًا لـ <code>tsquery</code> أم لـ <code>tsvector</code> آخر، عبر عرض إحدى نتيجتين (<code>true</code> أو <code>false</code>)، مما يسهّل استخدامه كجزء من معيار <code>WHERE</code>.<br>
	الخرج:
</p>

<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs applescript"><span class="pun">-[</span><span class="pln"> RECORD </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="pun">]</span><span class="hljs-comment"><span class="pun">-----------------------------------------------------</span></span><span class="pln">
</span><span class="hljs-property"><span class="pln">id</span></span><span class="pln">      </span><span class="pun">|</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pln">
title   </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Hitting</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">the</span></span><span class="pln"> beach was voted </span><span class="hljs-keyword"><span class="pln">the</span></span><span class="pln"> best part </span><span class="hljs-keyword"><span class="pln">of</span></span><span class="pln"> life </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">the</span></span><span class="pln"> region
content </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Exploring</span><span class="pln"> tracks </span><span class="hljs-keyword"><span class="kwd">and</span></span><span class="pln"> trails was </span><span class="hljs-keyword"><span class="pln">second</span></span><span class="pln"> most popular</span><span class="pun">,</span><span class="pln"> followed </span><span class="hljs-keyword"><span class="kwd">by</span></span><span class="pln"> visiting </span><span class="hljs-keyword"><span class="pln">the</span></span><span class="pln"> shops </span><span class="hljs-keyword"><span class="kwd">and</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">then</span></span><span class="pln"> checking </span><span class="kwd">out</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">local</span></span><span class="pln"> parks</span><span class="pun">.</span><span class="pln">
author  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Ethan</span></code></pre>

<p>
	أظهرت عمليةُ البحث المستندَ الذي يحتوي كلمة Exploring، رغم أن الكلمة التي بحثنا عنها هي Exploration، أما لو استخدمنا مشغّل LIKE لكنّا حصلنا على نتيجة فارغة.<br>
	واﻵن بما أننا عرفنا كيفية تجهيز المستندات لها وكيفية هيكلة المستندات، فسننظر في كيفية تحسين أداء FTS.
</p>

<h3 id="الخطوة-الثالثة-تحسين-أداء-fts">
	الخطوة الثالثة: تحسين أداء FTS
</h3>

<p>
	قد يشكّل توليد مستند في كل مرة نستخدم فيها استعلام FTS مشكلة في الأداء إن كنا نستخدم خوادم صغيرة أو بيانات كبيرة.<br>
	وأحد الحلول الجيدة لهذا الأمر هو توليد المستند المحوّل أثناء إدخال المستند الأصلي وتخزينه مع البيانات الأخرى، وبهذه الطريقة يمكننا استرجاعه باستعلام صغير عوضًا عن توليده في كل مرة.
</p>

<ul>
<li>
		أولًا ننشئ عمودًا إضافيًا اسمه document في جدول news الذي أنشأناه قبل قليل:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs sql"><span class="pln"> sammy</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">ALTER</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">TABLE</span></span><span class="pln"> news </span><span class="hljs-keyword"><span class="pln">ADD</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"document"</span></span><span class="pln"> tsvector</span><span class="pun">;</span></span></code></pre>

<ul>
<li>
		سنحتاج الآن أن نستخدم استعلامًا جديدًا ﻹدخال البيانات في الجدول، لكن على عكس الخطوة الثانية، سنحتاج هنا إلى تجهيز المستند المحوّل وإضافته إلى عمود document الجديد:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs vhdl"><span class="pln">sammy</span><span class="pun">=#</span><span class="pln"> INSERT INTO news </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">,</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> author</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">)</span><span class="pln">
sammy</span><span class="pun">=#</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="hljs-number"><span class="lit">4</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Sleep</span></span><span class="str"> deprivation curing depression'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Clinicians</span></span><span class="str"> have long known that there </span><span class="hljs-keyword"><span class="str">is</span></span><span class="str"> a </span><span class="hljs-keyword"><span class="str">strong</span></span><span class="str"> link between sleep, sunlight </span><span class="hljs-keyword"><span class="str">and</span></span><span class="str"> mood.'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Patel</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> to_tsvector</span><span class="pun">(</span><span class="hljs-attribute"><span class="str">'Sleep</span></span><span class="str"> deprivation curing depression'</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="str">'. '</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="hljs-attribute"><span class="str">'Clinicians</span></span><span class="str"> have long known that there </span><span class="hljs-keyword"><span class="str">is</span></span><span class="str"> a </span><span class="hljs-keyword"><span class="str">strong</span></span><span class="str"> link between sleep, sunlight </span><span class="hljs-keyword"><span class="str">and</span></span><span class="str"> mood.'</span><span class="pun">));</span></code></pre>

<p>
	تتطلب إضافة عمود جديد إلى الجدول الموجود مسبقًا أن نضيف قيمًا فارغة لعمود document أولًا، وسنحدّثه الآن بالقيم المولَّدة.
</p>

<ul>
<li>
		استخدم أمر UPDATE لإضافة البيانات الناقصة.
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs sql"><span class="pln">sammy</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">UPDATE</span></span><span class="pln"> news </span><span class="hljs-keyword"><span class="pln">SET</span></span><span class="pln"> document </span><span class="pun">=</span><span class="pln"> to_tsvector</span><span class="pun">(</span><span class="pln">title </span><span class="pun">||</span><span class="pln"> </span><span class="hljs-string"><span class="str">'. '</span></span><span class="pln"> </span><span class="pun">||</span><span class="pln"> content</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">WHERE</span></span><span class="pln"> document </span><span class="hljs-keyword"><span class="pln">IS</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">NULL</span></span><span class="pun">;</span></span></code></pre>

<p>
	وهذه الأسطر التي أضفناها إلى جدولنا تحسّن من أداء FTS، لكن قد نواجه مشاكل أخرى في حالة البيانات الكبيرة بسبب أن قاعدة البيانات ﻻ تزال في حاجة إلى فحص الجدول كله ﻹيجاد الأسطر التي توافق مدخلات البحث، وحل هذا أن نستخدم الفهارس “indexes”. فهرس قاعدة البيانات database index هو هيكل بيانات يخزّن البيانات بشكل منفصل من البيانات الأساسية التي تحسّن عمليات استرجاع البيانات، ويتم تحديثها بعد أي تغيّر في محتوى الجدول وﻻ تتكلف إﻻ الكتابة الجديدة ومساحة تخزين صغيرة نسبيًا. وتسمح المساحة الصغيرة وهيكل البيانات المهيّأ جيدًا للفهارس أن تعمل بكفاءة أكبر من استخدام مساحة الجدول لاختيار الاستعلامات. وبشكل عام، فإن الفهارس تسرّع إيجاد قواعد البيانات للصفوف من خلال البحث باستخدام خوارزميات وهياكل بيانات خاصة. ويمتاز نظام PostgreSQL بأن به <a href="https://www.postgresql.org/docs/9.1/static/indexes-types.html" rel="external nofollow">عدة أنواع من الفهارس</a> التي تناسب أنواعًا محددة من الاستعلامات، وأقرب هذه الأنواع إلى حالتنا هنا هي فهارس GiST وGIN. والفرق البارز بينهما هو السرعة التي يجلب كل منهما البيانات من الجدول، فـGIN أبطأ أثناء إضافة بيانات جديدة لكنه أسرع في الاستعلام، أما GiST فأسرع في بناء البيانات الجديدة لكنه يحتاج إلى قراءات إضافية للبيانات.
</p>

<p>
	وسننشئ فهرس GIN هنا ﻷن GiST أبطأ بثلاث مرات في جلب البيانات:
</p>

<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs sql"><span class="pln">sammy</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">CREATE</span></span><span class="pln"> INDEX idx_fts_search </span><span class="hljs-keyword"><span class="pln">ON</span></span><span class="pln"> news </span><span class="hljs-keyword"><span class="pln">USING</span></span><span class="pln"> gin</span><span class="pun">(</span><span class="pln">document</span><span class="pun">);</span></span></code></pre>

<ul>
<li>
		وسيصبح استعلام SELECT أبسط باستخدام عمود document المفهرس:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs sql"><span class="pln">sammy</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">SELECT</span></span><span class="pln"> title</span><span class="pun">,</span><span class="pln"> content </span><span class="hljs-keyword"><span class="pln">FROM</span></span><span class="pln"> news </span><span class="hljs-keyword"><span class="pln">WHERE</span></span><span class="pln"> document </span><span class="pun">@@</span><span class="pln"> to_tsquery</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Travel | Cure'</span></span><span class="pun">);</span></span></code></pre>

<p>
	ويجب أن يكون الخرج شيئًا كهذا:
</p>

<pre class="ipsCode" id="ips_uid_1711_8">
<code class="hljs livecodeserver"><span class="pun">-[</span><span class="pln"> RECORD </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="pun">]</span><span class="hljs-comment"><span class="pun">-----------------------------------------------------</span></span><span class="pln">
title   </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Sleep</span><span class="pln"> deprivation curing depression
content </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Clinicians</span><span class="pln"> have </span><span class="hljs-keyword"><span class="kwd">long</span></span><span class="pln"> known that there </span><span class="kwd">is</span><span class="pln"> </span><span class="hljs-operator"><span class="pln">a</span></span><span class="pln"> strong link between sleep</span><span class="pun">,</span><span class="pln"> sunlight </span><span class="hljs-operator"><span class="kwd">and</span></span><span class="pln"> mood</span><span class="pun">.</span><span class="pln">
</span><span class="pun">-[</span><span class="pln"> RECORD </span><span class="hljs-number"><span class="lit">2</span></span><span class="pln"> </span><span class="pun">]</span><span class="hljs-comment"><span class="pun">-----------------------------------------------------</span></span><span class="pln">
title   </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Pacific</span><span class="pln"> </span><span class="typ">Northwest</span><span class="pln"> high</span><span class="pun">-</span><span class="pln">speed rail </span><span class="hljs-built_in"><span class="pln">line</span></span><span class="pln">
content </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Currently</span><span class="pln"> there are only </span><span class="hljs-operator"><span class="pln">a</span></span><span class="pln"> few options </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> traveling </span><span class="hljs-operator"><span class="pln">the</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">140</span></span><span class="pln"> miles between </span><span class="typ">Seattle</span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">and</span></span><span class="pln"> </span><span class="typ">Vancouver</span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">and</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">none</span></span><span class="pln"> </span><span class="hljs-operator"><span class="pln">of</span></span><span class="pln"> them are ideal</span><span class="pun">.</span></code></pre>

<p>
	واﻵن يمكنك الخروج من لوحة التحكم الخاصة بقاعدة البيانات عبر كتابة q\.
</p>

<h2 id="الخلاصة">
	الخلاصة
</h2>

<p>
	يغطي هذا الدليل كيفية استخدام تقنية بحث النصوص الكاملة في PostgreSQL، بما في ذلك تجهيز وتخزين مستند البيانات الوصفية metadata واستخدام فهرس لتحسين أداء البحث. وإن أردت مزيدًا من الشرح حول FTS في PostgreSQL فألق نظرة على<a href="https://www.postgresql.org/docs/9.5/static/textsearch-intro.html" rel="external nofollow"> التوثيق الرسمي لنظام PostgreSQL</a> حول بحث النصوص الكاملة.
</p>

<p>
	ترجمة -بتصرف- لمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-use-full-text-search-in-postgresql-on-ubuntu-16-04" rel="external nofollow">How to Use Full-Text Search in PostgreSQL on Ubuntu 16.04</a> لصاحبه Ilya Kotov
</p>
]]></description><guid isPermaLink="false">369</guid><pubDate>Thu, 18 Jan 2018 07:01:00 +0000</pubDate></item><item><title>&#x634;&#x631;&#x62D; &#x627;&#x644;&#x62A;&#x643;&#x631;&#x627;&#x631; &#x641;&#x64A; &#x646;&#x638;&#x627;&#x645; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; PostgreSQL &#x639;&#x644;&#x649; &#x62A;&#x648;&#x632;&#x64A;&#x639;&#x629; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648;</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D9%86%D8%B8%D8%A7%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-%D8%B9%D9%84%D9%89-%D8%AA%D9%88%D8%B2%D9%8A%D8%B9%D8%A9-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r378/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_01/13-2.png.2183be6b8cbe84c29edcd46e98e33fc5.png" /></p>

<p>
	PostgreSQL، هو نظام متطور مفتوح المصدر، كائنيّ الارتباط-Object Relational ﻹدارة قواعد البيانات، وهو نظام قابل للتوسع، بمعنى أنه يستطيع معالجة اﻷحمال المختلفة بدءًا من تطبيقات جهاز واحد إلى خدمات الويب التجارية التي تتعامل مع مستخدمين كثر في نفس الوقت. وهذا النظام Transactional أي يعامل النقل المتسلسل للبيانات -مثل تحديث قاعدة البيانات- كوحدة واحدة لضمان سلامتها، ويحقق خصائص ACID (Atomicity – Consistency – Isolation – Durability). وكذلك يدعم قسمًا كبيرًا من معايير SQL.
</p>

<p>
	<strong>فائدة</strong>: خصائص ACID هي أربعة خصائص يجب توافرها في تعاملات قواعد البيانات، وهي الذرية-Atomicity -أن تُنفَّذ العملية كوحدة واحدة-، والتناسق-Consistency، والعزل-Isolation، والثبات-Durability. ويوفر PostgreSQL العديد من المزايا مثل:
</p>

<ul>
<li>
		الاستعلامات المعقدة-Complex Queries
	</li>
	<li>
		المفاتيح الأجنبية-Foreign Keys
	</li>
	<li>
		المشاهدات القابلة للتحديث-Updatable Views
	</li>
	<li>
		 سلامة عمليات نقل البيانات-Transactional Integrity
	</li>
	<li>
		التحكم في التزامن متعدد الإصدارات-Multiversion Concurrency Control
	</li>
</ul>
<p>
	وذكرنا قبل قليل أنه قابل للتمدد والتوسع بواسطة مستخدميه عبر إضافة دوال-Functions جديدة، ومشغّلات-operators، وأنواع بيانات، وطرق فهرسة، ولغات إجرائية-Procedural Languages. ويقدّم PostgreSQL طرقًا عديدة لتكرار قاعدة بيانات، وسنتعلم في هذا الدليل كيفية إعداد تكرار من نوع (الرئيسي-Master/الثانوي-Slave)، وهي عملية مزامنة بين قاعدتي بيانات من خلال النسخ من قاعدة بيانات على خادم (الرئيسي) إلى قاعدة بيانات أخرى في خادم آخر (الثانوي)، وسننفذ هذه العملية على خادم يعمل بتوزيعة أوبنتو 16.04.
</p>

<h3 id="المتطلبات">
	المتطلبات
</h3>

<p>
	أن يكون PostgreSQL 9.6 مثبتًا على خادم أوبنتو 16.04
</p>

<h2 id="إعداد-ufw">
	إعداد UFW
</h2>

<ul>
<li>
		ثبّت جدار الحماية الناري غير المعقّد-Uncomplicated Firewall على خوادم أوبنتو، وهو أداة ﻹدارة جدار الحماية المعتمِد على iptables. استخدم الأمر التالي في الطرفية:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
# apt-get install -y ufw</pre>

<ul>
<li>
		واﻵن، أضف PostgreSQL وخدمة <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> إلى جدار الحماية، عبر تنفيذ اﻷمر التالي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># ufw allow <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>
# ufw allow postgresql
</code></pre>

<ul>
<li>
		فعّل جدار الحماية:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># ufw enable
</code></pre>

<h2 id="إعداد-خادم-postgresql-الرئيسي">
	إعداد خادم PostgreSQL الرئيسي
</h2>

<p>
	سيمتلك الخادم الرئيسي صلاحيات القراءة والكتابة لقاعدة البيانات، وسيكون هو القادر على نقل البيانات إلى الخادم الثانوي. • افتح محررًا نصيًا وعدّل إعدادات PostgreSQL الرئيسية كما يلي: (ملاحظة: استبدل EDITOR$ بالمحرر النصي الذي تفضّله)
</p>

<pre class="ipsCode" id="ips_uid_2735_7">
<code># $EDITOR /etc/postgresql/9.6/main/postgresql.conf
</code></pre>

<ul>
<li>
		أزل التعليق (#) من سطر listen_addresses وأضف عنوان IP للخادم الرئيسي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>listen_addresses = 'master_server_IP_address'
</code></pre>

<ul>
<li>
		واﻵن، أزل التعليق من سطر wal_level لتغيير قيمته:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>wal_level = hot_standby
</code></pre>

<ul>
<li>
		وأزل التعليق من السطر التالي كي تستخدم المزامنة المحلية-Local Syncing لمستوى المزامنة "Synchronization Level"
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>synchronous_commit = local
</code></pre>

<ul>
<li>
		ثم أزل التعليق من السطرين التاليين، وعدلهما كما يلي، بما أننا نستخدم خادمين:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>max_wal_senders = 2
wal_keep_segments = 10
</code></pre>

<p>
	واﻵن احفظ الملف وأغلقه. عدّل ملف pg_hba.conf من أجل إعدادات التوثيق-Authentication، كما يلي:
</p>

<ul>
<li>
		افتح الملف عبر هذا الأمر:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># $EDITOR /etc/postgresql/9.6/main/pg_hba.conf
</code></pre>

<ul>
<li>
		الصق الإعدادات التالية:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># Localhost
host    replication     replica          127.0.0.1/32            md5
 
# PostgreSQL Master IP address
host    replication     replica          master_IP_address/32            md5
 
# PostgreSQL SLave IP address
host    replication     replica          slave_IP_address/32            md5
</code></pre>

<ul>
<li>
		احفظ الملف وأغلقه، ثم أعد تشغيل PostgreSQL باستخدام systemctl
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># systemctl restart postgresql
</code></pre>

<h2 id="إنشاء-مستخدم-من-أجل-التكرار">
	إنشاء مستخدم من أجل التكرار
</h2>

<p>
	سننشئ مستخدم PostgreSQL من أجل عملية التكرار، فسجّل الدخول أولًا إلى حساب المستخدم المسمّىpostgres وافتح صدفة PostgreSQL، من خلال الأوامر التالية:
</p>

<pre class="ipsCode" id="ips_uid_2735_7">
<code># su - postgres
$ psql
</code></pre>

<p>
	أنشئ مستخدمًا جديدًا:
</p>

<pre class="ipsCode" id="ips_uid_2735_7">
<code>postgres=# CREATE USER replica REPLICATION LOGIN ENCRYPTED PASSWORD 'usr_strong_pwd';
</code></pre>

<p>
	أغلق الصَّدَفة، وهكذا تنتهي إعدادات الخادم الرئيسي.
</p>

<h2 id="إعداد-الخادم-الثانوي">
	إعداد الخادم الثانوي
</h2>

<p>
	لن تكون للخادم الثانوي صلاحيات الكتابة في قاعدة البيانات، وستكون وظيفته الوحيدة هي استقبال البيانات من الخادم الرئيسي، أي ستكون له صلاحية القراءة فقط. • سنوقف أولًا خدمة PostgreSQL:
</p>

<pre class="ipsCode" id="ips_uid_2735_7">
<code># systemctl stop postgresql
</code></pre>

<ul>
<li>
		افتح ملف الإعدادات الرئيسية لـ PostgreSQL:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># $EDITOR /etc/postgresql/9.6/main/postgresql.conf
</code></pre>

<ul>
<li>
		أزل التعليق من سطر listen_addresses وغيّر قيمته:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>listen_addresses = 'slave_IP_address'
</code></pre>

<ul>
<li>
		أزل التعليق من سطر wal_level وغيّره كما يلي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>wal_level = hot_standby
</code></pre>

<ul>
<li>
		وأزل التعليق أيضًا من سطر synchronous_commit كما في الخادم الرئيسي للاستفادة من المزامنة المحلية-local syncing:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>synchronous_commit = local
</code></pre>

<ul>
<li>
		ثم أزل التعليق من السطرين التاليين وغيّر قيمهما كما يلي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>max_wal_senders = 2
wal_keep_segments = 10
</code></pre>

<ul>
<li>
		أزل التعليق من السطر التالي وغيّر قيمته كما يلي من أجل تفعيل hot_standby للخادم الثانوي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>hot_standby = on
</code></pre>

<p>
	احفظ الملف وأغلقه.
</p>

<h2 id="نسخ-البيانات-من-الخادم-الرئيسي-إلى-الثانوي">
	نسخ البيانات من الخادم الرئيسي إلى الثانوي
</h2>

<p>
	لكي نزامن بيانات الخادم الرئيسي مع الثانوي، فيجب أن يحل المجلد الأساسي “main” في الخادم الرئيسي محل المجلد الرئيسي في الخادم الثانوي، ونفعل هذا كما يلي: • سجل الدخول إلى مستخدم postgres:
</p>

<pre class="ipsCode" id="ips_uid_2735_7">
<code># su – postgres
</code></pre>

<ul>
<li>
		خذ نسخة احتياطية من مجلد البيانات الفعلي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>$ cd/var/lib/postgresql/9.6/
$ mv main main_bak
</code></pre>

<ul>
<li>
		أنشئ مجلد أساسيًا جديدًا:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>$ mkdir main/
</code></pre>

<ul>
<li>
		غيّر صلاحياته:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>$ chmod 700 main
</code></pre>

<ul>
<li>
		وهنا، انسخ المجلد الأساسي من الخادم الرئيسي إلى الخادم الثانوي باستخدام pg_basebackup:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># pg_basebackup -h master_IP_address -U replica -D /var/lib/postgresql/9.6/main /-P –xlog
</code></pre>

<ul>
<li>
		وحين ينتهي النسخ، أنشئ ملف recovery.conf داخل المجلد الأساسي "main” وانسخ المحتوى التالي فيه:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code>standby_mode = 'on'
primary_conninfo = 'host=10.0.15.10 port=5432 user=replica password=usr_strong_pwd'
trigger_file = '/tmp/postgresql.trigger.5432'
</code></pre>

<ul>
<li>
		واﻵن، احفظ الملف وأغلقه، ثم غير صلاحياته كما يلي:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># chmod 600 recovery.conf
</code></pre>

<ul>
<li>
		شغّل خدمة PostgreSQL:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_2735_7">
<code># systemctl start postgresql
</code></pre>

<p>
	وهنا تنتهي إعدادات الخادم الثانوي.
</p>

<h2 id="الخلاصة">
	الخلاصة
</h2>

<p>
	لقد رأينا في هذا الدليل المبسّط كيفية ضبط تكرار Master/Slave في PostgreSQL عبر استخدام خادمين يعملان بأوبنتو. وهذه الطريقة في التكرار ما هي إﻻ إحدى طرق عديدة يوفرها نظام PostgreSQL لإدارة قواعد البيانات.
</p>

<p>
	ترجمة -بتصرف- لمقال <a href="https://www.unixmen.com/postgresql-replication-tutorial/" rel="external nofollow">PostgreSQL Replication on Ubuntu Tutorial</a> لصاحبه Giuseppe Molica
</p>
]]></description><guid isPermaLink="false">378</guid><pubDate>Sat, 13 Jan 2018 05:00:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x646;&#x642;&#x644; &#x645;&#x62C;&#x644;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x641;&#x64A; PostgreSQL &#x625;&#x644;&#x649; &#x645;&#x633;&#x627;&#x631; &#x645;&#x62E;&#x62A;&#x644;&#x641; &#x641;&#x64A; &#x62E;&#x627;&#x62F;&#x645; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 16.04</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D9%82%D9%84-%D9%85%D8%AC%D9%84%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-postgresql-%D8%A5%D9%84%D9%89-%D9%85%D8%B3%D8%A7%D8%B1-%D9%85%D8%AE%D8%AA%D9%84%D9%81-%D9%81%D9%8A-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r368/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_12/20-2.png.8731c2500de28b29a2454837b1fa062b.png" /></p>

<p>
	تزيد أحجام قواعد البيانات مع الوقت حتى تتجاوز أحيانًا المساحة اﻷصلية التي خُصِّصت لها، وقد تواجهك مشاكل في المدخلات والمخرجات I/O إن كانت قاعدة البيانات موجودة في نفس القسم “Partition” الموجود به بقية نظام التشغيل. وسنتعلم في هذا الدليل كيفية نقل مجلد البيانات في <a href="https://academy.hsoub.com/devops/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D9%8A%D8%A9-sqlite-%D9%85%D8%B9-mysql-%D9%85%D8%B9-postgresql-r72/" rel="">نظام PostgreSQL لإدارة قواعد البيانات</a> إلى مكان جديد في حالة كنت تريد إضافة مساحة جديدة أو تبحث في طرق لتحسين الأداء، أو الاستفادة من مزايا التخزين الأخرى التي توفرها أنظمة مصفوفات الأقراص المستقلة RAID، أو عُقّدُ التخزين الشبكية “Network Block Storages”، أو غيرها من الأجهزة وأنظمة التخزين.
</p>

<h2 id="المتطلبات">
	المتطلبات
</h2>

<ul>
<li>
		خادم يعمل بتوزيعة أوبنتو 16.04، عليها مستخدم له صلاحية sudo -انتبه، ليس المستخدم الجذر root-.
	</li>
	<li>
		خادم PostgreSQL، <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D8%AA-postgresql-%D9%88%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%87-%D8%B9%D9%84%D9%89-ubuntu-1404-r147/" rel="">يمكنك قراءة كيفية تثبيت واستخدام PostgreSQL على أوبنتو في هذا المقال</a>.
	</li>
</ul>
<p>
	وسننقل البيانات إلى وحدة تخزينية “Block Storage Device” لها نقطة الضم التالية <code>/mnt/volume-nyc1-01</code>.<br><strong>فائدة</strong>: تكون اﻷقراص أو اﻷجهزة/الوحدات “Devices”بشكل عام في أنظمة لينكس عبارة عن ملفات، وكل جهاز “قسم/partition من القرص الصلب مثلًا” له نقطة ضم “mount point” يكون فيها محتواه.
</p>

<h2 id="الخطوة-الأولى-نقل-مجلد-بيانات-postgresql">
	الخطوة الأولى: نقل مجلد بيانات PostgreSQL
</h2>

<ul>
<li>
		سنبدأ جلسة PostgreSQL تفاعلية أولًا كي نتحقق من المكان الحالي للمجلد، وسنستخدم أمر <code>psql</code> للدخول إلى شاشة تفاعلية “interactive monitor”، ثم نضيف<code>u postgres-</code> لتخبر <code>sudo</code> أن ينفِّذ أمر <code>psql</code> كمستخدم <code>postgre</code>.
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
$ sudo -u postgres psql</pre>

<ul>
<li>
		وبمجرد دخولك إلى الشاشة، اطلب عرض مجلد البيانات:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs sql"><span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">SHOW</span></span><span class="pln"> data_directory</span><span class="pun">;</span></span></code></pre>

<p>
	وسيكون الخرج في حالتنا هكذا:
</p>

<pre class="ipsCode" id="ips_uid_6879_15">
       data_directory       
------------------------------
/var/lib/postgresql/9.5/main
(1 row)</pre>

<p>
	ويؤكد هذا الخرج أن PostgreSQL مُعدَّ لاستخدام مجلد البيانات الافتراضي <code>main</code> الموجود في المسار ذي اللون الأحمر بالأعلى، إذًا هذا هو المجلد الذي سننقله.
</p>

<ul>
<li>
		اكتب <code>q\</code> للخروج بمجرد أن تتأكد من وجود المجلد في النظام.
	</li>
	<li>
		سنوقف PostgreSQL لضمان سلامة البيانات، قبل أن نغيّر شيئًا في مجلد <code>main</code>:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> systemctl stop postgresql</span></code></pre>

<ul>
<li>
		ثم نستعلم عن حالة PostgreSQL لنتأكد أنها أُوقِفَت، إذ أن <code>systemctl</code> ﻻ يعرض نتائج أوامر إدارة الخدمات في النظام:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> systemctl status postgresql</span></code></pre>

<p>
	وتتأكد أنها أوقفت إن كان السطر الأخير في الخرج يقول لك إن الخادم قد توقف:
</p>

<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs css"><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">
</span><span class="hljs-tag"><span class="typ">Jul</span></span><span class="pln"> </span><span class="lit">22</span><span class="pln"> </span><span class="lit">16</span><span class="hljs-pseudo"><span class="pun">:</span><span class="lit">22</span></span><span class="hljs-pseudo"><span class="pun">:</span><span class="lit">44</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pln">ubuntu</span><span class="pun">-</span><span class="lit">512mb</span><span class="pun">-</span><span class="pln">nyc1</span><span class="pun">-</span><span class="lit">01</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pln">systemd</span></span><span class="hljs-attr_selector"><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-tag"><span class="typ">Stopped</span></span><span class="pln"> </span><span class="hljs-tag"><span class="typ">PostgreSQL</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pln">RDBMS</span></span><span class="pun">.</span></code></pre>

<p>
	والآن، سننسخ مجلد البيانات الحالي إلى مكان جديد باستخدام <code>rsync</code>، مع استخدام لاحقة <code>a-</code> للحفاظ على الصلاحيات وبقية خصائص المجلد، و<code>v-</code> لعرض خرج مفصّل كي تتابع ما يحدث.<br>
	ملاحظة: تأكد من عدم وجود شرطة مائلة بعد اسم المجلد، والتي قد تضاف تلقائيًا إن استخدمت زر tab لإكمال النصوص، إذ أن <code>rsync</code> سيضع محتوى المجلد في نقطة الضم بدلًا من مجلد محتوي لـ PostgreSQL.
</p>

<ul>
<li>
		سنبدأ <code>rsync</code> من مجلد postgresql من أجل محاكاة هيكل المجلد الأصلي في المكان الجديد، وسنتجنب مشاكل الصلاحيات للترقيات المستقبلية عبر إنشاء مجلد postgresql داخل نقطة الضم “mount point” والإبقاء على ملكيته لمستخدم PostgreSQL.
	</li>
</ul>
<p>
	ونحن لا نحتاج هنا إلى مجلد الإصدار 9.5 بما أننا حددنا مكان المجلد بوضوح في ملف<code>postgresql.conf</code>، لكن ﻻ بأس باتباع أسلوب المشروع خاصة إن كانت هناك حاجة في المستقبل لتشغيل عدة إصدارات من PostgreSQL:
</p>

<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs lasso"><span class="pln">   $ sudo rsync </span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">av</span></span><span class="pln"> </span><span class="pun">/</span><span class="hljs-built_in"><span class="kwd">var</span></span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">postgresql </span><span class="pun">/</span><span class="pln">mnt</span><span class="pun">/</span><span class="pln">volume</span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">nyc1</span></span><span class="hljs-subst"><span class="pun">-</span></span><span class="hljs-number"><span class="lit">01</span></span></code></pre>

<ul>
<li>
		وسنعيد تسمية المجلد الحالي مع امتداد <code>bak</code>. ونبقي عليه حتى نتأكد أن النقل تم بنجاح، ونحن نعيد تسميته من أجل تجنب أي لبس قد يحدث من ملفات موجودة في كلا من المكان القديم والجديد:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs cs"><span class="pln">$ sudo mv </span><span class="pun">/</span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">postgresql</span><span class="pun">/</span><span class="hljs-number"><span class="lit">9.5</span></span><span class="pun">/</span><span class="pln">main </span><span class="pun">/</span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">postgresql</span><span class="pun">/</span><span class="hljs-number"><span class="lit">9.5</span></span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">bak</span></code></pre>

<p>
	وبهذا نكون جاهزين لننتقل إلى ضبط إعدادات PostgreSQL.
</p>

<h2 id="الخطوة-الثانية-التوجيه-إلى-المكان-الجديد-للبيانات">
	الخطوة الثانية: التوجيه إلى المكان الجديد للبيانات
</h2>

<p>
	تُضبط القيمة الافتراضية لـ <code>data_directory</code> في إعدادات PostgreSQL على أنه موجود في هذا المسار:
</p>

<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs cs"><span class="str">/</span><span class="hljs-keyword"><span class="str">var</span></span><span class="str">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">postgresql</span><span class="pun">/</span><span class="hljs-number"><span class="lit">9.5</span></span><span class="pun">/</span><span class="pln">main</span></code></pre>

<ul>
<li>
		وتوجد هذه الإعدادات في ملف <code>postgresql.conf</code>، وسنغيّر الآن تلك الإعدادات لنضع المكان الجديد لمجلد البيانات:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> nano </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">postgresql</span><span class="pun">/</span><span class="hljs-number"><span class="lit">9.5</span></span><span class="pun">/</span><span class="pln">main</span><span class="pun">/</span><span class="pln">postgresql</span><span class="pun">.</span><span class="pln">conf</span></code></pre>

<ul>
<li>
		ابحث عن السطر الذي يبدأ بكلمة <code>data_directory</code> وغيّر مساره إلى المسار الموجود فيه المجلد الجديد، وفي حالتنا فإن هذا السطر يجب أن يبدو هكذا بعد تغيير المسار:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs bash"><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">
data_directory </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'/mnt/volume-nyc1-01/postgresql/9.5/main'</span></span><span class="pln">
</span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span></code></pre>

<h2 id="الخطوة-الثالثة-إعادة-تشغيل-postgresql">
	الخطوة الثالثة: إعادة تشغيل PostgreSQL
</h2>

<p>
	نحن الآن جاهزون لتشغيل PostgreSQL، الصق الأمر الأول لتشغيله، والثاني لمعرفة حالته:
</p>

<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> systemctl start postgresql
$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> systemctl status postgresql</span></code></pre>

<ul>
<li>
		افتح شاشة PostgreSQL التفاعلية:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> </span><span class="pun">-</span><span class="pln">u postgres psql</span></code></pre>

<ul>
<li>
		اطلب عرض قيمة data_directory لنتأكد أن مجلد البيانات الجديد هو المستخدَم الآن:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs sql"><span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">SHOW</span></span><span class="pln"> data_directory</span><span class="pun">;</span></span></code></pre>

<p>
	يجب أن يكون الخرج هكذا في حالتنا:
</p>

<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs asciidoc"><span class="hljs-header"><span class="pln">            data_directory
</span><span class="pun">-----------------------------------------</span></span><span class="pln">
</span><span class="pun">/</span><span class="pln">mnt</span><span class="pun">/</span><span class="pln">volume</span><span class="pun">-</span><span class="pln">nyc1</span><span class="pun">-</span><span class="lit">01</span><span class="pun">/</span><span class="pln">postgresql</span><span class="pun">/</span><span class="lit">9.5</span><span class="pun">/</span><span class="pln">main
</span><span class="pun">(</span><span class="lit">1</span><span class="pln"> row</span><span class="pun">)</span></code></pre>

<p>
	وننتهز هذه الفرصة بما أننا أعدنا تشغيل PostgreSQL وتأكدنا أنه يستخدم المكان الجديد، كي نتأكد أن قاعدة البيانات تعمل بكفاءة.
</p>

<ul>
<li>
		احذف مجلد البيانات الاحتياطي -القديم- بمجرد أن تتأكد من سلامة أي بيانات موجودة مسبقًا:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_13">
<code class="hljs lasso"><span class="pln">$ sudo rm </span><span class="hljs-attribute"><span class="pun">-</span><span class="typ">Rf</span></span><span class="pln"> </span><span class="pun">/</span><span class="hljs-built_in"><span class="kwd">var</span></span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">postgresql</span><span class="pun">/</span><span class="hljs-number"><span class="lit">9.5</span></span><span class="pun">/</span><span class="pln">main</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="pln">bak</span></code></pre>

<ul>
<li>
		أعد تشغيل PostgreSQL مرة أخيرة للتأكد من أنها تعمل كما يجب:
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_6879_17">
$ sudo systemctl start postgresql
$ sudo systemctl status postgresql</pre>

<h2 id="الخلاصة">
	الخلاصة
</h2>

<p>
	يجب أن تستخدم قاعدةُ بياناتك الآن المجلدَ الجديد في المكان الذي اخترتَه له، وهذا يعني أنك تستطيع الآن زيادة حجم قاعدة البيانات بما أنك نقلتها من المكان القديم ذي المساحة المحدودة.
</p>

<p>
	ترجمة -بتصرف- لمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-move-a-postgresql-data-directory-to-a-new-location-on-ubuntu-16-04" rel="external nofollow">How To Move a PostgreSQL Data Directory to a New Location on Ubuntu 16.04</a> لصاحبته Melissa Anderson
</p>
]]></description><guid isPermaLink="false">368</guid><pubDate>Wed, 20 Dec 2017 14:08:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; PostgreSQL &#x645;&#x639; &#x62A;&#x637;&#x628;&#x64A;&#x642; Django &#x639;&#x644;&#x649; &#x62E;&#x627;&#x62F;&#x645; &#x64A;&#x639;&#x645;&#x644; &#x628;&#x62F;&#x64A;&#x628;&#x64A;&#x627;&#x646; 8</title><link>https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-postgresql-%D9%85%D8%B9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-django-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D9%8A%D8%B9%D9%85%D9%84-%D8%A8%D8%AF%D9%8A%D8%A8%D9%8A%D8%A7%D9%86-8-r372/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_12/16-2.png.e0a6addd576b25fa3cad6cf772e35a19.png" /></p>

<p>
	چانجو هو إطار عمل مرن يستخدم ﻹنشاء تطبيقات بلغة بايثون، وهذه التطبيقات مُجهزة تلقائيًا لتخزين البيانات في ملف قاعدة بيانات SQLite خفيف ويعمل بشكل جيد في الاستعمالات العادية والصغيرة، لكن استخدام نظام إدارة قواعد بيانات تقليدي سيطوِّر أداء التطبيق تحت ضغط زيادة المستخدمين أو زيادة حجم البيانات. وسنستعرض في هذا الدليل كيفية تثبيت وتهيئة PostgreSQL لاستخدامها مع تطبيقات Django، وسنثبّت الحزم اللازمة وننشئ اعتماديات قاعدة البيانات للتطبيق، ثم نبدأ مشروع Django جديد ونجهّزه ليستخدم هذه اﻹعدادات.
</p>

<h2 id="المتطلبات">
	المتطلبات
</h2>

<p>
	خادم يعمل بتوزيعة ديبيان جنو/لينكس إصدار 8 “Jessie” مع مستخدم -غير الجذر- له صلاحية <code>sudo</code>.
</p>

<h2 id="تثبيت-الحزم-من-مستودعات-ديبيان">
	تثبيت الحزم من مستودعات ديبيان
</h2>

<p>
	سنثبّت أولًا <code>pip</code> -مدير حزم بايثون- لتثبيت وإدارة حزم بايثون، وسنثبّت أيضًا برنامج قاعدة البيانات والمكتبات اللازمة للتفاعل معهم.<br>
	يحتاج إصدار بايثون 2 و3 إلى حزم مختلفة قليلًا عن بعضها، لذا اختر الأوامر التي تتوافق مع إصدار بايثون لديك.
</p>

<ul>
<li>
		انسخ الأوامر التالية إن كنت تستخدم بايثون 2:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<span class="pln">$ sudo apt</span><span class="pun">-</span><span class="kwd">get</span><span class="pln"> update
$ sudo apt</span><span class="pun">-</span><span class="kwd">get</span><span class="pln"> install python</span><span class="pun">-</span><span class="pln">pip python</span><span class="pun">-</span><span class="pln">dev libpq</span><span class="pun">-</span><span class="pln">dev postgresql postgresql</span><span class="pun">-</span><span class="pln">contrib</span></pre>

<ul>
<li>
		وهذه إن كنت تستخدم بايثون 3:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code>$ sudo apt-get update
$ sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib
</code></pre>

<h2 id="إنشاء-قاعدة-البيانات-والمستخدم-الخاص-بها">
	إنشاء قاعدة البيانات والمستخدم الخاص بها
</h2>

<p>
	يستخدم Postgres نظام توثيق للاتصالات المحلية اسمه “توثيق النِّدّ Peer Authentication”. وهذا يعني أنه إذا كان اسم المستخدم في نظام التشغيل يطابق اسم Postgres صالح، فإن هذا المستخدم يمكنه الولوج دون الحاجة إلى توثيق. وقد أُنشئ مستخدم للنظام اسمه postgres ليتوافق مع مستخدم postgres المدير لنظام PostgreSQL، وسنحتاج هذا المستخدم لتنفيذ مهام إدارية، ويمكننا أيضًا أن نستخدم sudo وندخل اسم المستخدم من خلال لاحقة u-.
</p>

<ul>
<li>
		سجل الدخول إلى جلسة Postgres تفاعلية عبر كتابة الأمر التالي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> </span><span class="pun">-</span><span class="pln">u postgres psql</span></code></pre>

<p>
	وسننشئ أولًا قاعدة بيانات لمشروع Django، ويجب أن يكون لكل مشروع قاعدة البيانات الخاصة به للدواعي الأمنية. وسنسمّي قاعدة البيانات في هذا المقال باسم <code>myproject</code>، لكن من اﻷفضل طبعًا أن تختار اسمًا يصلح لمشروع حقيقي.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: تذكر أن تنهي كل الأوامر في محث SQL بفاصلة منقوطة ; :
		</p>
	</div>
</blockquote>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs sql"><span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">CREATE</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">DATABASE</span></span><span class="pln"> myproject</span><span class="pun">;</span></span></code></pre>

<p>
	سيكون الخرج هكذا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs sql"><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">CREATE</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">DATABASE</span></span></span></code></pre>

<ul>
<li>
		أنشئ مستخدمًا لقاعدة البيانات، وسنستعمله للاتصال بقاعدة البيانات والتفاعل معها، وﻻ تنس أن تستبدل <code>myprojectuser</code> باسم قاعدة البيانات الذي اخترته، وتغيّر <code>password</code> بكلمة سر قوية:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs sql"><span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">CREATE</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">USER</span></span><span class="pln"> myprojectuser </span><span class="hljs-keyword"><span class="pln">WITH</span></span><span class="pln"> PASSWORD </span><span class="hljs-string"><span class="str">'password'</span></span><span class="pun">;</span></span></code></pre>

<p>
	سيكون الخرج هكذا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs sql"><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">CREATE</span></span><span class="pln"> ROLE</span></span></code></pre>

<p>
	واﻵن سنعدّل بعض معاملات الاتصال لهذا المستخدم لتسريع عمليات قاعدة البيانات بما أن القيم الصحيحة لن تضطر إلى أن تمر بعمليات استعلام وضبط في كل مرة يحدث اتصال.
</p>

<ol>
<li>
		 فسنضبط الترميز الافتراضي على UTF-8 وهو الترميز الافتراضي الذي يتوقعه Django.
	</li>
	<li>
		 وسنضبط القاعدة الافترضية لعزل التعاملات “default transactio isolation scheme” على <code>read committed</code>، والتي تحظر القراءة من التعاملات غير المرسلة “uncommitted transactions”.
	</li>
	<li>
		 وأخيرًا، سنضبط المنطقة الزمنية الافتراضية لمشاريع Django على <code>UTC</code>.
	</li>
</ol>
<p>
	وهذه الإعدادات يُنصح بها في التوثيق الرسمي لمشروع Django، دعنا نكتب ذلك الآن:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs sql"><span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">ALTER</span></span><span class="pln"> ROLE myprojectuser </span><span class="hljs-keyword"><span class="pln">SET</span></span><span class="pln"> client_encoding </span><span class="hljs-keyword"><span class="pln">TO</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'utf8'</span></span><span class="pun">;</span></span><span class="pln">
postgres</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">ALTER</span></span><span class="pln"> ROLE myprojectuser </span><span class="hljs-keyword"><span class="pln">SET</span></span><span class="pln"> default_transaction_isolation </span><span class="hljs-keyword"><span class="pln">TO</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'read committed'</span></span><span class="pun">;</span></span><span class="pln">
postgres</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">ALTER</span></span><span class="pln"> ROLE myprojectuser </span><span class="hljs-keyword"><span class="pln">SET</span></span><span class="pln"> timezone </span><span class="hljs-keyword"><span class="pln">TO</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'UTC'</span></span><span class="pun">;</span></span></code></pre>

<p>
	ويكون الخرج هكذا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs sql"><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">ALTER</span></span><span class="pln"> ROLE
</span><span class="hljs-keyword"><span class="pln">ALTER</span></span><span class="pln"> ROLE
</span><span class="hljs-keyword"><span class="pln">ALTER</span></span><span class="pln"> ROLE</span></span></code></pre>

<ul>
<li>
		وكل ما نحتاجه الآن هو إعطاء مستخدم قاعدة البيانات صلاحيات الوصول لقاعدة البيانات التي أنشأناها للتو:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs sql"><span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">GRANT</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">ALL</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">PRIVILEGES</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">ON</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">DATABASE</span></span><span class="pln"> myproject </span><span class="hljs-keyword"><span class="pln">TO</span></span><span class="pln"> myprojectuser</span><span class="pun">;</span></span></code></pre>

<p>
	ويكون الخرج هكذا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs sql"><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">GRANT</span></span></span></code></pre>

<ul>
<li>
		اخرج الآن من محث SQL:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs bash"><span class="pln">postgres</span><span class="pun">=</span><span class="hljs-comment"><span class="pun">#</span><span class="pln"> \q</span></span></code></pre>

<p>
	يجب أن تعود الطرفية بك الآن إلى جلسة shell السابقة.
</p>

<h2 id="تثبيت-django-في-بيئة-افتراضية">
	تثبيت Django في بيئة افتراضية
</h2>

<p>
	يمكننا تثبيت Django الآن بما أن قاعدة بياناتنا قد صارت جاهزة، وسنثبته وكل اعتمادياته داخل بيئة بايثون افتراضية لتحقيق مرونة أكثر، وستتيح لنا حزمة <code>virtualenv</code> إنشاء هذه البيئات بسهولة.
</p>

<ul>
<li>
		اكتب هذا السطر في الطرفية لتثبيت <code>virtualenv</code> إن كنت تستخدم Python 2:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> pip install virtualenv</span></code></pre>

<ul>
<li>
		وهذا إن كنت تستخدم Python 3:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> pip3 install virtualenv</span></code></pre>

<ul>
<li>
		أنشئ مجلدًا جديدًا باسم مشروعك (استبدل اسم مشروعك بـ <code>myproject</code> الذي اخترناه هنا لغرض المثال فقط)، ثم انتقل داخله:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs smalltalk"><span class="hljs-char"><span class="pln">$ </span></span><span class="pln">mkdir </span><span class="pun">~/</span><span class="pln">myproject
</span><span class="hljs-char"><span class="pln">$ </span></span><span class="pln">cd </span><span class="pun">~/</span><span class="pln">myproject</span></code></pre>

<ul>
<li>
		اكتب السطر التالي لإنشاء بيئة افتراضية لتخزين متطلبات بايثون لمشروع Django الخاص بنا:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">virtualenv venv</span></code></pre>

<p>
	وذلك سيثبّت نسخة محلية من بايثون وأمر pip محلي داخل مجلد اسمه venv داخل مجلد مشروعك.
</p>

<ul>
<li>
		نحتاج الآن إلى تفعيل البيئة الافتراضية قبل تثبيت البرامج داخلها، ويمكننا فعل ذلك عبر الأمر التالي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-built_in"><span class="pln">source</span></span><span class="pln"> venv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></code></pre>

<p>
	سيتغير المحثّ الآن ليشير إلى أنك تعمل الآن داخل بيئة افتراضية وسيبدو شبيهًا بهذا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs ruby"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln">user</span><span class="hljs-variable"><span class="pln">@host</span></span><span class="hljs-symbol"><span class="pun">:~/</span><span class="pln">myproject</span></span><span class="pln">$</span></code></pre>

<ul>
<li>
		ويمكننا الآن تثبيت Django باستخدام <code>pip</code>، ثم سنثبت <code>psycopg2</code> التي ستتيح لنا استخدام قاعدة البيانات التي أعددناها:
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			(ﻻحظ أنه يجب استخدام أمر <code>pip</code> وليس <code>pip3</code>داخل البيئة الافتراضية بغض النظر عن نسخة بايثون التي لديك)
		</p>
	</div>
</blockquote>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs ruby"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">pip install django psycopg2</span></code></pre>

<ul>
<li>
		يمكننا الآن أن نبدأ مشروع Django داخل مجلد المشروع (myproject في حالتنا)، وسينشئ هذا مجلدًا فرعيًا بنفس اسم مجلد المشروع ليحتوي الشفرة البرمجية، إضافة إلى مخطوطة إدارية “management script” داخل المجلد الحالي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs ruby"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">django</span><span class="pun">-</span><span class="pln">admin</span><span class="pun">.</span><span class="pln">py startproject myproject </span><span class="pun">.</span></code></pre>

<p>
	<strong>ملاحظة</strong>: تأكد من إضافة النقطة في نهاية الأمر السابق، فنحن ﻻ نحتاج مستوىً فرعيًا آخر في المجلد بما أننا أنشأنا مجلدًا أبًا للمشروع “parent directory” ليحتوي مجلد البيئة الوهمية، وهو ما كان سيحدث لو لم نضع النقطة في نهاية سطر الأوامر السابق.<br>
	يجب أن تكون هيكلة مجلدك الحالي شبيهة بهذا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs avrasm"><span class="pun">.</span><span class="pln">
</span><span class="pun">└──</span><span class="pln"> </span><span class="pun">./</span><span class="pln">myproject</span><span class="pun">/</span><span class="pln">
    </span><span class="pun">├──</span><span class="pln"> manage</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span><span class="pln">
    </span><span class="pun">├──</span><span class="pln"> myproject</span><span class="pun">/</span><span class="pln">
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __init__</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span><span class="pln">
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> settings</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span><span class="pln">
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> urls</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span><span class="pln">
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> wsgi</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span><span class="pln">
    </span><span class="pun">└──</span><span class="pln"> venv</span><span class="pun">/</span><span class="pln">
        </span><span class="pun">└──</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span></code></pre>

<p>
	وكما ترى فإن لدينا مجلدًا أبًا للمشروع يحتوي مخطوطة manage.py، ومجلد داخلي للمشروع، ومجلد البيئة الوهمية venv الذي أنشأناه قبل قليل.
</p>

<h2 id="ضبط-إعدادات-قاعدة-بيانات-django">
	ضبط إعدادات قاعدة بيانات Django
</h2>

<p>
	سنضبط الآن مشروعنا كي نستخدم قاعدة البيانات التي أنشأناها،
</p>

<ul>
<li>
		افتح ملف الإعدادات الرئيسية لمشروع Django الموجود في المجلد الفرعي للمشروع:
	</li>
</ul>
<p>
	<strong>(ملاحظة: استبدل مشروعك بـmyproject)</strong>
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs ruby"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">nano </span><span class="pun">~</span><span class="hljs-regexp"><span class="str">/myproject/</span><span class="pln">myproject</span></span><span class="hljs-regexp"><span class="pun">/</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">py</span></span></code></pre>

<p>
	قد تحتاج أيضًا إلى تعديل تعليمة <code>ALLOWED_HOSTS</code> قبل إعداد قاعدة البيانات، وتلك التعليمةتحدد قائمة عناوين أو أسماء نطاقات مسموح باستخدامها للاتصال مع مشروع Django، فأي طلب اتصال بترويسة HOST ليس في هذه القائمة سيتم اعتراضه. ويتطلّب Django أن تعدّل هذه التعليمة كي يمنع فئة معينة من الاختراقات الأمنية.<br>
	ولتعديل هذه التعليمة، أدخل -بين قوسين مربعيْن- عناوين IP أو أسماء النطاقات المرتبطة بخادم Django الخاص بك ويجب أن يكون كل نطاق أو عنوان IP داخل علامتي تنصيص مفردتيْن، وتفصل بين كل واحد منهم فاصلة “,”. وإن رغبت في الاستجابة لطلبات من نطاق ما إضافة إلى النطاقات الفرعية له فضع نقطة قبله أثناء كتابته.
</p>

<ul>
<li>
		إليك أمثلة تعرض لك الطريقة الصحيحة لصيغة هذه التعليمة، استبدل النطاقات وعناوين الـ IP التي تريدها بالأمثلة الموجودة هنا:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs ruleslanguage"><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">
</span><span class="hljs-array"><span class="com"># </span></span><span class="com">أبسط حالة: اكتب العناوين وأسماء النطاقات لخادم چانجو الخاص بك  </span><span class="pln">
</span><span class="hljs-array"><span class="com"># ALLOWED</span></span><span class="com">_HOSTS = [ </span><span class="hljs-string"><span class="com">'example.com'</span></span><span class="com">, </span><span class="hljs-string"><span class="com">'203.0.113.5'</span></span><span class="com">]</span><span class="pln">
</span><span class="hljs-array"><span class="com"># </span></span><span class="com">ابدأ اسم النطاق بنقطة للاستجابة له ولأي نطاق فرعي</span><span class="pln">
</span><span class="hljs-array"><span class="com"># ALLOWED</span></span><span class="com">_HOSTS = [</span><span class="hljs-string"><span class="com">'.example.com'</span></span><span class="com">, </span><span class="hljs-string"><span class="com">'203.0.113.5'</span></span><span class="com">]</span><span class="pln">
ALLOWED_HOSTS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'your_server_domain_or_IP'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'second_domain_or_IP'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.]</span></code></pre>

<p>
	واﻵن ابحث عن قسم DATABASES الذي يبدو كهذا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs cs"><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">

DATABASES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-string"><span class="str">'default'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'ENGINE'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'django.db.backends.sqlite3'</span></span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'NAME'</span></span><span class="pun">:</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">join</span></span><span class="pun">(</span><span class="pln">BASE_DIR</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'db.sqlite3'</span></span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span></code></pre>

<p>
	هذا القسم يستخدم SQLite كقاعدة بيانات، ونريد تعديل هذه لكي يستخدم قاعدة بيانات PostgreSQL الخاصة بنا.
</p>

<ul>
<li>
		فأول ما نفعله هو تغيير المحرك كي يستخدم محوّل <code>postgresql_psycopg2</code> بدلًا من <code>sqlite3</code>، ثم نستخدم اسم قاعدة بياناتنا (myproject في مثالنا) في خانة NAME، ونضيف بعض بيانات تسجيل الدخول مثل اسم المستخدم وكلمة المرور، والمضيف الذي سيتصل به، وسنضيف خانة Port ونتركها فارغة كي يتم اختيار المنفذ الافتراضي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs bash"><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">

DATABASES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-string"><span class="str">'default'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'ENGINE'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'django.db.backends.postgresql_psycopg2'</span></span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'NAME'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'myproject'</span></span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'USER'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'myprojectuser'</span></span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'PASSWORD'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'password'</span></span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'HOST'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'localhost'</span></span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'PORT'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">''</span></span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span></code></pre>

<p>
	واﻵن احفظ الملف وأغلقه.
</p>

<h2 id="نقل-قاعدة-البيانات-واختبار-مشروعك">
	نقل قاعدة البيانات واختبار مشروعك
</h2>

<p>
	يمكننا الآن نقل هياكل البيانات -بما أننا أنهينا ضبط إعدادات Django- إلى قاعدة بياناتنا واختبار الخادم،
</p>

<ul>
<li>
		سنبدأ بإنشاء هيكل ابتدائي لقاعدة البيانات بما أننا ﻻ نملك أي بيانات حقيقية بعد:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs smalltalk"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-char"><span class="pln">$ </span></span><span class="pln">cd </span><span class="pun">~/</span><span class="pln">myproject
</span><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-char"><span class="pln">$ </span></span><span class="pun">./</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py makemigrations
</span><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-char"><span class="pln">$ </span></span><span class="pun">./</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py migrate</span></code></pre>

<ul>
<li>
		أنشئ حسابًا إداريًا:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs ruby"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">$ </span></span><span class="pun">./</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></code></pre>

<p>
	وسيطلب منك النظام اختيار اسم لمستخدم هذا الحساب وعنوان بريد وكلمة مرور له.<br>
	ملاحظة: قبل أن تجرب خادم التطوير، تأكد أن تفتح منفذًا في جدارك الناري، وإن كنت تستخدم جدار ufw، فإن فتح المنفذ المناسب يتم عبر كتابة هذا الأمر:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs bash"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> $ </span><span class="hljs-built_in"><span class="pln">sudo</span></span><span class="pln"> ufw allow </span><span class="hljs-number"><span class="lit">8000</span></span></code></pre>

<p>
	أما إن كنت تستخدم جدار iptables، فإن الأمر الذي تحتاجه يعتمد على اﻹعدادات التي تستخدمها، الأمر التالي يصلح ﻷغلب الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs lasso"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> $ sudo iptables </span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">I</span></span><span class="pln"> INPUT </span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">p</span></span><span class="pln"> tcp </span><span class="hljs-subst"><span class="pun">--</span></span><span class="pln">dport </span><span class="hljs-number"><span class="lit">8000</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">j</span></span><span class="pln"> ACCEPT</span></code></pre>

<ul>
<li>
		يمكنك الآن اختبار عمل قاعدة بياناتك بشكل صحيح من خلال بدء تشغيل خادم تطوير Django:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs ruby"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">$ </span></span><span class="pun">./</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py runserver </span><span class="hljs-number"><span class="lit">0</span></span><span class="lit">.</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">.</span><span class="hljs-number"><span class="lit">0</span></span><span class="lit">.</span><span class="hljs-number"><span class="lit">0</span></span><span class="hljs-symbol"><span class="pun">:</span></span><span class="hljs-number"><span class="lit">8000</span></span></code></pre>

<ul>
<li>
		اذهب إلى عنوان IP الخاص بالخادم أو اسم النطاق الخاص به متبوعًا بـ 8000: للوصول إلى الصفحة الجذر الافتراضية لـDjango:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs cs"><span class="pln">http</span><span class="pun">:</span><span class="hljs-comment"><span class="com">//server_domain_or_IP:8000</span></span></code></pre>

<p>
	يجب أن ترى صفحة index الافتراضية:
</p>

<p style="text-align: center;">
	<img alt="django_index.png" class="ipsImage ipsImage_thumbnailed" data-fileid="25886" data-unique="rnta5qj1y" src="https://academy.hsoub.com/uploads/monthly_2017_12/django_index.png.a21dbbd3584517db0734af891992e584.png"></p>

<ul>
<li>
		ضع <code>admin/</code> في نهاية الرابط، يجب أن تكون قادرًا على الوصول لشاشة تسجيل الدخول إلى واجهة التحكم:
	</li>
</ul>
<p style="text-align: center;">
	<img alt="admin_login.png" class="ipsImage ipsImage_thumbnailed" data-fileid="25885" data-unique="1ed6h0arn" src="https://academy.hsoub.com/uploads/monthly_2017_12/admin_login.png.4112657536b2ee21f61a9ee5dad0d7eb.png"></p>

<ul>
<li>
		أدخل اسم المستخدم وكلمة المرور اللتان أنشأتهما قبل قليل باستخدام <code>createsuperuser</code>، فتدخل إلى لوحة التحكم:
	</li>
</ul>
<p style="text-align: center;">
	<img alt="admin_interface.png" class="ipsImage ipsImage_thumbnailed" data-fileid="25884" data-unique="l9knz08v2" src="https://academy.hsoub.com/uploads/monthly_2017_12/admin_interface.png.7b48b6d82f728a97f3bcd32592667de6.png"></p>

<p>
	وبدخولنا للوحة التحكم نكون قد تأكدنا أن قاعدة البيانات قد خزّنت معلومات حساب المستخدم الخاص بنا ويمكننا الدخول إليه دون مشاكل. يمكنك الآن إيقاف الخادم حين تنتهي من تحققك بالضغط على ctrl-c داخل شاشة الطرفية.<br>
	وإن أردت وسيلة أخرى لاختبار قاعدة البيانات يمكنك الاستعلام داخل قاعدة بيانات Postgres نفسها باستخدام psql،
</p>

<ul>
<li>
		فمثلًا يمكنك الاتصال بقاعدة بيانات مشروعك (myproject) عن طريق المستخدم myprojectuser وإظهار كل الجداول المتاحة بكتابة الأمر التالي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs lasso"><span class="pun">(</span><span class="pln">venv</span><span class="pun">)</span><span class="pln"> $ psql </span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">W</span></span><span class="pln"> myproject myprojectuser </span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">h</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">127.0</span></span><span class="hljs-number"><span class="pun">.</span><span class="lit">0</span></span><span class="hljs-number"><span class="lit">.1</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">f</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">&lt;</span></span><span class="pun">(</span><span class="pln">echo </span><span class="hljs-string"><span class="str">'\dt'</span></span><span class="pun">)</span></code></pre>

<p>
	لتفصيل اﻷمر السابق، فإنه يجب أن نستخدم ﻻحقة <code>h-</code> من أجل الاتصال بالمضيف المحلي localhost عبر الشبكة لتحديد أننا نريد توثيق كلمة المرور بدلًا من توثيق النّدّ.<br>
	أما <code>W-</code> فستجعل psql يسألك عن كلمة المرور المناسبة، و<code>f-</code> لتمرير الأمر الوصفي “<code>meta-command</code>” في <code>psql</code> لتنفيذه، و<code>dt\</code> لعرض كل الجداول في قاعدة البيانات.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2824_7" style="">
<code class="hljs lasso"><span class="pln">                      </span><span class="hljs-built_in"><span class="typ">List</span></span><span class="pln"> of relations
 </span><span class="typ">Schema</span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln">            </span><span class="typ">Name</span><span class="pln">            </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="typ">Type</span></span><span class="pln">  </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln">     </span><span class="typ">Owner</span><span class="pln">     
</span><span class="hljs-subst"><span class="pun">--------+----------------------------+-------+---------------</span></span><span class="pln">
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> auth_group                 </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> auth_group_permissions     </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> auth_permission            </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> auth_user                  </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> auth_user_groups           </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> auth_user_user_permissions </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> django_admin_log           </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> django_content_type        </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> django_migrations          </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
 </span><span class="hljs-keyword"><span class="kwd">public</span></span><span class="pln"> </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> django_session             </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> table </span><span class="hljs-subst"><span class="pun">|</span></span><span class="pln"> myprojectuser
</span><span class="pun">(</span><span class="hljs-number"><span class="lit">10</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">rows</span></span><span class="pun">)</span></code></pre>

<p>
	وكما ترى فإن Django قد أنشأ بعض الجداول داخل قاعدة البيانات الخاصة بنا، وهذا يؤكد لنا أن إعداداتنا كانت صحيحة.
</p>

<h2 id="الخلاصة">
	الخلاصة
</h2>

<p>
	قد عرضنا في هذا الدليل كيفية تثبيت وإعداد PostgreSQL كقاعدة بيانات في النهاية الخلفية لمشروع Django، إذ تستفيد أغلب المشاريع من استخدام نظم إدارة متطورة لقواعد البيانات، رغم أن SQLite تتعامل بشكل جيد أثناء تطوير المشروع وأثناء الاستخدام الخفيف له.
</p>

<p>
	ترجمة -بتصرف- لمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-django-application-on-debian-8" rel="external nofollow">How To Use Postgresql with your Django Application on Debian 8</a> لصاحبه Justin Ellingwood.
</p>
]]></description><guid isPermaLink="false">372</guid><pubDate>Sat, 16 Dec 2017 03:00:00 +0000</pubDate></item></channel></rss>
