كيفية استخدام خطوة ملف تعريف التنفيذ لتقييم استعلامات Gremlin

ينطبق على: العفريت

توفر هذه المقالة نظرة عامة حول كيفية استخدام خطوة ملف تعريف التنفيذ لقواعد بيانات الرسم البياني Azure Cosmos DB ل Gremlin. توفر هذه الخطوة معلومات ذات صلة لاستكشاف الأخطاء وإصلاحها وتحسين الاستعلام، وهي متوافقة مع أي استعلام Gremlin يمكن تنفيذه مقابل حساب واجهة برمجة التطبيقات COSMOS DB Gremlin.

لاستخدام هذه الخطوة، فم بإلحاق استدعاء الدالة executionProfile() في نهاية الاستعلام Gremlin. يُنفذ استعلام Gremlin وستُرجع نتيجة العملية كائن استجابة JSON مع ملف تعريف تنفيذ الاستعلام.

على سبيل المثال:

    // Basic traversal
    g.V('mary').out()

    // Basic traversal with execution profile call
    g.V('mary').out().executionProfile()

بعد استدعاء الخطوة executionProfile()، ستكون الاستجابة كائن JSON يتضمن الخطوة Gremlin المنفذة، وإجمالي الوقت المستغرق، ومجموعة من عمال تشغيل وقت تشغيل Cosmos DB التي نتجت عن العبارة.

إشعار

لم يتم تحديد تطبيق ملف تعريف التنفيذ هذا في مواصفات Apache Tinkerpop. وهو خاص ب Azure Cosmos DB لتنفيذ Gremlin.

مثال للاستجابة

ما يلي هو مثال توضيحي للإخراج الذي سيتم إرجاعه:

إشعار

هذا المثال موضح بتعليقات تشرح البنية العامة للاستجابة. لن تحتوي استجابة ملف التنفيذ الفعلي على أي تعليقات.

[
  {
    // The Gremlin statement that was executed.
    "gremlin": "g.V('mary').out().executionProfile()",

    // Amount of time in milliseconds that the entire operation took.
    "totalTime": 28,

    // An array containing metrics for each of the steps that were executed. 
    // Each Gremlin step will translate to one or more of these steps.
    // This list is sorted in order of execution.
    "metrics": [
      {
        // This operation obtains a set of Vertex objects.
        // The metrics include: time, percentTime of total execution time, resultCount, 
        // fanoutFactor, count, size (in bytes) and time.
        "name": "GetVertices",
        "time": 24,
        "annotations": {
          "percentTime": 85.71
        },
        "counts": {
          "resultCount": 2
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 2,
            "size": 696,
            "time": 0.4
          }
        ]
      },
      {
        // This operation obtains a set of Edge objects. 
        // Depending on the query, these might be directly adjacent to a set of vertices, 
        // or separate, in the case of an E() query.
        //
        // The metrics include: time, percentTime of total execution time, resultCount, 
        // fanoutFactor, count, size (in bytes) and time.
        "name": "GetEdges",
        "time": 4,
        "annotations": {
          "percentTime": 14.29
        },
        "counts": {
          "resultCount": 1
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 1,
            "size": 419,
            "time": 0.67
          }
        ]
      },
      {
        // This operation obtains the vertices that a set of edges point at.
        // The metrics include: time, percentTime of total execution time and resultCount.
        "name": "GetNeighborVertices",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      },
      {
        // This operation represents the serialization and preparation for a result from 
        // the preceding graph operations. The metrics include: time, percentTime of total 
        // execution time and resultCount.
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      }
    ]
  }
]

إشعار

ستُنفذ الخطوة executionProfile الاستعلام Gremlin. ويتضمن ذلك الخطوتين addV أو addE، والتي ستظهر في الإنشاء وستُنفذ التغييرات المحددة في الاستعلام. ونتيجة لذلك، سيتم أيضاً فرض رسوم على وحدات الطلب التي تم إنشاؤها بواسطة استعلام Gremlin.

كائنات استجابة ملف تعريف التنفيذ

