মাইএসকিউএল - যেখানে ক্ষেত্রটি নির্বাচন করুন (সাবকিউারি) - অত্যন্ত ধীর কেন?


133

আমি একটি ডাটাবেসে বেশ কয়েকটি নকল পেয়েছি যা আমি পরিদর্শন করতে চাই, তাই আমি যেগুলি সদলিপি ছিল তা দেখতে আমি কী করেছি:

SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1

এইভাবে, আমি প্রাসঙ্গিক_ফিল্ডে একাধিক বার সংঘটিত হওয়ার সাথে সমস্ত সারি পাব। এই ক্যোয়ারীটি কার্যকর করতে মিলিসেকেন্ড নেয়।

এখন, আমি প্রতিলিপিগুলির প্রত্যেকটি পরীক্ষা করতে চেয়েছিলাম, তাই আমি ভেবেছিলাম যে আমি উপরের ক্যোয়ারীতে প্রাসঙ্গিক_ফিল্ডের সাথে কিছু_ টেবিলের মধ্যে প্রতিটি সারি নির্বাচন করতে পারি, তাই আমি এটি পছন্দ করেছি:

SELECT *
FROM some_table 
WHERE relevant_field IN
(
    SELECT relevant_field
    FROM some_table
    GROUP BY relevant_field
    HAVING COUNT(*) > 1
)

এটি কোনও কারণে অতিমাত্রায় ধীর হয়ে উঠেছে (এটি কয়েক মিনিট সময় নেয়)। এটিকে ধীর করে দেওয়ার জন্য এখানে ঠিক কী চলছে? প্রাসঙ্গিক_ফিল্ড সূচকযুক্ত।

শেষ পর্যন্ত আমি প্রথম ক্যোয়ারী থেকে একটি "টেম্প_ভিউ" তৈরি করার চেষ্টা করেছি (SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1)এবং তারপরে আমার দ্বিতীয় ক্যোয়ারীটি এর পরিবর্তে তৈরি করার চেষ্টা করেছি:

SELECT *
FROM some_table
WHERE relevant_field IN
(
    SELECT relevant_field
    FROM temp_view
)

এবং এটি ঠিক কাজ করে। মাইএসকিউএল কিছু মিলিসেকেন্ডে এটি করে।

এখানে যে কোনও এসকিউএল বিশেষজ্ঞ কী হতে চলেছে তা ব্যাখ্যা করতে পারেন?


আপনি ঠিক কি চান? একটি ছাড়া ডুপ্লিকেট এন্ট্রি মুছতে চান ?? প্রস্তাবনা: অনুগ্রহ করে পড়ুন স্বয়ং যোগদান
diEcho

1
স্পষ্টতই গ্রুপ-বাই ধীরে ধীরে ...
আজ্রিয়াল

প্রথম ক্যোয়ারি মিলিসেকেন্ডে চালিত হয় (একটি গ্রুপিং এবং হাওয়িংয়ের সাথে ফিল্টারিং)। এটি কেবলমাত্র অন্যান্য ক্যোয়ারির সাথে মিলিত যা সবকিছু ধীরে ধীরে করে তোলে (এটি কয়েক মিনিট সময় নেয়)
কোয়ানো

@diEcho, আমি সদৃশগুলি খুঁজে পেতে, সেগুলি পরীক্ষা করতে এবং ম্যানুয়ালি কিছু মুছতে চাই।
কোয়ানো

উত্তর:


112

এটিতে ক্যোয়ারিকে পুনরায় লিখুন

SELECT st1.*, st2.relevant_field FROM sometable st1
INNER JOIN sometable st2 ON (st1.relevant_field = st2.relevant_field)
GROUP BY st1.id  /* list a unique sometable field here*/
HAVING COUNT(*) > 1

আমি মনে করি st2.relevant_fieldঅবশ্যই নির্বাচিত হতে হবে, কারণ অন্যথায় havingধারাটি একটি ত্রুটি দেবে, তবে আমি 100% নিশ্চিত নই

INএকটি subquery সঙ্গে ব্যবহার করবেন না; এটি কুখ্যাতভাবে ধীর।
কেবলমাত্র INমানগুলির একটি নির্দিষ্ট তালিকা সহ কখনও ব্যবহার করুন ।

