PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

पोस्टग्रेएसक्यूएल के लिए पीजीपूल के लिए एक गाइड:भाग दो

यह ब्लॉग "A Guide to Pgpool for PostgreSQL" का दूसरा भाग है। मेमोरी कैश और इंस्टॉलेशन में लोड बैलेंसिंग, सेशन पूलिंग को कवर करने वाला पहला भाग यहां पाया जा सकता है।

कई उपयोगकर्ता विशेष रूप से उच्च उपलब्धता सुविधाओं के लिए pgpool की ओर देखते हैं, और इसमें बहुत कुछ है। वेब पर pgpool HA के लिए बहुत कम निर्देश हैं (उदाहरण के लिए एक लंबा और छोटा वाला), इसलिए उन्हें दोहराने का कोई मतलब नहीं होगा। न ही हम कॉन्फ़िगरेशन मानों का एक और अंधा सेट प्रदान करना चाहते हैं। इसके बजाय मैं नियमों के खिलाफ खेलने का सुझाव देता हूं और इसे गलत तरीके से करने का प्रयास करता हूं, इसलिए हम कुछ दिलचस्प व्यवहार देखेंगे। शीर्ष अपेक्षित सुविधाओं में से एक (कम से कम यह पृष्ठ के शीर्ष पर है) एक "मृत" पूर्व मास्टर की उपयोगिता को पहचानने और इसे pg_rewind के साथ पुन:उपयोग करने की क्षमता है। यह बड़े डेटा के साथ नए स्टैंडबाय को वापस लाने के घंटों को बचा सकता है (जैसा कि हम rsync या pg_basebackup को छोड़ देते हैं, जो नए मास्टर से सभी फाइलों को प्रभावी ढंग से कॉपी करता है)। कड़ाई से बोलते हुए, pg_rewind नियोजित विफलता के लिए है (नए हार्डवेयर में अपग्रेड या माइग्रेट के दौरान)। लेकिन हमने देखा है कि जब यह नियोजित नहीं, लेकिन फिर भी सुंदर शटडाउन और स्वचालित विफलता के साथ बहुत मदद करता है - उदाहरण के लिए, प्रतिकृति दासों के स्वचालित विफलता प्रदर्शन करते समय क्लस्टरकंट्रोल इसका उपयोग करता है। आइए मान लें कि हमारे पास मामला है:जितना संभव हो सके पहुंच योग्य होने के लिए हमें (किसी भी) मास्टर की आवश्यकता है। यदि किसी कारण से (नेटवर्क विफलता, अधिकतम कनेक्शन पार हो गया है या कोई अन्य "विफलता" जो नए सत्र शुरू करने से मना करती है) तो हम अब आरडब्ल्यू संचालन के लिए मास्टर का उपयोग नहीं कर सकते हैं, हमारे पास एक फेलओवर क्लस्टर कॉन्फ़िगर किया गया है, जिसमें दास कनेक्शन स्वीकार कर सकते हैं। फिर हम एक गुलाम को बढ़ावा दे सकते हैं और उस पर असफल हो सकते हैं।

पहले मान लें कि हमारे पास तीन नोड हैं:

  • 10.1.10.124:5400 /pg/10/m के साथ (pgpool यहां भी घूमता है)
  • 10.1.10.147:5401 /pg/10/m2 के साथ
  • 10.1.10.124:5402 /pg/10/s2 के साथ

वे प्रभावी रूप से भाग एक के समान नोड हैं, लेकिन फ़ेलओवर नोड को एक अलग होस्ट और $PGDATA में ले जाया जाता है। मैंने यह सुनिश्चित करने के लिए किया था कि मैं रिमोट ssh कमांड में कुछ अतिरिक्त उद्धरण टाइप या भूल नहीं गया हूं। साथ ही डिबगिंग जानकारी सरल दिखेगी क्योंकि आईपी पते अलग हैं। अंत में मुझे यकीन नहीं था कि मैं इस असमर्थित उपयोग के मामले को काम करने में सक्षम कर पाऊंगा, इसलिए मुझे इसे अपनी आंखों से देखना होगा।

विफलता

पहले हम फेलओवर_कमांड सेट करते हैं और पीजीपूल रीलोड चलाते हैं और फेलओवर का प्रयास करते हैं। यहाँ और आगे, मैं pgpool सर्वर पर /tmp/d पर कुछ जानकारी प्रतिध्वनित करूँगा, ताकि मैं प्रवाह को देखने के लिए -f /tmp/d को टेल कर सकूं।

[email protected]:~$ grep failover_command /etc/pgpool2/pgpool.conf
failover_command = 'bash /pg/10/fo.sh %D %H %R'

[email protected]:~$ cat /pg/10/fo.sh
rem_cmd="pg_ctl -D $3 promote"
cmd="ssh -T [email protected]$2 $rem_cmd"
echo "$(date) $cmd" >>/tmp/d
$cmd &>>/tmp/d

एनबी:क्या आपके पास रिमोट होस्ट पर .bashrc में $PATH सेट है?...

आइए मास्टर को रोकें (मुझे पता है कि आपदा कैसे होती है, आप कम से कम कुछ विशाल बंदर या लाल चमकते रोबोट से सर्वर को एक बड़े हथौड़े से तोड़ देने की उम्मीद करते हैं, या कम से कम उबाऊ हार्ड डिस्क मरने के लिए, लेकिन मैं इस सुंदर का उपयोग कर रहा हूं pg_rewind के संभावित उपयोग को प्रदर्शित करने के लिए संस्करण, इसलिए यहां विफलता मानव त्रुटि या नेटवर्क विफलता का परिणाम health_check_period के आधे सेकंड में होगा), इसलिए:

/usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m stop
2018-04-18 13:53:55.469 IST [27433]  LOG:  received fast shutdown request
waiting for server to shut down....2018-04-18 13:53:55.478 IST [27433]  LOG:  aborting any active transactions
2018-04-18 13:53:55.479 IST [28855] postgres t FATAL:  terminating connection due to administrator command
2018-04-18 13:53:55.483 IST [27433]  LOG:  worker process: logical replication launcher (PID 27440) exited with exit code 1
2018-04-18 13:53:55.484 IST [27435]  LOG:  shutting down
2018-04-18 13:53:55.521 IST [27433]  LOG:  database system is shut down
 done
server stopped

अब फ़ेलओवर कमांड आउटपुट की जाँच:

[email protected]:~$ cat /tmp/d
Wed Apr 18 13:54:05 IST 2018 ssh -T [email protected]
pg_ctl -D /pg/10/f promote
waiting for server to promote.... done
server promoted

और थोड़ी देर बाद चेक करना:

t=# select nid,port,st, role from dblink('host=localhost port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int);
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | down | standby
   1 | 5401 | up   | primary
   2 | 5402 | up   | standby
(3 rows)

इसके अलावा हम पूर्व-विफलता क्लस्टर लॉग में देखते हैं:

2018-04-13 14:26:20.823 IST [20713]  LOG:  received promote request
2018-04-13 14:26:20.823 IST [20713]  LOG:  redo done at 0/951EC20
2018-04-13 14:26:20.823 IST [20713]  LOG:  last completed transaction was at log time 2018-04-13 10:41:54.355274+01
2018-04-13 14:26:20.872 IST [20713]  LOG:  selected new timeline ID: 2
2018-04-13 14:26:20.966 IST [20713]  LOG:  archive recovery complete
2018-04-13 14:26:20.998 IST [20712]  LOG:  database system is ready to accept connections

प्रतिकृति की जांच:

[email protected]:~$ psql -p 5401 t -c "select now() into test"
SELECT 1
[email protected]:~$ psql -p 5402 t -c "select * from test"
              now
-------------------------------
 2018-04-13 14:33:19.569245+01
(1 row)

गुलाम /pg/10/s2:5402 एक नई टाइमलाइन पर स्विच किया गया, जिसके लिए रिकवरी_टारगेट_टाइमलाइन =रिकवरी.कॉन्फ में नवीनतम धन्यवाद, इसलिए हम अच्छे हैं। हमें नए मास्टर को इंगित करने के लिए पुनर्प्राप्ति.कॉन्फ़ को समायोजित करने की आवश्यकता नहीं है, क्योंकि यह पीजीपूल आईपी और पोर्ट को इंगित करता है और वे वही रहते हैं जो प्राथमिक मास्टर भूमिका निभा रहा है।

लोड संतुलन की जाँच करना:

[email protected]:~$ (for i in $(seq 1 9); do psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1" -XAt; done) | sort| uniq -c
      6 5401
      3 5402

अच्छा। pgpool के पीछे के ऐप्स एक दूसरे आउटेज को नोटिस करेंगे और काम करना जारी रखेंगे।

पूर्व मास्टर का पुन:उपयोग करना

अब हम पूर्व-मास्टर को फ़ेलओवर स्टैंडबाय में बदल सकते हैं और इसे वापस ला सकते हैं (बिना कोई नया नोड जोड़े, क्योंकि यह पहले से मौजूद है)। यदि आपके पास wal_log_hints सक्षम या डेटा चेकसम नहीं है (इन विकल्पों के बीच व्यापक अंतर यहां है), तो आपको नई टाइमलाइन का पालन करने के लिए पूर्व-मास्टर पर क्लस्टर को फिर से बनाना होगा:

[email protected]:~$ rm -fr /pg/10/m
[email protected]:~$ pg_basebackup -h localhost -p 5401 -D /pg/10/m/

लेकिन ऊपर दिए गए बयानों को चलाने में जल्दबाजी न करें! यदि आपने wal_log_hints (पुनरारंभ करने की आवश्यकता है) का ध्यान रखा है, तो आप पूर्व-मास्टर के नए दास में बहुत तेज़ी से स्विच करने के लिए pg_rewind का उपयोग करने का प्रयास कर सकते हैं।

तो एटीएम हमारे पास पूर्व मास्टर ऑफ़लाइन है, अगली टाइमलाइन के साथ नया मास्टर शुरू हो गया है। यदि पूर्व-मास्टर अस्थायी नेटवर्क विफलता के कारण ऑफ़लाइन था और वह वापस आता है, तो हमें इसे पहले बंद करना होगा। ऊपर के मामले में हम जानते हैं कि यह नीचे है, इसलिए हम केवल रिवाइंड करने का प्रयास कर सकते हैं:

[email protected]:~$ pg_rewind -D /pg/10/m2 --source-server="port=5401 host=10.1.10.147"
servers diverged at WAL location 0/40605C0 on timeline 2
rewinding from last common checkpoint at 0/4060550 on timeline 2
Done!

और फिर:

[email protected]:~$ pg_ctl -D /pg/10/m2 start
server started
...blah blah 
[email protected]:~$ 2018-04-16 12:08:50.303 IST [24699]  LOG:  started streaming WAL from primary at 0/B000000 on timeline 2

t=# select nid,port,st,role from dblink('host=localhost port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int);
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | down | standby
   1 | 5401 | up   | primary
   2 | 5402 | up   | standby
(3 rows)

संचालन दुह! इस तथ्य के बावजूद कि पोर्ट 5400 पर क्लस्टर ऑनलाइन है और एक नई समयरेखा का अनुसरण करता है, हमें इसे पहचानने के लिए pgpool को बताना होगा:

[email protected]:~$ pcp_attach_node -w -h 127.0.0.1 -U vao -n 0
 pcp_attach_node  -- Command Successful

अब तीनों तैयार हैं (और pgpool इसे जानता है) और सिंक में हैं:

[email protected]:~$ sql="select ts.i::timestamp(0), current_setting('data_directory'),case when pg_is_in_recovery() then 'recovering' else 'mastering' end stream from ts order by ts desc"
[email protected]:~$ psql -h 10.1.10.147 -p 5401 t -c "$sql";
          i          | current_setting |  stream
---------------------+-----------------+-----------
 2018-04-30 14:34:36 | /pg/10/m2       | mastering
(1 row)

[email protected]:~$ psql -h 10.1.10.124 -p 5402 t -c "$sql";
          i          | current_setting |   stream
---------------------+-----------------+------------
 2018-04-30 14:34:36 | /pg/10/s2       | recovering
(1 row)

[email protected]:~$ psql -h 10.1.10.124 -p 5400 t -c "$sql";
          i          | current_setting |   stream
---------------------+-----------------+------------
 2018-04-30 14:34:36 | /pg/10/m        | recovering
(1 row)

अब मैं पूर्व-मास्टर का पुन:उपयोग करने के लिए पुनर्प्राप्ति_1st_stage_command का उपयोग करने का प्रयास करूंगा:

[email protected]:~# grep 1st /etc/pgpool2/pgpool.conf
recovery_1st_stage_command = 'or_1st.sh'

लेकिन पुनर्प्राप्ति_1st_stage_command pg_rewind के लिए आवश्यक तर्क प्रस्तुत नहीं करता है, जिसे मैं पुनर्प्राप्ति_1st_stage_command में जोड़ने पर देख सकता हूं:

echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4"; exit 1;

आउटपुट:

online recovery started on u2 2018-04-30 /pg/10/m2/or_1st.sh /pg/10/m2 10.1.10.124 /pg/10/m 5401

खैर - pg_rewind का उपयोग करना केवल कार्य सूची में है - मुझे क्या उम्मीद थी?.. तो मुझे मास्टर आईपी और पोर्ट प्राप्त करने के लिए कुछ बंदर हैक करने की ज़रूरत है (याद रखें कि यह विफलता के बाद बदलता रहेगा)।

आज श्वेतपत्र डाउनलोड करें क्लस्टरकंट्रोल के साथ पोस्टग्रेएसक्यूएल प्रबंधन और स्वचालन इस बारे में जानें कि पोस्टग्रेएसक्यूएल को तैनात करने, मॉनिटर करने, प्रबंधित करने और स्केल करने के लिए आपको क्या जानना चाहिए। श्वेतपत्र डाउनलोड करें

एक बंदर हैक

तो मेरे पास पुनर्प्राप्ति_1st_stage_command में कुछ ऐसा है:

[email protected]:~# cat /pg/10/or_1st.sh
pgpool_host=10.1.10.124
pgpool_port=5433
echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4" | ssh -T $pgpool_host "cat >> /tmp/d"
master_port=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select port from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role='primary'")
master_host=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select hostname from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role='primary'")
failover_host=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select hostname from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role!='primary' order by port limit 1")
src='"port=$master_port host=$master_host"'
rem_cmd="'pg_rewind -D $3 --source-server=\"port=$master_port host=$master_host\"'"
cmd="ssh -T $failover_host $rem_cmd"
echo $cmd | ssh -T $pgpool_host "cat >> /tmp/d"
$cmd

tmp=/tmp/rec_file_tmp
cat > $tmp <<EOF
standby_mode          = 'on'
primary_conninfo      = 'host=$master_host port=$master_port user=postgres'
trigger_file = '/tmp/tg_file'
recovery_target_timeline  = latest
EOF

scp $tmp $failover_host:$3/recovery.conf

rem_cmd="pg_ctl -D $3 start"
cmd="ssh -T $failover_host $rem_cmd"
echo $cmd | ssh -T $pgpool_host "cat >> /tmp/d"
$cmd
echo "OR finished $(date --iso-8601)" | ssh -T $pgpool_host "cat >> /tmp/d"
exit 0;

अब क्या गड़बड़ है! ठीक है - यदि आप मौजूदा सुविधा का उपयोग नहीं करने का निर्णय लेते हैं - तैयार करें - यह खराब लगेगा, बदतर काम करेगा और आपने जो किया उसके लिए आप स्थायी रूप से शर्मिंदा महसूस करेंगे। तो कदम दर कदम:

  • मुझे "पूल_नोड्स दिखाएं" क्वेरी करने और चरणों को लॉग करने और कमांड चलाने के लिए, इसे दूरस्थ रूप से कनेक्ट करने के लिए pgpool IP और पोर्ट की आवश्यकता है।
  • मैं कुछ dbg जानकारी को /tmp/d ssh पर पाइप कर रहा हूं, क्योंकि कमांड को मास्टर साइड पर निष्पादित किया जाएगा, जो विफल होने के बाद बदल जाएगा
  • मैं "शो पूल_नोड्स" के परिणाम का उपयोग चल रहे मास्टर कनेक्शन जानकारी को केवल WHERE क्लॉज के साथ फ़िल्टर करने के लिए कर सकता हूं
  • मुझे pg_rewind के लिए तर्क में दोहरे उद्धरण चिह्नों की आवश्यकता होगी, जिसे ssh पर चलाने की आवश्यकता होगी, इसलिए मैं केवल पठनीयता के लिए कमांड को विभाजित करता हूं, फिर इसे प्रतिध्वनित करता हूं और चलाता हूं
  • “शो पूल_नोड्स” से आउटपुट के आधार पर रिकवरी.कॉन्फ़ तैयार करना (इसे लिखकर मैं खुद से पूछता हूं - मैंने इसके बजाय सिर्फ पीजीपूल आईपी और पोर्ट का उपयोग क्यों नहीं किया?..
  • नया फेलओवर स्लेव शुरू करना (मुझे पता है कि मुझे दूसरे चरण का उपयोग करना चाहिए - सभी आईपी और पोर्ट को फिर से प्राप्त करने से बचने के लिए बस छोड़ दिया गया)

अब क्या बचा है - इस गड़बड़ी को पीसीपी में इस्तेमाल करने की कोशिश कर रहा हूं:

[email protected]:~# pcp_recovery_node -h 127.0.0.1 -U vao -n 0 -w
pcp_recovery_node -- Command Successful
[email protected]:~# psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port | st |  role
-----+------+----+---------
   0 | 5400 | up | standby
   1 | 5401 | up | primary
   2 | 5402 | up | standby
(3 rows)

pgpool सर्वर पर /tmp/d की जाँच करना:

[email protected]:~# cat /tmp/d
Tue May  1 11:37:59 IST 2018 ssh -T [email protected] /usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m2 promote
waiting for server to promote.... done
server promoted
online recovery started on u2 2018-05-01 /pg/10/m2/or_1st.sh /pg/10/m2
ssh -T 10.1.10.124 'pg_rewind -D --source-server="port=5401 host=10.1.10.147"'
ssh -T 10.1.10.124 pg_ctl -D start
OR finished 2018-05-01

अब स्पष्ट रूप से हम इसे फिर से रोल करना चाहते हैं यह देखने के लिए कि क्या यह किसी होस्ट पर काम करता है:

[email protected]:~$ ssh -T 10.1.10.147 pg_ctl -D /pg/10/m2 stop             waiting for server to shut down.... done
server stopped
[email protected]:~$ psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | up   | primary
   1 | 5401 | down | standby
   2 | 5402 | up   | standby
(3 rows)

[email protected]:~# pcp_recovery_node -h 127.0.0.1 -U vao -n 1 -w

[email protected]:~$ psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port | st |  role
-----+------+----+---------
   0 | 5400 | up | primary
   1 | 5401 | up | standby
   2 | 5402 | up | standby
(3 rows)

लॉग समान दिखता है - केवल आईपी और पोर्ट बदल गए हैं:

 Tue May  1 11:44:01 IST 2018 ssh -T [email protected] /usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m promote
waiting for server to promote.... done
server promoted
online recovery started on u 2018-05-01 /pg/10/m/or_1st.sh /pg/10/m 10.1.10.147 /pg/10/m2 5400
ssh -T 10.1.10.147 'pg_rewind -D /pg/10/m2 --source-server="port=5400 host=10.1.10.124"'
ssh -T 10.1.10.147 pg_ctl -D /pg/10/m2 start
online recovery started on u 2018-05-01 /pg/10/m/or_1st.sh /pg/10/m
ssh -T 10.1.10.147 'pg_rewind -D --source-server="port=5400 host=10.1.10.124"'
ssh -T 10.1.10.147 pg_ctl -D start
OR finished 2018-05-01

इस सैंडबॉक्स में, मास्टर फेलओवर पर 5401 पर चला गया और कुछ समय के लिए वहां रहने के बाद यह 5400 पर वापस चला गया। pg_rewind का उपयोग करके इसे यथासंभव तेज़ बनाना चाहिए। पहले स्वचालित विफलता का डरावना हिस्सा था - यदि आपने वास्तव में कॉन्फ़िगरेशन को गड़बड़ कर दिया है और कुछ बल की आशंका नहीं है, तो आप अगले दास के लिए स्वचालित विफलता में भाग सकते हैं और अगला और अगला जब तक कोई मुक्त दास नहीं छोड़ा जाता है। और उसके बाद, आप बस कई विभाजित दिमाग वाले मास्टर्स के साथ समाप्त होते हैं और कोई फ़ेलओवर अतिरिक्त नहीं होता है। ऐसे परिदृश्य में विफलता के लिए और भी अधिक दास होने के लिए यह एक खराब सांत्वना है, लेकिन pg_rewind के बिना आपके पास वह भी नहीं होगा। स्टैंडबाय बनाने के लिए "पारंपरिक" rsync या pg_basebackup सभी $PGDATA कॉपी करें, और "बहुत अधिक भिन्न नहीं" पूर्व मास्टर का पुन:उपयोग नहीं कर सकते।

इस प्रयोग के अंत में मैं एक बार फिर जोर देना चाहूंगा - यह ब्लाइंड कॉपी पेस्टिंग के लिए उपयुक्त समाधान नहीं है। pg_rewind के उपयोग को pg_pool के लिए प्रोत्साहित नहीं किया जाता है। यह सभी एटीएम में प्रयोग करने योग्य नहीं है। मैं pgpool HA कॉन्फ़िगरेशन में कुछ ताजी हवा जोड़ना चाहता था, मेरे जैसे न्यूब्स के लिए यह थोड़ा करीब से देखने के लिए कि यह कैसे काम करता है। कोरीफियस के लिए नैविस्टिक दृष्टिकोण पर मुस्कुराने के लिए और शायद इसे हमारी - न्यूब्स आँखों से देखें।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. एनएसआईएस के साथ पोस्टग्रेस्क्ल की स्थापना

  2. डेटटाइम ऑब्जेक्ट पर अलग-अलग टाइमज़ोन_टाइप्स

  3. PostgreSql 'PDOException' संदेश के साथ 'ड्राइवर नहीं मिल सका'

  4. विभिन्न चयन प्रश्नों के आउटपुट को वापस करने के लिए पीएल/पीजीएसक्यूएल फ़ंक्शन को दोबारा दोहराएं

  5. PG::त्रुटि:SELECT DISTINCT, ORDER BY एक्सप्रेशन चुनिंदा सूची में दिखना चाहिए