ستؤدي استجابة الدالة executionProfile() إلى تسلسل هرمي لكائنات JSON بالبنية التالية:

  • كائن عملية Gremlin: يمثل كامل عملية Gremlin التي تم تنفيذها. ويحتوي على الخصائص التالية.

    • gremlin: عبارة Gremlin الصريحة التي تم تنفيذها.
    • totalTime: الوقت بالملّي ثانية الذي تم فيه تنفيذ الخطوة.
    • metrics: مصفوفة تحتوي على كل من عمال تشغيل وقت تشغيل Cosmos DB التي تم تنفيذها لتحقيق الاستعلام. ويتم فرز هذه القائمة حسب ترتيب التنفيذ.
  • عمال تشغيل وقت تشغيل Cosmos DB: يمثل كل مكون من مكونات عملية Gremlin بأكملها. ويتم فرز هذه القائمة حسب ترتيب التنفيذ. يحتوي كل عنصر على الخصائص التالية:

    • name: اسم عامل التشغيل. هذا هو نوع الخطوة التي تم تقييمها وتنفيذها. اقرأ المزيد في الجدول أدناه.
    • time: مقدار الوقت بالملّي ثانية الذي استغرقه عامل تشغيل معين.
    • annotations: يحتوي على معلومات إضافية خاصة بالمشغل الذي تم تنفيذه.
    • annotations.percentTime: النسبة المئوية لإجمالي الوقت المستغرق في تنفيذ عامل التشغيل المحدد.
    • counts: عدد الكائنات التي تم إرجاعها من طبقة التخزين بواسطة عامل التشغيل هذا. يتم تضمين هذا في القيمة العددية counts.resultCount داخله.
    • storeOps: يمثل عملية تخزين يمكن أن تمتد عبر قسم واحد أو عدة أقسام.
    • storeOps.fanoutFactor: يمثل عدد الأقسام التي وصلت إليها عملية التخزين المحددة هذه.
    • storeOps.count: يمثل عدد النتائج التي أرجعتها عملية التخزين هذه.
    • storeOps.size: يمثل الحجم بالبايت الناتج عن عملية تخزين معينة.
عامل تشغيل وقت تشغيل Cosmos DB Gremlin ‏‏الوصف
GetVertices تحصل هذه الخطوة على مجموعة متوقعة من الكائنات من طبقة الاستدامة.
GetEdges تحصل هذه الخطوة على الحواف المجاورة لمجموعة من الرؤوس. يمكن أن تؤدي هذه الخطوة إلى عملية تخزين واحدة أو عدة عمليات.
GetNeighborVertices تحصل هذه الخطوة على الرؤوس المتصلة بمجموعة من الحواف. تحتوي الحواف على مفاتيح الأقسام ومعرفات كل من رؤوس المصدر والهدف.
Coalesce تمثل هذه الخطوة تقييم عمليتين كلما تم تنفيذ خطوة coalesce() في Gremlin.
CartesianProductOperator تحسب هذه الخطوة منتجاً ديكارتياً بين مجموعتي بيانات. يتم تنفيذها عادةً عند استخدام دالتي التقييم to() أو from().
ConstantSourceOperator تحسب هذه الخطوة تعبيراً لإنتاج قيمة ثابتة كنتيجة لذلك.
ProjectOperator تقوم هذه الخطوة بإعداد استجابة باستخدام نتيجة العمليات السابقة وتسلسلها.
ProjectAggregation تقوم هذه الخطوة بإعداد استجابة لعملية تجميعية وتسلسلها.

إشعار

سيستمر تحديث هذه القائمة مع إضافة عمال تشغيل جدد.

أمثلة حول كيفية تحليل استجابة ملف تعريف التنفيذ

فيما يلي أمثلة على التحسينات الشائعة التي يمكن رصدها باستخدام استجابة ملف تعريف التنفيذ:

  • استعلام مروحة خارج أعمى.
  • استعلام غير مُصفى.

أنماط استعلام توزيع المهام إلى عدة وجهات دون تمييز

افترض استجابة ملف تعريف التنفيذ التالية من رسم بياني مقسم:

[
  {
    "gremlin": "g.V('tt0093640').executionProfile()",
    "totalTime": 46,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 46,
        "annotations": {
          "percentTime": 100
        },
        "counts": {
          "resultCount": 1
        },
        "storeOps": [
          {
            "fanoutFactor": 5,
            "count": 1,
            "size": 589,
            "time": 75.61
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      }
    ]
  }
]