আরও টিপস

  1. আপনি যদি প্রশ্নগুলি আরও দ্রুত করতে চান তবে SELECT *কেবলমাত্র আপনার প্রয়োজনীয় ক্ষেত্রগুলি নির্বাচন করবেন না ।
  2. relevant_fieldইক্যুই-জোড়কে গতি বাড়ানোর জন্য আপনার একটি সূচক রয়েছে তা নিশ্চিত করুন ।
  3. group byপ্রাথমিক কীতে নিশ্চিত হয়ে নিন ।
  4. আপনি যদি ইনোডিবিতে থাকেন এবং মাইএসকিউএল থেকে আপনি কেবল ইনডেক্স ক্ষেত্রগুলি (এবং জিনিসগুলি খুব জটিল নয়) নির্বাচন করেন তবে কেবল সূচকগুলি ব্যবহার করে আপনার ক্যোয়ারী সমাধান করবে, দ্রুতগতিতে জিনিসগুলি বাড়িয়ে তোলা হবে।

আপনার IN (select প্রশ্নের 90% সাধারণ সমাধান

এই কোডটি ব্যবহার করুন

SELECT * FROM sometable a WHERE EXISTS (
  SELECT 1 FROM sometable b
  WHERE a.relevant_field = b.relevant_field
  GROUP BY b.relevant_field
  HAVING count(*) > 1) 

1
আপনি এটি দিয়ে লিখতে পারেন HAVING COUNT(*) > 1। এটি সাধারণত মাইএসকিউএল এ দ্রুত হয়।
ypercubeᵀᴹ

নীচের ক্যোয়ারির জন্য সম্পন্ন @ টিউবারকিউব, আমি মনে করি শীর্ষ প্রশ্নের জন্য এটি ফলাফলকে পরিবর্তন করবে।
জোহান

@ জোহান: যেহেতু st2.relevant_fieldএটি নেই NULL(এটি ইতিমধ্যে ONক্লজের অন্তর্ভুক্ত ) তাই ফলাফলটি পরিবর্তন করবে না।
ypercubeᵀᴹ

@ টিউবকিউব, যাতে আপনি নিশ্চিত হন (আফিল্ড) কাউন্টে (*) যদি আপনি নিশ্চিত হন afieldযে কখনই হবে না null, পেয়ে গেছেন । ধন্যবাদ
জোহান

1
@ ক্যানো, হ্যাঁ এটি সমস্ত অনুলিপি তালিকাবদ্ধ করে কারণ group byচালু আছে st1.id, না st1.relevant_field
জোহান

110

সাবকোয়ারিটি প্রতিটি সারির জন্য চালানো হচ্ছে কারণ এটি একটি সম্পর্কিত প্রশ্ন। উপ-ক্ষেত্র থেকে সমস্ত কিছু নির্বাচন করে, কেউ একটি সম্পর্কিত নয় এমন প্রশ্নের সাথে একটি সম্পর্কিত সম্পর্কিত ক্যোয়ারী তৈরি করতে পারেন:

SELECT * FROM
(
    SELECT relevant_field
    FROM some_table
    GROUP BY relevant_field
    HAVING COUNT(*) > 1
) AS subquery

চূড়ান্ত ক্যোয়ারী এটির মতো দেখাবে:

SELECT *
FROM some_table
WHERE relevant_field IN
(
    SELECT * FROM
    (
        SELECT relevant_field
        FROM some_table
        GROUP BY relevant_field
        HAVING COUNT(*) > 1
    ) AS subquery
)

3
এটি আমার জন্য আশ্চর্যজনকভাবে ভাল কাজ করেছে। আইএন (সাবকোয়ারি) এর মধ্যে আমার আরও একটি আইএন (সাবকোয়ারি) ছিল এবং এটি 10 ​​মিনিটেরও বেশি সময় নিয়েছিল, আমি অপেক্ষা করতে করতে আমি এতক্ষণ গুগল করেছিলাম। প্রতিটি সাবকিউরিটি SELECT * FROM () এ মোড়ানো আপনার প্রস্তাবিত হিসাবে এটি 2 সেকেন্ডে কমিয়ে দেওয়া!
লিয়াম

ধন্যবাদ, আমি এখন কয়েক ঘন্টা ধরে এটি করার জন্য একটি ভাল উপায় বের করার চেষ্টা করছি। এটি পুরোপুরি কাজ করে। আশা করি আমি আপনাকে আরও উপার্জন দিতে পারতাম! এটি অবশ্যই উত্তর হওয়া উচিত।
থাপ্পিয়াস

পুরোপুরি কাজ করে। একটি ক্যোয়ারী যা চালাতে sec 50 সেকেন্ড নিয়েছে এখন তাত্ক্ষণিক। আশা করি আমি আরও উঁচু হতে পারে। কখনও কখনও আপনি যোগদান করতে পারবেন না তাই এটি সঠিক উত্তর।
সাইমন

আমি আশ্চর্য হয়েছি কেন অপ্টিমাইজার ইউনিয়নগুলির সাথে কোয়েরিগুলি সম্পর্কিত বলে বিবেচনা করে ... যাইহোক, এই কৌশলটি যাদুটির মতো কাজ করেছিল
ব্রায়ান

2
আপনি কি দয়া করে ব্যাখ্যা করতে পারেন যে এটি একটি পরস্পর সম্পর্কিত subquery হয়? বাহ্যিক ক্যোয়ারীর উপর নির্ভর করে এমন কোনও মান ব্যবহার করা হলে আমার বোঝা যাচ্ছে যে সাবকিউরিটি সম্পর্কযুক্ত হয়। তবে এই উদাহরণে আমি কোনও আন্তঃনির্ভরতা দেখতে পাচ্ছি না। এটি বাইরের ক্যোয়ারী দ্বারা প্রত্যাবর্তিত প্রতিটি সারির জন্য একই ফলাফল দিতে চাই। আমার একই রকম উদাহরণটি মারিয়াডিবিতে প্রয়োগ করা হচ্ছে এবং আমি কোনও পারফরম্যান্স হিট দেখতে পাচ্ছি না (এখনও অবধি), সুতরাং আমি পরিষ্কারভাবে দেখতে চাই, যখন এই SELECT *মোড়ানো প্রয়োজন হয়।
sbnc.eu

6

আমি এই জাতীয় কিছু সন্দেহ করেছিলাম যে প্রতিটি সারিতে সাবকোয়ারি চালানো হচ্ছে।
কোয়ানো

কিছু মাইএসকিউএল সংস্করণ এমনকি ইন ইনডেক্স ব্যবহার করে না। আমি আর একটি লিঙ্ক যুক্ত করেছি।
এডিজ

1
মাইএসকিউএল 6 এখনও স্থিতিশীল নয়, আমি উত্পাদনের জন্য এটি প্রস্তাব দেব না!
জোহান

1
আমি এটি সুপারিশ করব না। তবে এটি ব্যাখ্যা করা হয় কীভাবে এটি অভ্যন্তরীণভাবে চালিত হয় (4.1 / 5.x -> 6)। এটি বর্তমান সংস্করণগুলির কিছু ক্ষতি দেখায়।

5
SELECT st1.*
FROM some_table st1
inner join 
(
    SELECT relevant_field
    FROM some_table
    GROUP BY relevant_field
    HAVING COUNT(*) > 1
)st2 on st2.relevant_field = st1.relevant_field;

আমি আমার ডেটাবেসগুলির একটিতে আপনার জিজ্ঞাসাটি চেষ্টা করেছি এবং এটি একটি সাব-কোয়েরিতে যোগদান হিসাবে পুনরায় লেখার চেষ্টা করেছি।

এটি অনেক দ্রুত কাজ করেছে, চেষ্টা করে দেখুন!


হ্যাঁ, এটি সম্ভবত গোষ্ঠীর ফলাফলগুলি সহ একটি টেম্প টেবিল তৈরি করবে, সুতরাং এটি দেখার সংস্করণ হিসাবে একই গতি হবে। তবে ক্যোয়ারী পরিকল্পনাগুলি সত্য বলা উচিত tell
ypercubeᵀᴹ

3

এটা চেষ্টা কর

SELECT t1.*
FROM 
 some_table t1,
  (SELECT relevant_field
  FROM some_table
  GROUP BY relevant_field
  HAVING COUNT (*) > 1) t2
WHERE
 t1.relevant_field = t2.relevant_field;

2

আমি আপনার ধীর এসকিএল কোয়েরিটি www. ব্যাখ্যাtysql.net এর সাথে পুনরায় ফর্ম্যাট করেছি

SELECT *
FROM some_table
WHERE
 relevant_field in
 (
  SELECT relevant_field
  FROM some_table
  GROUP BY relevant_field
  HAVING COUNT ( * ) > 1
 );

কোয়েরি এবং সাবকোয়ারি উভয় ক্ষেত্রে একটি সারণী ব্যবহার করার সময়, আপনাকে সর্বদা উভয়রূপে এইরকম হওয়া উচিত:

SELECT *
FROM some_table as t1
WHERE
 t1.relevant_field in
 (
  SELECT t2.relevant_field
  FROM some_table as t2
  GROUP BY t2.relevant_field
  HAVING COUNT ( t2.relevant_field ) > 1
 );

এটা কি সাহায্য করে?


1
দুর্ভাগ্যক্রমে এটি সাহায্য করে না। এটি ঠিক ধীরভাবে কার্যকর করে।
কোয়ানো

আমি আমার উত্তর আপডেট করেছি, আপনি আবার চেষ্টা করতে পারেন? এমনকি গোষ্ঠীটি ধীর গতিতে থাকলেও এটি কেবল একবার কার্যকর করা উচিত ...

আমি গতবার দুর্ঘটনাক্রমে একটি লাইভ মাইএসকিএল সার্ভারটি হত্যা করেছি, তাই আমি আশঙ্কা করছি যে আমি এখনই এটি চেষ্টা করতে পারছি না। আমি পরে একটি পরীক্ষা ডাটাবেস সেট আপ করতে হবে। তবে কেন এই প্রশ্নটি প্রভাবিত করবে তা আমি বুঝতে পারি না। হ্যাভিং স্টেটমেন্টটি কেবলমাত্র এটির মধ্যে থাকা কোয়েরিতে প্রয়োগ করা উচিত, তাই না? "সত্যিকারের" ক্যোয়ারীটি সাবকিউরিতে কেন প্রভাব ফেলবে তা আমি সত্যিই বুঝতে পারি না।
কোয়ানো

আমি এটি পেয়েছি: xaprb.com/blog/2006/04/30/… । আমি মনে করি এটিই সমাধান হতে পারে। সময় পেলে চেষ্টা করব।
কোয়ানো

2

প্রথমত আপনি নকল সারিগুলি খুঁজে পেতে এবং সারিগুলির গণনা কতবার ব্যবহৃত হয় তা খুঁজে পেতে এবং এটির মতো সংখ্যায় এটি অর্ডার করতে পারেন;

SELECT q.id,q.name,q.password,q.NID,(select count(*) from UserInfo k where k.NID= q.NID) as Count,
(
		CASE q.NID
		WHEN @curCode THEN
			@curRow := @curRow + 1
		ELSE
			@curRow := 1
		AND @curCode := q.NID
		END
	) AS No
FROM UserInfo q,
(
		SELECT
			@curRow := 1,
			@curCode := ''
	) rt
WHERE q.NID IN
(
    SELECT NID
    FROM UserInfo
    GROUP BY NID
    HAVING COUNT(*) > 1
) 

এর পরে একটি টেবিল তৈরি করুন এবং এতে ফলাফল .োকান।

create table CopyTable 
SELECT q.id,q.name,q.password,q.NID,(select count(*) from UserInfo k where k.NID= q.NID) as Count,
(
		CASE q.NID
		WHEN @curCode THEN
			@curRow := @curRow + 1
		ELSE
			@curRow := 1
		AND @curCode := q.NID
		END
	) AS No
FROM UserInfo q,
(
		SELECT
			@curRow := 1,
			@curCode := ''
	) rt
WHERE q.NID IN
(
    SELECT NID
    FROM UserInfo
    GROUP BY NID
    HAVING COUNT(*) > 1
) 

পরিশেষে, প্রজাতন্ত্র সারিগুলি মুছুন 0. এখন শুরু হয় না 0. প্রতিটি গ্রুপের মুষ্টি সংখ্যা বাদে সমস্ত প্রজাতন্ত্র সারি মুছুন।

delete from  CopyTable where No!= 0;


1

কখনও কখনও যখন ডেটা বড় মাইএসকিএল বৃদ্ধি পায় যেখানে কোয়েরি অপ্টিমাইজেশনের কারণে খুব ধীর হতে পারে। যেমন কোয়েরি কার্যকর করার জন্য মাইএসকিএলকে বলতে স্ট্র্যাটাইট_জোঁট ব্যবহার করে চেষ্টা করুন

SELECT STRAIGHT_JOIN table.field FROM table WHERE table.id IN (...)

তবে সাবধান থাকুন: বেশিরভাগ ক্ষেত্রে মাইএসকিএল অপ্টিমাইজারটি বেশ ভালভাবে কাজ করে, তাই আমি যখন আপনার এই ধরণের সমস্যা হয় কেবল তখনই এটি ব্যবহার করার পরামর্শ দেব would


0

এটি আমার ক্ষেত্রে সাদৃশ্য, যেখানে আমার একটি টেবিল রয়েছে tabel_buku_besar। আমার যা দরকার তা হ'ল

  1. রেকর্ড জন্যে আছে account_code='101.100'মধ্যে tabel_buku_besarযা আছে companyarea='20000'এবং আছে IDRযেমনcurrency

  2. আমার সমস্ত রেকর্ড পেতে হবে tabel_buku_besarযা থেকে অ্যাকাউন্ট_কোড ধাপ 1 এর সমান তবে transaction_number1 ধাপে ফলাফল রয়েছে

ব্যবহার করার সময় select ... from...where....transaction_number in (select transaction_number from ....), আমার কোয়েরিটি অত্যন্ত ধীর হয়ে চলছে এবং কখনও কখনও অনুরোধের সময় শেষ করে দেয় বা আমার অ্যাপ্লিকেশনটি সাড়া না দেয় ...

আমি এই সংমিশ্রণটি চেষ্টা করেছি এবং ফলাফলটি ... খারাপ নয় ...

`select DATE_FORMAT(L.TANGGAL_INPUT,'%d-%m-%y') AS TANGGAL,
      L.TRANSACTION_NUMBER AS VOUCHER,
      L.ACCOUNT_CODE,
      C.DESCRIPTION,
      L.DEBET,
      L.KREDIT 
 from (select * from tabel_buku_besar A
                where A.COMPANYAREA='$COMPANYAREA'
                      AND A.CURRENCY='$Currency'
                      AND A.ACCOUNT_CODE!='$ACCOUNT'
                      AND (A.TANGGAL_INPUT BETWEEN STR_TO_DATE('$StartDate','%d/%m/%Y') AND STR_TO_DATE('$EndDate','%d/%m/%Y'))) L 
INNER JOIN (select * from tabel_buku_besar A
                     where A.COMPANYAREA='$COMPANYAREA'
                           AND A.CURRENCY='$Currency'
                           AND A.ACCOUNT_CODE='$ACCOUNT'
                           AND (A.TANGGAL_INPUT BETWEEN STR_TO_DATE('$StartDate','%d/%m/%Y') AND STR_TO_DATE('$EndDate','%d/%m/%Y'))) R ON R.TRANSACTION_NUMBER=L.TRANSACTION_NUMBER AND R.COMPANYAREA=L.COMPANYAREA 
LEFT OUTER JOIN master_account C ON C.ACCOUNT_CODE=L.ACCOUNT_CODE AND C.COMPANYAREA=L.COMPANYAREA 
ORDER BY L.TANGGAL_INPUT,L.TRANSACTION_NUMBER`

0

আমি এটির সন্ধান করার জন্য সবচেয়ে কার্যকর বলে মনে করি যে কোনও মান বিদ্যমান থাকলে লজিক সহজেই উল্টানো যায় যদি কোনও মান বিদ্যমান না থাকে (যেমন IS NULL);

SELECT * FROM primary_table st1
LEFT JOIN comparision_table st2 ON (st1.relevant_field = st2.relevant_field)
WHERE st2.primaryKey IS NOT NULL

* আপনার টেবিলে থাকা মানটির নামের সাথে প্রাসঙ্গিক_ফিল্ডটি প্রতিস্থাপন করুন

* তুলনা টেবিলের প্রাথমিক কী কলামের নাম দিয়ে প্রাথমিককে প্রতিস্থাপন করুন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.