ISNULL () প্রতিস্থাপনের বিভিন্ন উপায়ে কীভাবে এমন শর্তে কেবল আক্ষরিক মান ব্যবহার করা হয়?


55

এটি কি সম্পর্কে নয়:

এটি ক্যাচ-সমস্ত প্রশ্নের সম্পর্কে নয় যা ব্যবহারকারীর ইনপুট গ্রহণ করে বা ভেরিয়েবল ব্যবহার করে।

এই প্রশ্নের যেখানে সম্পর্কে কঠোরভাবে হয় ISNULL()ব্যবহার করা হয় WHEREদফা প্রতিস্থাপন করতে NULLএকটি বিধেয় তুলনায় জন্য একটি হলদে মান মান, এবং যারা প্রশ্নের পুনর্লিখন হতে বিভিন্ন উপায়ে SARGable SQL সার্ভার হবে।

তোমার ওখানে সিট নেই কেন?

আমাদের উদাহরণ ক্যোয়ারী এসকিউএল সার্ভার 2016 এর স্ট্যাক ওভারফ্লো ডেটাবেজের স্থানীয় অনুলির বিরুদ্ধে এবং একটি NULLবয়সের বা <18 বছর বয়সী ব্যবহারকারীদের সন্ধান করে ।

SELECT COUNT(*)
FROM dbo.Users AS u
WHERE ISNULL(u.Age, 17) < 18;

ক্যোয়ারী পরিকল্পনাটি যথেষ্ট চিন্তাশীল অবিচ্ছিন্ন সূচকগুলির একটি স্ক্যান দেখায়।

বাদাম

স্ক্যান অপারেটর দেখায় (এসকিউএল সার্ভারের আরও সাম্প্রতিক সংস্করণগুলিতে এক্সএমএল প্রকৃত বাস্তবায়ন পরিকল্পনার সংযোজনগুলির জন্য ধন্যবাদ) যা আমরা প্রতিটি দুর্ঘটনার সারি পড়ি।

বাদাম

সামগ্রিকভাবে, আমরা 9157 পড়ি এবং সিপিইউ সময়ের প্রায় অর্ধেক সেকেন্ড ব্যবহার করি:

Table 'Users'. Scan count 1, logical reads 9157, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 485 ms,  elapsed time = 483 ms.

প্রশ্ন: এই ক্যোয়ারীটিকে আরও দক্ষ করে তোলার জন্য এবং সম্ভবত এসএআরজেবলকে পুনরায় লেখার কী কী উপায় রয়েছে?

অন্য পরামর্শ প্রস্তাব নির্দ্বিধায়। আমি মনে করি না আমার উত্তর অগত্যা হয় উত্তর, এবং সেখানে সেখানে আউট যথেষ্ট স্মার্ট মানুষ বিকল্প যে ভাল হতে পারে নিয়ে আসা হয়।

আপনি যদি নিজের কম্পিউটারে খেলতে চান তবে এসও ডাটাবেস ডাউনলোড করতে এখানে যান ।

ধন্যবাদ!

উত্তর:


57

উত্তর বিভাগ

বিভিন্ন টি-এসকিউএল কনস্ট্রাক্টস ব্যবহার করে এটি পুনরায় লেখার বিভিন্ন উপায় রয়েছে। আমরা উপকারিতা এবং নীতিগুলি দেখুন এবং নীচে একটি সামগ্রিক তুলনা করব।

প্রথম আপ : ব্যবহারOR

SELECT COUNT(*)
FROM dbo.Users AS u
WHERE u.Age < 18
OR u.Age IS NULL;

ব্যবহারের ফলে ORআমাদের আরও কার্যকর সিক প্ল্যান দেয়, যা আমাদের প্রয়োজনীয় সারিগুলির সঠিক সংখ্যাটি পড়ে, তবে এটি প্রযুক্তি সম্পর্কিত বিশ্বকে a whole mess of malarkeyকোয়েরি পরিকল্পনায় ডাকে ।

বাদাম

এছাড়াও লক্ষ করুন যে সিক এখানে দু'বার মৃত্যুদন্ড কার্যকর করা হয়েছে যা গ্রাফিকাল অপারেটর থেকে সত্যই আরও স্পষ্ট হওয়া উচিত:

বাদাম

Table 'Users'. Scan count 2, logical reads 8233, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 469 ms,  elapsed time = 473 ms.

সেকেন্ড আপ : UNION ALL আমাদের ক্যোয়ারীর সাহায্যে উত্সযুক্ত টেবিলগুলি ব্যবহার করেও এটি আবার লিখিত যেতে পারে

SELECT SUM(Records)
FROM 
(
    SELECT COUNT(Id)
    FROM dbo.Users AS u
    WHERE u.Age < 18

    UNION ALL

    SELECT COUNT(Id)
    FROM dbo.Users AS u
    WHERE u.Age IS NULL
) x (Records);

এটি একই ধরণের পরিকল্পনার ফলস্বরূপ, কম কম ম্যালার্কি সহ এবং সূচকটি কতবার চাওয়া হয়েছে (চাওয়া?) তার সম্পর্কে আরও স্পষ্টতই সততা অর্জন করা।