يمكن استخلاص الاستنتاجات التالية منه:

  • الاستعلام عبارة عن بحث معرف فردي، حيث إن عبارة Gremlin تتبع النمط g.V('id').
  • استنادا إلى time المقياس، يبدو أن زمن الانتقال مرتفع نظراً لأنه يزيد عن 10 ملّي ثانية لعملية قراءة نقطة واحدة.
  • إذا نظرنا إلى الكائن storeOps، يمكننا أن نرى أن fanoutFactor هو 5، ما يعني أنه تم الوصول إلى 5 أقسام من خلال هذه العملية.

وكنتيجة لهذا التحليل، يمكننا تحديد أن الاستعلام الأول وصل إلى أقسام أكثر من اللازم. ويمكن معالجة هذا عن طريق تحديد مفتاح التقسيم في الاستعلام كدالة تقييم. وسيؤدي ذلك إلى تقليل زمن الانتقال وتكلفة أقل لكل استعلام. اقرأ المزيد حول تقسيم الرسم البياني. وسيكون الاستعلام الأمثل g.V('tt0093640').has('partitionKey', 't1001').

أنماط الاستعلام غير المصفاة

مقارنة استجابتي ملف تعريف التنفيذ التاليتين. تستخدم هذه الأمثلة رسم بياني فردي مقسم للتبسيط.

يسترجع هذا الاستعلام الأول جميع الرؤوس ذات التسمية tweet ثم يحصل على الرؤوس المجاورة لها:

[
  {
    "gremlin": "g.V().hasLabel('tweet').out().executionProfile()",
    "totalTime": 42,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 31,
        "annotations": {
          "percentTime": 73.81
        },
        "counts": {
          "resultCount": 30
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 13,
            "size": 6819,
            "time": 1.02
          }
        ]
      },
      {
        "name": "GetEdges",
        "time": 6,
        "annotations": {
          "percentTime": 14.29
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 20,
            "size": 7950,
            "time": 1.98
          }
        ]
      },
      {
        "name": "GetNeighborVertices",
        "time": 5,
        "annotations": {
          "percentTime": 11.9
        },
        "counts": {
          "resultCount": 20
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 4,
            "size": 1070,
            "time": 1.19
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 20
        }
      }
    ]
  }
]

لاحظ ملف تعريف نفس الاستعلام، ولكن الآن باستخدام عامل تصفية إضافي، has('lang', 'en')، قبل استكشاف الرؤوس المجاورة:

[
  {
    "gremlin": "g.V().hasLabel('tweet').has('lang', 'en').out().executionProfile()",
    "totalTime": 14,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 14,
        "annotations": {
          "percentTime": 58.33
        },
        "counts": {
          "resultCount": 11
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 11,
            "size": 4807,
            "time": 1.27
          }
        ]
      },
      {
        "name": "GetEdges",
        "time": 5,
        "annotations": {
          "percentTime": 20.83
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 18,
            "size": 7159,
            "time": 1.7
          }
        ]
      },
      {
        "name": "GetNeighborVertices",
        "time": 5,
        "annotations": {
          "percentTime": 20.83
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 4,
            "size": 1070,
            "time": 1.01
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 18
        }
      }
    ]
  }
]

وصلا هذان الاستعلامان إلى نفس النتيجة، ومع ذلك، سيتطلب الاستعلام الأول المزيد من وحدات الطلب نظراً لأنه يحتاج إلى تكرار مجموعة بيانات أولية أكبر قبل الاستعلام عن العناصر المجاورة. ويمكننا رؤية مؤشرات هذا السلوك عند مقارنة المعلمات التالية من كلا الاستجابتين:

  • القيمة metrics[0].time أعلى في الاستجابة الأولى، ما يشير إلى أن هذه الخطوة الفردية استغرقت وقتاً أطول لحلها.
  • القيمة metrics[0].counts.resultsCount أعلى أيضاً في الاستجابة الأولى، ما يشير إلى أن مجموعة بيانات العمل الأولية كانت أكبر.

الخطوات التالية