برنامه نویسی

MongoDB Multi-Planner Optimizer و Cache Plan

سیستم های پایگاه داده از برنامه ریزان پرس و جو برای بهینه سازی بازیابی داده ها ، در درجه اول از طریق دو روش استفاده می کنند: بهینه سازهای مبتنی بر قانون (RBO) و بهینه سازهای مبتنی بر هزینه (CBO).

  • بهینه ساز مبتنی بر قانون (RBO): این روش برای انتخاب برنامه های اجرای ، از قوانین از پیش تعریف شده استفاده می کند ، در نتیجه برنامه های پرس و جو پایدار اما ساده گرایانه. غالباً با نمایش داده های پیچیده مربوط به پیوندهای متعدد اما با یک مدل اسناد مبارزه می کند ، سفارش پیوستن به صورت مقدماتی حل می شود.

  • بهینه ساز مبتنی بر هزینه (CBO): CBO آمار توزیع داده ها را برای ارزیابی برنامه های بالقوه و انتخاب مقرون به صرفه ترین گزینه تجزیه و تحلیل می کند. اعتماد به نفس آن به آمار احتمالاً منسوخ می تواند منجر به تصمیمات زیر حد شود ، بنابراین جمع آوری آمار بسیار مهم است. برنامه ریزی پرس و جوهای پیچیده می تواند زمان ببرد ، بنابراین یا به یک حافظه نهان مشترک متکی است یا در صورت وجود پیوستن بسیاری ، به الگوریتم های ژنتیکی ساده باز می گردد.

منگوله از یک مدل سند استفاده می کند که به حداقل می رساند ، و در درجه اول روی انتخاب شاخص مناسب تمرکز می کند. این تصمیمات اجرای را تا زمان اجرا به جای تکیه بر RBO یا CBO برای انتخاب یکی از تصمیمات. از طریق حافظه پنهان برنامه مشترک وت چند افلار مکانیسم ، MongoDB به صورت پویا برنامه های پرس و جو را برای اجرای بهینه ارزیابی و تنظیم می کند.

بیایید با یک مثال ساده توضیح دهیم و از چالش برانگیزترین وضعیت برای یک برنامه ریز پرس و جو استفاده کنیم: ستون SKEW ، جایی که یک زمینه دارای مقادیر منحصر به فرد و چند مورد محبوب است. یک مورد تجاری که با آن روبرو شدم در یک فروشنده کپسول قهوه بود. مشتریان آنلاین از شناسه مشتری خود استفاده می کنند و به طور متوسط ​​هر سه ماه برخی کپسول ها را سفارش می دهند. مغازه ها دارای شناسه مشتری ویژه هستند و هر روز هزاران سفارش دریافت می کنند. شاخص مورد استفاده باید متفاوت باشد ، اما برنامه از “تجزیه و تحلیل” بسیاری از بهترین ها را اجرا می کند ، و اولین کسی که اجرا می کند ، برنامه اعدام را برای دیگران تعیین می کند. تام کیت گفت که داستان پایگاه داده هنگام باران کند است (زیرا اولین کاربر که بیانیه را تجزیه می کند به کاربر بستگی دارد که با دوچرخه یا ماشین همراه است).

یک مجموعه را اولیه کنید

من یک مثال ساده می سازم ، مجموعه ای از ده میلیون سند با دو زمینه: a وت b:

  • a برای چند سند (با ارزش کمتر از 50) بسیار انتخابی است اما میلیون ها سند باقیمانده همگی دارای یک مقدار 50 هستند.
  • b یکنواخت ، با مقادیر 1 تا 10 و انتخاب خوب: یک مقدار ده سند را برمی گرداند.

در اینجا چگونه من این را با یک حلقه روشن کردم iبا a با تولید می شود Math.min(i,50) وت b با تولید می شود i%1e6:

// Drop the collection if it already exists
db.franck.drop();
// Insert documents with different data distributions
const bulk = db.franck.initializeUnorderedBulkOp();
const num=1e7;
for (let i = 0; i < num; i++) {
    bulk.insert({ a: Math.min(i,50), b: i%1e6 });
}
const r = bulk.execute();

console.log(`Bulk Operation Summary: Inserted: ${r.insertedCount}, Matched: ${r.matchedCount}, Modified: ${r.modifiedCount}, Deleted: ${r.deletedCount}, Upserted: ${r.upsertedCount}`);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این ده میلیون سند درج شده است:

test> console.log(`Bulk Operation Summary: Inserted: ${r.insertedCount}, Matched: ${r.matchedCount}, Modified: ${r.modifiedCount}, Deleted: ${r.deletedCount}, Upserted: ${r.upsertedCount}`);             
Bulk Operation Summary: Inserted: 10000000, Matched: 0, Modified: 0, Deleted: 0, Upserted: 0
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

شاخص ها ایجاد کنید

به عنوان هدف نشان دادن دو برنامه اجرای احتمالی ، من دو فهرست ایجاد می کنم ، یکی در هر زمینه:

test> db.franck.createIndex({ a: 1 });
a_1
test> db.franck.createIndex({ b: 1 });
b_1
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

داده ها را تأیید کنید

test> // "b" has a good selectivity

test> db.franck.countDocuments({ b: 42 });
10

test> // "a" has a better selectivity when a<50

test> db.franck.countDocuments({ a: 42         });
1

test> // "a" has a very bad selectivity when a=50 (popular value)

test> db.franck.countDocuments({ a: 50         });
9999950

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پرس و جو من در هر ستون یک محمول خواهد داشت. من تست می کنم { a: 42, b: 42 } که یک سند را برمی گرداند ، و { a: 50, b: 42 } که ده سند را برمی گرداند.

مشخصات اجرای و حافظه پنهان

من به اعدام های آمار با پروفایل و در حافظه نهان پرس و جو نگاه می کنم ، بنابراین آنها را در آزمایشگاه خود تنظیم می کنم:

db.franck.getPlanCache().clear();
db.franck.getPlanCache().list();
db.setProfilingLevel(0);
db.system.profile.drop();
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اولین اجرای و برنامه ریزی حافظه پنهان

من پروفایل را تنظیم کردم و اولین اجرای آن را اجرا می کنم که یک سند را برمی گرداند:

test> db.setProfilingLevel(2 );
{ was: 0, slowms: 0, sampleRate: 1, ok: 1 }
test> db.franck.find({ a: 42, b: 42 });
[ { _id: ObjectId('67d34e6128ca7c6f95a00acb'), a: 42, b: 42 } ]
test> db.setProfilingLevel(0);
{ was: 2, slowms: 0, sampleRate: 1, ok: 1 }
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اجرای اولیه برنامه ریز پرس و جو MongoDB تمام برنامه های احتمالی ذخیره شده در حافظه نهان را ایجاد می کند: یک طرح IXSCAN را در فهرست اجرا می کند a، دیگری ixscan را در فهرست انجام می دهد b، و یک سوم هر دو شاخص را با یک عملیات and_sorted ترکیب می کند:

test> db.franck.getPlanCache().list();