বাদাম

এটি ORক্যোয়ারির সমান পরিমাণ পাঠ (8233) করে তবে প্রায় 100 মিমি সিপিইউ সময় বন্ধ করে দেয়।

CPU time = 313 ms,  elapsed time = 315 ms.

তবে আপনাকে এখানে সত্যিই সতর্ক হতে হবে , কারণ এই পরিকল্পনাটি যদি সমান্তরাল হওয়ার চেষ্টা করে তবে দুটি পৃথক COUNTক্রিয়াকলাপ সিরিয়ালায়িত হবে, কারণ তারা প্রত্যেকে বিশ্বব্যাপী স্কেলার সমষ্টি হিসাবে বিবেচিত হয়। আমরা যদি ট্রেস ফ্ল্যাগ 8649 ব্যবহার করে একটি সমান্তরাল পরিকল্পনা জোর করি তবে সমস্যাটি সুস্পষ্ট হয়ে যায়।

SELECT SUM(Records)
FROM 
(
    SELECT COUNT(Id)
    FROM dbo.Users AS u
    WHERE u.Age < 18

    UNION ALL

    SELECT COUNT(Id)
    FROM dbo.Users AS u
    WHERE u.Age IS NULL
) x (Records)
OPTION(QUERYTRACEON 8649);

বাদাম

আমাদের ক্যোয়ারিটি কিছুটা পরিবর্তন করে এড়ানো যায়।

SELECT SUM(Records)
FROM 
(
    SELECT 1
    FROM dbo.Users AS u
    WHERE u.Age < 18

    UNION ALL

    SELECT 1
    FROM dbo.Users AS u
    WHERE u.Age IS NULL
) x (Records)   
OPTION(QUERYTRACEON 8649);

এখন সিকের জন্য সম্পাদনা করা উভয় নোড পুরোপুরি সমান্তরাল হয় যতক্ষণ না আমরা কনকেশনেশন অপারেটরটিকে আঘাত করি।

বাদাম

এটি মূল্যবান কিসের জন্য, সম্পূর্ণ সমান্তরাল সংস্করণটির কিছু ভাল সুবিধা রয়েছে। আরও প্রায় 100 টি পঠন এবং 90 মিলিয়ন অতিরিক্ত সিপিইউয়ের সময় ব্যয় করা সময়টি 93 এমএসে সঙ্কুচিত হয়।

Table 'Users'. Scan count 12, logical reads 8317, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 500 ms,  elapsed time = 93 ms.

ক্রস আবেদন সম্পর্কে কি? এর জাদু ছাড়া কোনও উত্তরই সম্পূর্ণ নয় CROSS APPLY!

দুর্ভাগ্যক্রমে, আমরা আরও সমস্যায় পড়েছি COUNT

SELECT SUM(Records)
FROM dbo.Users AS u 
CROSS APPLY 
(
    SELECT COUNT(Id)
    FROM dbo.Users AS u2 
    WHERE u2.Id = u.Id
    AND u2.Age < 18

    UNION ALL

    SELECT COUNT(Id)
    FROM dbo.Users AS u2 
    WHERE u2.Id = u.Id 
    AND u2.Age IS NULL
) x (Records);

এই পরিকল্পনাটি ভয়াবহ। আপনি যখন সেন্ট প্যাট্রিক্স ডে শেষ দেখবেন তখন এই জাতীয় পরিকল্পনার সমাপ্তি ঘটে। সুন্দরভাবে সমান্তরাল হলেও কিছু কারণে এটি পিকে / সিএক্স স্ক্যান করছে। ইডব্ল্যু। এই পরিকল্পনার 2198 টি ক্যোয়ারী টাকা রয়েছে has

বাদাম

Table 'Users'. Scan count 7, logical reads 31676233, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 29532 ms,  elapsed time = 5828 ms.

যা একটি অদ্ভুত পছন্দ, কারণ যদি আমরা এটি অবিবাহিত সূচকটি ব্যবহার করতে বাধ্য করি তবে ব্যয়টি উল্লেখযোগ্যভাবে 1798 কোয়েরি বাক্সে নেমে আসে।

SELECT SUM(Records)
FROM dbo.Users AS u 
CROSS APPLY 
(
    SELECT COUNT(Id)
    FROM dbo.Users AS u2 WITH (INDEX(ix_Id_Age))
    WHERE u2.Id = u.Id
    AND u2.Age < 18

    UNION ALL

    SELECT COUNT(Id)
    FROM dbo.Users AS u2 WITH (INDEX(ix_Id_Age))
    WHERE u2.Id = u.Id 
    AND u2.Age IS NULL
) x (Records);

আরে, সন্ধান! আপনি সেখানে পরীক্ষা করে দেখুন। এছাড়াও লক্ষ করুন যে এর CROSS APPLYযাদুটির সাথে, বেশিরভাগ সম্পূর্ণ সমান্তরাল পরিকল্পনা করার জন্য আমাদের বোকা কিছু করার দরকার নেই।

বাদাম

Table 'Users'. Scan count 5277838, logical reads 31685303, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 27625 ms,  elapsed time = 4909 ms.

ক্রস অ্যাপ্লিকেশন COUNTসেখানে স্টাফ ছাড়াই ফোরিং ভাল শেষ হয়।

SELECT SUM(Records)
FROM dbo.Users AS u
CROSS APPLY 
(
    SELECT 1
    FROM dbo.Users AS u2
    WHERE u2.Id = u.Id
    AND u2.Age < 18

    UNION ALL

    SELECT 1
    FROM dbo.Users AS u2
    WHERE u2.Id = u.Id 
    AND u2.Age IS NULL
) x (Records);

পরিকল্পনাটি দেখতে দুর্দান্ত, তবে পঠন এবং সিপিইউ কোনও উন্নতি নয়।

বাদাম

Table 'Users'. Scan count 20, logical reads 17564, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 4844 ms,  elapsed time = 863 ms.

ক্রসটি পুনরায় লেখালেখি হ'ল উদ্ভূত যুক্ত হওয়ার জন্য প্রয়োগ করা হয় ঠিক একই জিনিসটিতে। আমি ক্যোয়ারী পরিকল্পনা এবং পরিসংখ্যান তথ্য পুনরায় পোস্ট করতে যাচ্ছি না - সেগুলি সত্যিই পরিবর্তন হয়নি।

SELECT COUNT(u.Id)
FROM dbo.Users AS u
JOIN 
(
    SELECT u.Id
    FROM dbo.Users AS u
    WHERE u.Age < 18

    UNION ALL

    SELECT u.Id
    FROM dbo.Users AS u
    WHERE u.Age IS NULL
) x ON x.Id = u.Id;

রিলেশনাল বীজগণিত : পুরোপুরি হয়ে উঠতে এবং জো সেলকোকে আমার স্বপ্নগুলি ঘৃণা থেকে বিরত রাখতে আমাদের কমপক্ষে কিছু অদ্ভুত সম্পর্কযুক্ত জিনিস চেষ্টা করা দরকার। এখানেও যায় না '!

সঙ্গে একটি প্রচেষ্টা INTERSECT

SELECT COUNT(*)
FROM dbo.Users AS u
WHERE NOT EXISTS ( SELECT u.Age WHERE u.Age >= 18
                   INTERSECT
                   SELECT u.Age WHERE u.Age IS NOT NULL );

বাদাম

Table 'Users'. Scan count 1, logical reads 9157, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 1094 ms,  elapsed time = 1090 ms.

এবং এখানে একটি প্রচেষ্টা আছে EXCEPT

SELECT COUNT(*)
FROM dbo.Users AS u
WHERE NOT EXISTS ( SELECT u.Age WHERE u.Age >= 18
                   EXCEPT
                   SELECT u.Age WHERE u.Age IS NULL);

বাদাম

Table 'Users'. Scan count 7, logical reads 9247, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2126 ms,  elapsed time = 376 ms.

এগুলি লেখার অন্যান্য উপায়ও থাকতে পারে তবে আমি এগুলি এমন লোকদের মধ্যে রেখে দেব যারা সম্ভবত আমার চেয়ে বেশি ব্যবহার করে EXCEPTএবং INTERSECTপ্রায়শই ব্যবহার করে ।

আপনার যদি সত্যিইCOUNT আমার শঙ্কার কিছুটা হিসাবে আমার প্রশ্নগুলিতে ব্যবহার করার মতো একটি গণনা প্রয়োজন (পড়ুন: আমি কখনও কখনও আরও জড়িত পরিস্থিতিগুলির সাথে আসতে পারি না)। আপনার যদি কেবল একটি গণনা প্রয়োজন, আপনি CASEএকই জিনিসটি করতে কেবল একটি এক্সপ্রেশন ব্যবহার করতে পারেন ।

SELECT SUM(CASE WHEN u.Age < 18 THEN 1
                WHEN u.Age IS NULL THEN 1
                ELSE 0 END) 
FROM dbo.Users AS u

SELECT SUM(CASE WHEN u.Age < 18 OR u.Age IS NULL THEN 1
                ELSE 0 END) 
FROM dbo.Users AS u

এই উভয় একই পরিকল্পনা পান এবং একই সিপিইউ রয়েছে এবং পড়ার বৈশিষ্ট্য রয়েছে।

বাদাম

Table 'Users'. Scan count 1, logical reads 9157, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 719 ms,  elapsed time = 719 ms.

বিজয়ী? আমার পরীক্ষাগুলিতে, উত্পন্ন টেবিলের উপর এসইউমের সাথে বাধ্যতামূলক সমান্তরাল পরিকল্পনাটি সর্বোত্তমভাবে সম্পাদন করেছিল। এবং হ্যাঁ, উভয় পূর্বাভাসের জন্য অ্যাকাউন্টে দু'টি ফিল্টার সূচক যুক্ত করে এই প্রশ্নের অনেকগুলিই সহায়তা করা যেতে পারে, তবে আমি কিছু পরীক্ষা অন্যের কাছে রেখে যেতে চেয়েছিলাম।

SELECT SUM(Records)
FROM 
(
    SELECT 1
    FROM dbo.Users AS u
    WHERE u.Age < 18

    UNION ALL

    SELECT 1
    FROM dbo.Users AS u
    WHERE u.Age IS NULL
) x (Records)   
OPTION(QUERYTRACEON 8649);

ধন্যবাদ!


1
NOT EXISTS ( INTERSECT / EXCEPT )প্রশ্নের ছাড়া কাজ করবো INTERSECT / EXCEPTঅংশ: WHERE NOT EXISTS ( SELECT u.Age WHERE u.Age >= 18 );আরেকটি উপায় - ব্যবহার করে EXCEPT: SELECT COUNT(*) FROM (SELECT UserID FROM dbo.Users EXCEPT SELECT UserID FROM dbo.Users WHERE u.Age >= 18) AS u ; (যেখানে আইডি পি কে বা কোন অনন্য নয় নাল কলাম (গুলি) যায়)।
ypercubeᵀᴹ

এটি পরীক্ষা করা হয়েছিল? SELECT result = (SELECT COUNT(*) FROM dbo.Users AS u WHERE u.Age < 18) + (SELECT COUNT(*) FROM dbo.Users AS u WHERE u.Age IS NULL) ;আপনি পরীক্ষিত মিলিয়ন সংস্করণগুলি যদি আমি মিস করি তবে দুঃখিত!
ypercubeᵀᴹ

@ ইয়পারক्यूब ᵀᴹ এর জন্য পরিকল্পনা এখানে । এটি কিছুটা আলাদা, তবে UNION ALLপরিকল্পনাগুলির সাথে একই বৈশিষ্ট্য রয়েছে (360 মিমি সিপিইউ, 11 কে পড়ে)।
এরিক ডার্লিং

আরে, এরিক সিক্যুয়াল বিশ্ব জুড়ে ছিল এবং আপনাকে বিরক্ত করতে "গণিত কলাম" বলতে পপ করেছিল। <3
ক্রুশেবল

17

আমি কেবল একটি টেবিলের জন্য একটি 110 গিগাবাইট ডাটাবেস পুনরুদ্ধার করতে খেলিনি তাই আমি নিজের ডেটা তৈরি করেছি । বয়স বিতরণ স্ট্যাক ওভারফ্লোতে যা আছে তা মিলবে তবে স্পষ্টতই টেবিলটি মেলে না। আমি মনে করি না যে এটি একটি খুব বেশি সমস্যার কারণ প্রশ্নগুলি যেভাবেই সূচকগুলিতে আঘাত হানে। আমি এসকিউএল সার্ভার 2016 এসপি 1 দিয়ে একটি 4 সিপিইউ কম্পিউটারে পরীক্ষা করছি। একটি বিষয় লক্ষণীয় হ'ল যে প্রশ্নগুলির জন্য এটি দ্রুত শেষ হয় এটি প্রকৃত বাস্তবায়ন পরিকল্পনাটি অন্তর্ভুক্ত না করা গুরুত্বপূর্ণ। এটি জিনিসকে কিছুটা কমিয়ে দিতে পারে।

এরিকের দুর্দান্ত উত্তরের কয়েকটি সমাধানের মধ্য দিয়ে শুরু করেছিলাম। এটির জন্য:

SELECT SUM(Records)
FROM 
(
    SELECT COUNT(Id)
    FROM dbo.Users AS u
    WHERE u.Age < 18

    UNION ALL

    SELECT COUNT(Id)
    FROM dbo.Users AS u
    WHERE u.Age IS NULL
) x (Records);

আমি sys.dm_exec_sessions থেকে 10 টিরও বেশি পরীক্ষার (নীচে কোয়েরিটি স্বাভাবিকভাবে আমার জন্য সমান্তরাল হয়ে উঠেছে) থেকে নিম্নলিখিত ফলাফল পেয়েছি :

╔══════════╦════════════════════╦═══════════════╗
 cpu_time  total_elapsed_time  logical_reads 
╠══════════╬════════════════════╬═══════════════╣
     3532                 975          60830 
╚══════════╩════════════════════╩═══════════════╝

এরিকের জন্য আরও ভাল কাজ করা ক্যোয়ারীটি আসলে আমার মেশিনে আরও খারাপ অভিনয় করেছে:

SELECT SUM(Records)
FROM 
(
    SELECT 1
    FROM dbo.Users AS u
    WHERE u.Age < 18

    UNION ALL

    SELECT 1
    FROM dbo.Users AS u
    WHERE u.Age IS NULL
) x (Records)   
OPTION(QUERYTRACEON 8649);

10 ট্রায়াল থেকে ফলাফল:

╔══════════╦════════════════════╦═══════════════╗
 cpu_time  total_elapsed_time  logical_reads 
╠══════════╬════════════════════╬═══════════════╣
     5704                1636          60850 
╚══════════╩════════════════════╩═══════════════╝

কেন এটি খারাপ, আমি তাৎক্ষণিকভাবে ব্যাখ্যা করতে সক্ষম নই, তবে কেন আমরা ক্যোয়ারী পরিকল্পনার প্রায় প্রতিটি অপারেটরকে সমান্তরালে যেতে বাধ্য করতে চাই তা স্পষ্ট নয়। মূল পরিকল্পনায় আমাদের একটি ক্রমিক অঞ্চল রয়েছে যা সমস্ত সারি খুঁজে পায় AGE < 18। কয়েক হাজার সারি রয়েছে। আমার মেশিনে আমি ক্যোয়ারির সেই অংশটির জন্য 9 টি লজিক্যাল রিড পেয়েছি এবং 9 মিটার রিপোর্ট করা সিপিইউ সময় এবং সময় কাটিয়েছি। সারিগুলির জন্য বিশ্বব্যাপী সমষ্টিগুলির জন্য একটি সিরিয়াল অঞ্চলও রয়েছে AGE IS NULLতবে এটি কেবল ডওপি প্রতি একটি সারি প্রক্রিয়াকরণ করে। আমার মেশিনে এটি কেবল চারটি সারি।

আমার takeaway হয় এটি ক্যোয়ারী করে একটি সঙ্গে সারি খুঁজে বের করে অংশ নিখুত সবচেয়ে গুরুত্বপূর্ণ হয় NULLজন্য Ageকারণ ঐ সারি লক্ষ লক্ষ আছে। আমি কলামে একটি সাধারণ পৃষ্ঠা-সংক্ষেপিত পৃষ্ঠার চেয়ে কম পৃষ্ঠাগুলি দিয়ে ডেটা কভার করে এমন একটি সূচক তৈরি করতে সক্ষম হয়েছি। আমি ধরে নিয়েছি যে সারিতে প্রতি ন্যূনতম সূচকের আকার রয়েছে বা আমি চেষ্টা করেছি এমন কৌশলগুলি দিয়ে সূচকের অনেক অংশ এড়ানো যায় না। সুতরাং আমরা যদি তথ্য পেতে প্রায় একই সংখ্যক লজিক্যাল রিডের সাথে আটকে থাকি তবে দ্রুততর করার একমাত্র উপায় হল কোয়েরিটিকে আরও সমান্তরাল করে তোলা, তবে এরিকের প্রশ্নের তুলনায় এটি আলাদাভাবে করা দরকার যা টিএফ ব্যবহার করেছিল 8649. উপরের ক্যোয়ারিতে আমাদের সিপিইউ সময় অতিবাহিত সময়ের জন্য 3.62 এর অনুপাত রয়েছে যা বেশ ভাল। আদর্শটি আমার মেশিনে 4.0 এর অনুপাত হবে।

উন্নতির একটি সম্ভাব্য ক্ষেত্র হ'ল থ্রেডগুলির মধ্যে কাজকে আরও সমানভাবে ভাগ করা। নীচের স্ক্রিনশটে আমরা দেখতে পাচ্ছি যে আমার একটি সিপিইউ সামান্য বিরতি নেওয়ার সিদ্ধান্ত নিয়েছে:

অলস থ্রেড

সূচক স্ক্যান এমন কয়েকটি অপারেটরগুলির মধ্যে একটি যা সমান্তরালভাবে প্রয়োগ করা যেতে পারে এবং সারিগুলি থ্রেডগুলিতে কীভাবে বিতরণ করা হয় সে সম্পর্কে আমরা কিছুই করতে পারি না। এটিতে সুযোগের একটি উপাদান রয়েছে তবে বেশ ধারাবাহিকভাবে আমি একটি আন্ডার ওয়ার্কড থ্রেড দেখেছি। এটিকে ঘিরে কাজ করার একটি উপায় হ'ল শক্তভাবে সমান্তরালতা করা: নেস্টেড লুপের অভ্যন্তরের অংশে যোগ দিন। নেস্টেড লুপের অভ্যন্তরীণ অংশের যে কোনও কিছুই ক্রমিকভাবে প্রয়োগ করা হবে তবে অনেক সিরিয়াল থ্রেড একই সাথে চলতে পারে। যতক্ষণ আমরা একটি অনুকূল সমান্তরাল বিতরণ পদ্ধতি (যেমন রাউন্ড রবিন) পাই, ততক্ষণ প্রতিটি থ্রেডে কত সারি প্রেরণ করা হয় তা আমরা ঠিকভাবে নিয়ন্ত্রণ করতে পারি।

আমি ডওপ 4 দিয়ে প্রশ্নগুলি চালাচ্ছি সুতরাং আমার NULLটেবিলের সারিগুলি সমানভাবে চারটি বালতিতে ভাগ করা দরকার । এটি করার একটি উপায় হ'ল গণিত কলামগুলিতে একাধিক সূচী তৈরি করা:

ALTER TABLE dbo.Users
ADD Compute_bucket_0 AS (CASE WHEN Age IS NULL AND Id % 4 = 0 THEN 1 ELSE NULL END),
Compute_bucket_1 AS (CASE WHEN Age IS NULL AND Id % 4 = 1 THEN 1 ELSE NULL END),
Compute_bucket_2 AS (CASE WHEN Age IS NULL AND Id % 4 = 2 THEN 1 ELSE NULL END),
Compute_bucket_3 AS (CASE WHEN Age IS NULL AND Id % 4 = 3 THEN 1 ELSE NULL END);

CREATE INDEX IX_Compute_bucket_0 ON dbo.Users (Compute_bucket_0) WITH (DATA_COMPRESSION = PAGE);
CREATE INDEX IX_Compute_bucket_1 ON dbo.Users (Compute_bucket_1) WITH (DATA_COMPRESSION = PAGE);
CREATE INDEX IX_Compute_bucket_2 ON dbo.Users (Compute_bucket_2) WITH (DATA_COMPRESSION = PAGE);
CREATE INDEX IX_Compute_bucket_3 ON dbo.Users (Compute_bucket_3) WITH (DATA_COMPRESSION = PAGE);

আমি কেন পুরোপুরি নিশ্চিত নই যে কেন চারটি পৃথক সূচী এক সূচকের তুলনায় কিছুটা দ্রুত but তবে আমার পরীক্ষায় এটিই আমি খুঁজে পেয়েছি।

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

SELECT SUM(t.cnt) + (SELECT COUNT(*) FROM dbo.Users AS u WHERE u.Age < 18)
FROM 
(VALUES (0), (1), (2), (3)) v(x)
CROSS APPLY 
(
    SELECT COUNT(*) cnt 
    FROM dbo.Users 
    WHERE Compute_bucket_0 = CASE WHEN v.x = 0 THEN 1 ELSE NULL END

    UNION ALL

    SELECT COUNT(*) cnt 
    FROM dbo.Users 
    WHERE Compute_bucket_1 = CASE WHEN v.x = 1 THEN 1 ELSE NULL END

    UNION ALL

    SELECT COUNT(*) cnt 
    FROM dbo.Users 
    WHERE Compute_bucket_2 = CASE WHEN v.x = 2 THEN 1 ELSE NULL END

    UNION ALL

    SELECT COUNT(*) cnt 
    FROM dbo.Users 
    WHERE Compute_bucket_3 = CASE WHEN v.x = 3 THEN 1 ELSE NULL END
) t
OPTION (QUERYTRACEON 8649);

দশটি পরীক্ষার ফলাফল:

╔══════════╦════════════════════╦═══════════════╗
 cpu_time  total_elapsed_time  logical_reads 
╠══════════╬════════════════════╬═══════════════╣
     3093                 803          62008 
╚══════════╩════════════════════╩═══════════════╝

এই ক্যোয়ারির সাথে আমাদের কাছে সময়সীমা অনুপাতের 3.85 এর একটি সিপিইউ রয়েছে! আমরা রানটাইম থেকে 17 এমএস ছাঁটাই করেছি এবং এটি করতে এটি কেবল 4 টি গণিত কলাম এবং সূচি গ্রহণ করেছে! প্রতিটি থ্রেড সামগ্রিকভাবে একই সংখ্যার সারিগুলির খুব কাছাকাছি প্রক্রিয়া করে কারণ প্রতিটি সূচক একই সংখ্যক সারিগুলির খুব কাছাকাছি থাকে এবং প্রতিটি থ্রেড কেবল একটি সূচক স্ক্যান করে:

ভাল বিভক্ত কাজ

একটি চূড়ান্ত নোটে আমরা সহজ বোতামটিও চাপতে পারি এবং কলামটিতে একটি অনিবন্ধিত সিসিআই যুক্ত করতে পারি Age:

CREATE NONCLUSTERED COLUMNSTORE INDEX X_NCCI ON dbo.Users (Age);

নিম্নলিখিত কোয়েরিটি আমার মেশিনে 3 এমএসে শেষ হয়:

SELECT COUNT(*)
FROM dbo.Users AS u
WHERE u.Age < 18 OR u.Age IS NULL;

এটা মারতে শক্ত হতে চলেছে।


7

যদিও আমার কাছে স্ট্যাক ওভারফ্লো ডাটাবেসের স্থানীয় কপি নেই, তবে আমি বেশ কয়েকটি জিজ্ঞাসা করে দেখতে সক্ষম হয়েছি। আমার চিন্তাভাবনাটি ছিল সিস্টেম ক্যাটালগ ভিউ থেকে ব্যবহারকারীদের একটি গণনা পাওয়ার জন্য (অন্তর্নিহিত টেবিল থেকে সারিগুলির একটি গণনা সরাসরি পাওয়ার বিপরীতে)। তারপরে এমন একটি সারির গণনা পান যা এরিকের মানদণ্ডের সাথে মেলে (বা নাও পারে) এবং কিছু সাধারণ গণিত করুন।

আমি কোয়েরিগুলি পরীক্ষা করতে স্ট্যাক এক্সচেঞ্জ ডেটা এক্সপ্লোরার (পাশাপাশি SET STATISTICS TIME ON;এবং SET STATISTICS IO ON;) ব্যবহার করেছি। রেফারেন্সের পয়েন্টের জন্য, এখানে কিছু প্রশ্ন এবং সিপিইউ / আইও পরিসংখ্যান রয়েছে:

QUERY 1

--Erik's query From initial question.
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE ISNULL(u.Age, 17) < 18;

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 0 এমএস, অতিবাহিত সময় = 0 এমএস। (1 টি সারি) ফিরে এসেছে

সারণী 'ব্যবহারকারী'। স্ক্যান গণনা 17, যৌক্তিক 201567 পড়ছে, শারীরিক 0 0, পঠিত-এগিয়ে 2740 পড়বে, লব লজিকাল পড়বে 0, লব শারীরিক পাঠ 0, লব পঠন-এগিয়ে 0 0

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 1829 এমএস, অতিবাহিত সময় = 296 এমএস।

QUERY 2

--Erik's "OR" query.
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE u.Age < 18
OR u.Age IS NULL;

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 0 এমএস, অতিবাহিত সময় = 0 এমএস। (1 টি সারি) ফিরে এসেছে

সারণী 'ব্যবহারকারী'। স্ক্যান গণনা 17, লজিকাল পড়া 201567, শারীরিক পাঠ 0, রিড-ফরোয়ার্ড 0, লব লজিকাল রিড 0, লব ফিজিকাল 0, লব রিড-ফরোয়ার্ড 0

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 2500 এমএস, অতিবাহিত সময় = 147 এমএস।

QUERY 3

--Erik's derived tables/UNION ALL query.
SELECT SUM(Records)
FROM 
(
    SELECT COUNT(Id)
    FROM dbo.Users AS u
    WHERE u.Age < 18

    UNION ALL

    SELECT COUNT(Id)
    FROM dbo.Users AS u
    WHERE u.Age IS NULL
) x (Records);

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 0 এমএস, অতিবাহিত সময় = 0 এমএস। (1 টি সারি) ফিরে এসেছে

সারণী 'ব্যবহারকারী'। স্ক্যান গণনা 34, লজিকাল 403134, শারীরিক 0 0, পঠন-এগিয়ে 0, লব লজিকাল 0, লব শারীরিক পাঠ 0, লব পঠন-এগিয়ে 0 পড়ছে

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 3156 এমএস, অতিবাহিত সময় = 215 এমএস।

1 ম চেষ্টা

আমি এখানে তালিকাভুক্ত এরিকের সমস্ত প্রশ্নের তুলনায় এটি ধীর ছিল ... কমপক্ষে সময় অতিবাহিত হওয়া শর্তাবলী।

SELECT SUM(p.Rows)  -
  (
    SELECT COUNT(*)
    FROM dbo.Users AS u
    WHERE u.Age >= 18
  ) 
FROM sys.objects o
JOIN sys.partitions p
    ON p.object_id = o.object_id
WHERE p.index_id < 2
AND o.name = 'Users'
AND SCHEMA_NAME(o.schema_id) = 'dbo'
GROUP BY o.schema_id, o.name

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 0 এমএস, অতিবাহিত সময় = 0 এমএস। (1 টি সারি) ফিরে এসেছে

সারণী 'ওয়ার্কটেবল'। স্ক্যান কাউন্ট 0, লজিকাল রিড 0, ফিজিকাল রিড 0, রিড-ফরোডড রিড 0, লব লজিকাল রিড 0, লব ফিজিকাল রিড 0, লব রিড-ফরোয়ার্ড 0 টেবিল 'সিসরোজেট'। স্ক্যান কাউন্ট 2, লজিকাল রিড 10, ফিজিকাল রিড 0, রিড-ফরোয়ার্ড রিড 0, লব লজিকাল রিড 0, লব ফিজিকাল রিড 0, লব রিড-ফরোয়ার্ড 0 টেবিল 'সিসচোবজ'। স্ক্যান কাউন্ট 1, লজিকাল রিডস 4, ফিজিকাল রিডস 0, রিড-ফরোয়ার্ড রিড 0, লব লজিকাল রিড 0, লব ফিজিকাল রিড 0, লব রিড-ফরোয়ার্ড 0 টেবিল 'ব্যবহারকারী'। স্ক্যান কাউন্ট 1, লজিকাল রিডিং 201567, ফিজিকাল রিডস 0, রিড-ফরোয়ার্ড রিড 0, লব লজিকাল রিড 0, লব ফিজিকাল 0, লব রিড-ফরোয়ার্ড 0

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 593 এমএস, অতিবাহিত সময় = 598 এমএস।

২ য় প্রয়াস

এখানে আমি ব্যবহারকারীর মোট সংখ্যা (উপ-কোয়ের পরিবর্তে) সঞ্চয় করার জন্য একটি ভেরিয়েবলের বিকল্প বেছে নিয়েছি। 1 ম চেষ্টাটির তুলনায় স্ক্যানের সংখ্যা 1 থেকে 17 এ বেড়েছে। লজিকাল রিড একই ছিল। তবে অতিবাহিত সময়টি বেশ কমেছে।

DECLARE @Total INT;

SELECT @Total = SUM(p.Rows)
FROM sys.objects o
JOIN sys.partitions p
    ON p.object_id = o.object_id
WHERE p.index_id < 2
AND o.name = 'Users'
AND SCHEMA_NAME(o.schema_id) = 'dbo'
GROUP BY o.schema_id, o.name

SELECT @Total - COUNT(*)
FROM dbo.Users AS u
WHERE u.Age >= 18

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 0 এমএস, অতিবাহিত সময় = 0 এমএস। সারণী 'ওয়ার্কটেবল'। স্ক্যান কাউন্ট 0, লজিকাল রিড 0, ফিজিকাল রিড 0, রিড-ফরোডড রিড 0, লব লজিকাল রিড 0, লব ফিজিকাল রিড 0, লব রিড-ফরোয়ার্ড 0 টেবিল 'সিসরোজেট'। স্ক্যান কাউন্ট 2, লজিকাল রিড 10, ফিজিকাল রিড 0, রিড-ফরোয়ার্ড রিড 0, লব লজিকাল রিড 0, লব ফিজিকাল রিড 0, লব রিড-ফরোয়ার্ড 0 টেবিল 'সিসচোবজ'। স্ক্যান কাউন্ট 1, লজিকাল রিডস 4, ফিজিকাল রিড 0, রিড-ফরোয়ার্ড রিড 0, লব লজিকাল রিড 0, লব ফিজিকাল 0, লব রিড-ফরোয়ার্ড 0

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 0 এমএস, অতিবাহিত সময় = 1 এমএস। (1 টি সারি) ফিরে এসেছে

সারণী 'ব্যবহারকারী'। স্ক্যান গণনা 17, লজিকাল পড়া 201567, শারীরিক পাঠ 0, রিড-ফরোয়ার্ড 0, লব লজিকাল রিড 0, লব ফিজিকাল 0, লব রিড-ফরোয়ার্ড 0

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 1471 এমএস, অতিবাহিত সময় = 98 এমএস।

অন্যান্য নোট: ডিবিসিসি ট্র্যাকন স্ট্যাক এক্সচেঞ্জ ডেটা এক্সপ্লোরারে অনুমোদিত নয়, নীচে উল্লিখিত হিসাবে:

ব্যবহারকারী 'STACKEXCHANGE \ svc_sede' ডিবিসিসি ট্র্যাকইন চালানোর অনুমতি নেই।


1
তাদের সম্ভবত আমার মতো একই সূচকগুলি নেই, তাই পার্থক্যগুলি। এবং, কে জানে? সম্ভবত আমার হোম সার্ভারটি আরও ভাল হার্ডওয়্যারে রয়েছে;) দুর্দান্ত উত্তর যদিও!
এরিক ডার্লিং

আপনার প্রথম প্রয়াসের জন্য আপনার নীচের ক্যোয়ারীটি ব্যবহার করা উচিত ছিল (এটি অনেক দ্রুত হবে, যেহেতু এটি সিস্টেমেজ-ওভারহেডের প্রচুর পরিমাণে চলাফেরা করে): SELECT SUM(p.Rows) - (SELECT COUNT(*) FROM dbo.Users AS u WHERE u.Age >= 18 ) FROM sys.partitions p WHERE p.index_id < 2 AND p.object_id = OBJECT_ID('dbo.Users')
টমাস ফ্রাঞ্জ

পিএস: সচেতন থাকুন যে ইন-মেমোরি-ইনডেক্সগুলিতে (সাধারণ হ্যাশ / ক্লাস্টারড ইনডেক্সের হিসাবে অননুমুক্ত হ্যাশ) একটি সূচক আইডি = 0/1 নেই)
টমাস ফ্রানজ

1

ভেরিয়েবল ব্যবহার করবেন?

declare @int1 int = ( select count(*) from table_1 where bb <= 1 )
declare @int2 int = ( select count(*) from table_1 where bb is null )
select @int1 + @int2;

মন্তব্য প্রতি পরিবর্তনগুলি এড়ানো যাবে

SELECT (select count(*) from table_1 where bb <= 1) 
     + (select count(*) from table_1 where bb is null);

3
এছাড়াও:SELECT (select count(*) from table_1 where bb <= 1) + (select count(*) from table_1 where bb is null);
ypercubeᵀᴹ

3
সিপিইউ এবং আইও পরীক্ষা করার সময় এটি চেষ্টা করতে চান। ইঙ্গিত: এটি এরিকের উত্তরগুলির মতো একটি।
ব্রেন্ট ওজার

0

ভাল ব্যবহার SET ANSI_NULLS OFF;

SET ANSI_NULLS OFF; 
SET STATISTICS TIME ON;
SET STATISTICS IO ON;

SELECT COUNT(*)
FROM dbo.Users AS u
WHERE age=NULL or age<18

Table 'Users'. Scan count 17, logical reads 201567

 SQL Server Execution Times:
 CPU time = 2344 ms,  elapsed time = 166 ms.

এইটি এমন কিছু বিষয় শুধু popped মধ্যে আমার mind.Just এই মৃত্যুদন্ড কার্যকর হয় https://data.stackexchange.com

তবে যদিও @ বি্লিটজ_েরিকের মতো দক্ষ নয়


0

একটি তুচ্ছ সমাধান হ'ল গণনা (*) - গণনা (বয়স> = 18) গণনা করা:

SELECT
    (SELECT COUNT(*) FROM Users) -
    (SELECT COUNT(*) FROM Users WHERE Age >= 18);

বা:

SELECT COUNT(*)
     - COUNT(CASE WHEN Age >= 18)
FROM Users;

ফলাফল এখানে

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