[
  {
    version: '1',
    queryHash: '20F294D4',
    planCacheKey: '2AAF6E88',
    isActive: false,
    works: Long('2'),
    timeOfCreation: ISODate('2025-03-13T21:43:31.189Z'),
    createdFromQuery: { query: { a: 42, b: 42 }, sort: {}, projection: {} },
    cachedPlan: {
      stage: 'FETCH',
      filter: { b: { '$eq': 42 } },
      inputStage: {
        stage: 'IXSCAN',
        keyPattern: { a: 1 },
        indexName: 'a_1',
        isMultiKey: false,
        multiKeyPaths: { a: [] },
        isUnique: false,
        isSparse: false,
        isPartial: false,
        indexVersion: 2,
        direction: 'forward',
        indexBounds: { a: [ '[42, 42]' ] }
      }
    },
    creationExecStats: [
      {
        nReturned: 1,
        executionTimeMillisEstimate: 0,
        totalKeysExamined: 1,
        totalDocsExamined: 1,
        executionStages: {
          stage: 'FETCH',
          filter: { b: { '$eq': 42 } },
          nReturned: 1,
          executionTimeMillisEstimate: 0,
          works: 2,
          advanced: 1,
          needTime: 0,
          needYield: 0,
          saveState: 0,
          restoreState: 0,
          isEOF: 1,
          docsExamined: 1,
          alreadyHasObj: 0,
          inputStage: {
            stage: 'IXSCAN',
            nReturned: 1,
            executionTimeMillisEstimate: 0,
            works: 2,
            advanced: 1,
            needTime: 0,
            needYield: 0,
            saveState: 0,
            restoreState: 0,
            isEOF: 1,
            keyPattern: { a: 1 },
            indexName: 'a_1',
            isMultiKey: false,
            multiKeyPaths: { a: [] },
            isUnique: false,
            isSparse: false,
            isPartial: false,
            indexVersion: 2,
            direction: 'forward',
            indexBounds: { a: [Array] },
            keysExamined: 1,
            seeks: 1,
            dupsTested: 0,
            dupsDropped: 0
          }
        }
      },
      {
        nReturned: 1,
        executionTimeMillisEstimate: 0,
        totalKeysExamined: 2,
        totalDocsExamined: 2,
        executionStages: {
          stage: 'FETCH',
          filter: { a: { '$eq': 42 } },
          nReturned: 1,
          executionTimeMillisEstimate: 0,
          works: 2,
          advanced: 1,
          needTime: 1,
          needYield: 0,
          saveState: 0,
          restoreState: 0,
          isEOF: 0,
          docsExamined: 2,
          alreadyHasObj: 0,
          inputStage: {
            stage: 'IXSCAN',
            nReturned: 2,
            executionTimeMillisEstimate: 0,
            works: 2,
            advanced: 2,
            needTime: 0,
            needYield: 0,
            saveState: 0,
            restoreState: 0,
            isEOF: 0,
            keyPattern: { b: 1 },
            indexName: 'b_1',
            isMultiKey: false,
            multiKeyPaths: { b: [] },
            isUnique: false,
            isSparse: false,
            isPartial: false,
            indexVersion: 2,
            direction: 'forward',
            indexBounds: { b: [Array] },
            keysExamined: 2,
            seeks: 1,
            dupsTested: 0,
            dupsDropped: 0
          }
        }
      },
      {
        nReturned: 1,
        executionTimeMillisEstimate: 0,
        totalKeysExamined: 2,
        totalDocsExamined: 1,
        executionStages: {
          stage: 'FETCH',
          filter: { '$and': [ [Object], [Object] ] },
          nReturned: 1,
          executionTimeMillisEstimate: 0,
          works: 2,
          advanced: 1,
          needTime: 1,
          needYield: 0,
          saveState: 0,
          restoreState: 0,
          isEOF: 0,
          docsExamined: 1,
          alreadyHasObj: 0,
          inputStage: {
            stage: 'AND_SORTED',
            nReturned: 1,
            executionTimeMillisEstimate: 0,
            works: 2,
            advanced: 1,
            needTime: 1,
            needYield: 0,
            saveState: 0,
            restoreState: 0,
            isEOF: 0,
            failedAnd_0: 0,
            failedAnd_1: 0,
            inputStages: [ [Object], [Object] ]
          }
        }
      }
    ],
    candidatePlanScores: [ 2.5002, 1.5002, 1.5001 ],
    indexFilterSet: false,
    estimatedSizeBytes: Long('4693'),
    host: '4b49f6ca6400:27017'
  }
]
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این برنامه ها مورد ارزیابی قرار گرفت (creationExecStats) با { a: { '$eq': 42 } وت { b: { '$eq': 42 } و به ثمر رساند بهترین نمره به انتخابی ترین ، شاخص می رود a، که یک کلید را بررسی می کند و یک سند را واکشی می کند.

اعدام های بعدی با همان مقادیر

من همان نه بار دیگر را اجرا می کنم:

db.setProfilingLevel(2 );
db.franck.find({ a: 42, b: 42 });
db.franck.find({ a: 42, b: 42 });
db.franck.find({ a: 42, b: 42 });
db.franck.find({ a: 42, b: 42 });
db.franck.find({ a: 42, b: 42 });
db.franck.find({ a: 42, b: 42 });
db.franck.find({ a: 42, b: 42 });
db.franck.find({ a: 42, b: 42 });
db.franck.find({ a: 42, b: 42 });
db.setProfilingLevel(0);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

من برخی از اطلاعات جالب را از پروفایل آن ده اعدام استخراج می کنم:

test> db.system.profile.find({ ns: "test.franck" }).sort({ ts: 1 }).limit(100).forEach((doc) => { if (doc.execStats) console.log(`${doc.ts.toISOString().slice(11, 23)} works: ${doc.execStats.works.toString().padStart(5)} keys: ${doc.keysExamined.toString().padStart(5)} docs: ${doc.docsExamined.toString().padStart(5)} ret: ${doc.nreturned.toString().padStart(5)} ${doc.execStats.stage.padStart(12)} ${doc.planSummary.padStart(12)} exec(plan): ${doc.millis.toString().padStart(5)}ms (${doc.planningTimeMicros.toString().padStart(8)}us) query/plan ${doc.queryHash}/${doc.planCacheKey} ${doc.queryFramework} ${doc.fromPlanCache ? 'fromPlanCache ' : ''}${doc.fromMultiPlanner ? 'fromMultiPlanner ' : ''}${doc.replanned ? doc.replanReason : ''}`); });

21:43:31.191 works:     3 keys:     1 docs:     1 ret:     1        FETCH IXSCAN { a: 1 } exec(plan):     7ms (    7063us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner                                                             
21:56:49.938 works:     3 keys:     1 docs:     1 ret:     1        FETCH IXSCAN { a: 1 } exec(plan):     9ms (    8899us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner                                                             
21:56:49.982 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     1ms (    1264us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache                                                                
21:56:50.014 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     233us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache                                                                
21:56:50.053 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     240us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache                                                                
21:56:50.085 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     235us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache                                                                
21:56:50.108 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     254us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache                                                                
21:56:50.133 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     230us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache                                                                
21:56:50.157 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     246us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache                                                                
21:56:50.188 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     246us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache     
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در دو اعدام اول ، تمام برنامه ها با استفاده از چند برنامه ای مورد بررسی قرار گرفت. از اعدام سوم به بعد ، فقط برنامه برنده از حافظه نهان اجرا شد که منجر به کاهش زمان اجرای از جمله زمان برنامه ریزی شد. بهترین فهرست ، که کاملاً اجرا شد ، یکی از موارد است aبشر

اعدام های بیشتر با ارزش های مختلف

من همان شکل پرس و جو را اجرا می کنم اما با یک مقدار متفاوت ، برای اینکه می دانم شاخص روشن است a خوب نیست:

db.setProfilingLevel(2);
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.franck.find({ a: 50, b: 42 });
db.setProfilingLevel(0);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

من مشخصات همه اعدام ها را جمع می کنم:

test> db.system.profile.find({ ns: "test.franck" }).sort({ ts: 1 }).limit(100).forEach((doc) => { if (doc.execStats) console.log(`${doc.ts.toISOString().slice(11, 23)} works: ${doc.execStats.works.toString().padStart(5)} keys: ${doc.keysExamined.toString().padStart(5)} docs: ${doc.docsExamined.toString().padStart(5)} ret: ${doc.nreturned.toString().padStart(5)} ${doc.execStats.stage.padStart(12)} ${doc.planSummary.padStart(12)} exec(plan): ${doc.millis.toString().padStart(5)}ms (${doc.planningTimeMicros.toString().padStart(8)}us) query/plan ${doc.queryHash}/${doc.planCacheKey} ${doc.queryFramework} ${doc.fromPlanCache ? 'fromPlanCache ' : ''}${doc.fromMultiPlanner ? 'fromMultiPlanner ' : ''}${doc.replanned ? doc.replanReason : ''}`); });

21:43:31.191 works:     3 keys:     1 docs:     1 ret:     1        FETCH IXSCAN { a: 1 } exec(plan):     7ms (    7063us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
21:56:49.938 works:     3 keys:     1 docs:     1 ret:     1        FETCH IXSCAN { a: 1 } exec(plan):     9ms (    8899us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
21:56:49.982 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     1ms (    1264us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.014 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     233us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.053 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     240us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.085 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     235us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.108 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     254us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.133 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     230us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.157 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     246us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.188 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     246us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.435 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     2ms (    2851us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner cached plan was less efficient than expected: expected trial execution to take 2 works but it took at least 20 works
22:12:02.474 works:    12 keys:    10 docs:    10 ret:     9        FETCH IXSCAN { b: 1 } exec(plan):     0ms (     437us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
22:12:02.505 works:    12 keys:    10 docs:    10 ret:     9        FETCH IXSCAN { b: 1 } exec(plan):     0ms (     421us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
22:12:02.541 works:    12 keys:    10 docs:    10 ret:     9        FETCH IXSCAN { b: 1 } exec(plan):     0ms (     473us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
22:12:02.566 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     291us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.591 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     339us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.613 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     287us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.643 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     315us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.659 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     320us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.685 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     472us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بر خلاف بسیاری از بانکهای اطلاعاتی دیگر که قبل از بهینه سازی مجدد نیاز به خرابی دارند ، MongoDB هرگز از شاخص اشتباه استفاده نکرد. این کار با برنامه ذخیره شده اما در حالت آزمایشی آغاز شد. آن را تشخیص داد works مقدار بیش از ده برابر مقدار مورد انتظار و به چند برنامه ریز ، جایی که همه برنامه ها اجرا می شوند ، برگشتند. شاخص در b مورد استفاده قرار گرفت ، که انتخاب خوبی است. سه اعدام بعدی قبل از تعویض نیز همین کار را کردند تا از این برنامه با این فهرست استفاده کنند. توجه داشته باشید که می توانید دوباره به عنوان حافظه پنهان برنامه ، مجدداً برای این تمرین ارتباط برقرار کنید.

اعدام های بیشتر مانند اولین بار

وقتی دوباره یک پرس و جو انتخابی مانند اجرا می کنید find({ a: 42, b: 42 })، متوجه خواهید شد که این فهرست همچنان ادامه دارد bبشر این اتفاق می افتد زیرا ، با وجود a به طور بالقوه گزینه بهتری است ، تفاوت به اندازه کافی قابل توجه برای تضمین تغییر نیست.

test> db.system.profile.find({ ns: "test.franck" }).sort({ ts: 1 }).limit(100).forEach((doc) => { if (doc.execStats) console.log(`${doc.ts.toISOString().slice(11, 23)} works: ${doc.execStats.works.toString().padStart(5)} keys: ${doc.keysExamined.toString().padStart(5)} docs: ${doc.docsExamined.toString().padStart(5)} ret: ${doc.nreturned.toString().padStart(5)} ${doc.execStats.stage.padStart(12)} ${doc.planSummary.padStart(12)} exec(plan): ${doc.millis.toString().padStart(5)}ms (${doc.planningTimeMicros.toString().padStart(8)}us) query/plan ${doc.queryHash}/${doc.planCacheKey} ${doc.queryFramework} ${doc.fromPlanCache ? 'fromPlanCache ' : ''}${doc.fromMultiPlanner ? 'fromMultiPlanner ' : ''}${doc.replanned ? doc.replanReason : ''}`); });

21:43:31.191 works:     3 keys:     1 docs:     1 ret:     1        FETCH IXSCAN { a: 1 } exec(plan):     7ms (    7063us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
21:56:49.938 works:     3 keys:     1 docs:     1 ret:     1        FETCH IXSCAN { a: 1 } exec(plan):     9ms (    8899us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
21:56:49.982 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     1ms (    1264us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.014 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     233us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.053 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     240us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.085 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     235us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.108 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     254us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.133 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     230us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.157 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     246us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
21:56:50.188 works:     2 keys:     1 docs:     1 ret:     1  CACHED_PLAN IXSCAN { a: 1 } exec(plan):     0ms (     246us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.435 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     2ms (    2851us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner cached plan was less efficient than expected: expected trial execution to take 2 works but it took at least 20 works
22:12:02.474 works:    12 keys:    10 docs:    10 ret:     9        FETCH IXSCAN { b: 1 } exec(plan):     0ms (     437us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
22:12:02.505 works:    12 keys:    10 docs:    10 ret:     9        FETCH IXSCAN { b: 1 } exec(plan):     0ms (     421us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
22:12:02.541 works:    12 keys:    10 docs:    10 ret:     9        FETCH IXSCAN { b: 1 } exec(plan):     0ms (     473us) query/plan 20F294D4/2AAF6E88 classic fromMultiPlanner 
22:12:02.566 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     291us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.591 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     339us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.613 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     287us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.643 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     315us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.659 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     320us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:12:02.685 works:    10 keys:    10 docs:    10 ret:     9  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     472us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:20:26.110 works:     2 keys:    10 docs:    10 ret:     1  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     312us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:20:26.145 works:     2 keys:    10 docs:    10 ret:     1  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     311us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:20:26.174 works:     2 keys:    10 docs:    10 ret:     1  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     281us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:20:26.201 works:     2 keys:    10 docs:    10 ret:     1  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     303us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
22:20:36.089 works:     2 keys:    10 docs:    10 ret:     1  CACHED_PLAN IXSCAN { b: 1 } exec(plan):     0ms (     294us) query/plan 20F294D4/2AAF6E88 classic fromPlanCache 
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این الگوریتم برنامه ریزی مجدد ساده است اما کار مناسبی را انجام می دهد: از اجرای فهرست های بد جلوگیری می کند و از برنامه هایی که به اندازه کافی خوب هستند استفاده می کند بدون اینکه سعی کنید همیشه بهترین ها را پیدا کنید. من اغلب در مورد بهینه سازهای مبتنی بر هزینه نگران بوده ام که همیشه سعی می کنند بهترین برنامه اعدام را پیدا کنند ، در معرض خطر رگرسیون عملکرد عظیم در صورت عدم موفقیت در تخمین های خود. بیشتر کاربران زمان اجرای را ترجیح می دهند که به اندازه کافی خوب و قابل پیش بینی باشد. با تکیه بر آمار ، هیچ مشکلی در جداول ، خارج از مرز یا بی ثبات که در سایر پایگاه های داده با آنها روبرو هستیم ، مشکلی وجود ندارد.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا