سؤال

في منتجنا لدينا محرك بحث عام، ونحاول تحسين أداء البحث.تسمح الكثير من الجداول المستخدمة في الاستعلامات بقيم فارغة.هل يجب علينا إعادة تصميم جدولنا بحيث لا يسمح بالقيم الخالية للتحسين أم لا؟

منتجنا يعمل على كليهما Oracle و MS SQL Server.

هل كانت مفيدة؟

المحلول

في Oracle، فلن تتم فهرسة القيم NULL، ط. ه. هذا الاستعلام:

SELECT  *
FROM    table
WHERE   column IS NULL

وسوف دائما استخدام مسح جدول كامل منذ مؤشر لا يشمل القيم التي تحتاج إليها.

وأكثر من ذلك، وهذا الاستعلام:

SELECT  column
FROM    table
ORDER BY
        column

وسوف تستخدم أيضا مسح جدول كامل وفرز لنفس السبب.

إذا القيم الخاصة بك لا تسمح جوهريا في NULL، ثم وضع علامة العمود كما NOT NULL.

نصائح أخرى

وإجابة إضافية لرسم بعض الاهتمام اضافية لتعليق ديفيد الدريدج على الجواب Quassnoi في قبولها.

وجاء في البيان:

<اقتباس فقرة>   

وهذا الاستعلام:

     

وSELECT * FROM الجدول حيث العمود   IS NULL

     

وسوف دائما استخدام مسح الجدول الكامل

وهذا غير صحيح. هنا هو المثال مضادة باستخدام مؤشر قيمة حرفية:

SQL> create table mytable (mycolumn)
  2  as
  3   select nullif(level,10000)
  4     from dual
  5  connect by level <= 10000
  6  /

Table created.

SQL> create index i1 on mytable(mycolumn,1)
  2  /

Index created.

SQL> exec dbms_stats.gather_table_stats(user,'mytable',cascade=>true)

PL/SQL procedure successfully completed.

SQL> set serveroutput off
SQL> select /*+ gather_plan_statistics */ *
  2    from mytable
  3   where mycolumn is null
  4  /

  MYCOLUMN
----------


1 row selected.

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
  2  /

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------
SQL_ID  daxdqjwaww1gr, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ *   from mytable  where mycolumn
is null

Plan hash value: 1816312439

-----------------------------------------------------------------------------------
| Id  | Operation        | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |      1 |        |      1 |00:00:00.01 |       2 |
|*  1 |  INDEX RANGE SCAN| I1   |      1 |      1 |      1 |00:00:00.01 |       2 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("MYCOLUMN" IS NULL)


19 rows selected.

وكما ترون، يتم استخدام المؤشر.

والتحيات، روب.

والجواب باختصار: نعم، بشروط

والقضية الرئيسية مع القيم الخالية والأداء هو أن تفعل مع عمليات البحث إلى الأمام.

إذا قمت بإدراج صف في الجدول، مع القيم الخالية، انها وضعت في صفحة الطبيعية التي ينتمي إليها. وأي استفسار أبحث عن هذا السجل يجد في المكان المناسب. من السهل حتى الآن ....

... ولكن دعونا نقول صفحة تمتلئ، والآن محضون هذا الصف في بين الصفوف الأخرى. لا تزال تسير على ما يرام ...

... حتى يتم تحديث صف واحد، ويحتوي على قيمة فارغة الآن شيئا. وزاد حجم الصف وخارج الحيز المتاح له، وبالتالي فإن المحرك DB أن نفعل شيئا حيال ذلك.

وأسرع شيء لخادم القيام به هو نقل صف <م> من تلك الصفحة إلى آخر، والاستعاضة دخول الصف مع مؤشر إلى الأمام. للأسف، وهذا يتطلب بحث إضافية عندما يتم تنفيذ استعلام: واحد للعثور على المكان الطبيعي للصف واحد، واحد للعثور على موقعه الحالي

ولذا، فإن الجواب القصير على سؤالك هو نعم، مما يجعل تلك الحقول غير قيم الفارغة سيساعد أداء البحث. هذا ينطبق بشكل خاص إذا كان كثيرا ما يحدث أن حقول فارغة في سجلات كنت تبحث عن وتحديثها لغير فارغة.

وبطبيعة الحال، هناك عقوبات أخرى (ولا سيما I / O، على الرغم من أن عمق مؤشر مدى صغير) المرتبطة مع مجموعات البيانات الكبيرة، ومن ثم كان لديك مشاكل التطبيق مع عدم السماح بلا قيم في المجالات التي تتطلب منهم من الناحية النظرية، ولكن مهلا، هذا آخر مشكلة:)

إذا كان العمود الخاص بك لا يحتوي على قيم خالية، فمن الأفضل الإعلان عن هذا العمود NOT NULL, ، قد يكون المُحسِّن قادرًا على اتخاذ مسار أكثر كفاءة.

ومع ذلك، إذا كان لديك قيم فارغة في عمودك، فلن يكون لديك الكثير من الخيارات (قد تؤدي القيمة الافتراضية غير الخالية إلى إنشاء مشكلات أكثر مما تحلها).

كما ذكر Quassnoi، لا تتم فهرسة القيم الخالية في Oracle، أو لنكون أكثر دقة، لن تتم فهرسة الصف إذا كانت جميع الأعمدة المفهرسة فارغة، وهذا يعني:

  • من المحتمل أن تؤدي القيم الخالية إلى تسريع بحثك لأن الفهرس سيحتوي على صفوف أقل
  • لا يزال بإمكانك فهرسة الصفوف الخالية إذا قمت بإضافة عمود NOT NULL آخر إلى الفهرس أو حتى ثابت.

يوضح البرنامج النصي التالي طريقة لفهرسة القيم الخالية:

CREATE TABLE TEST AS 
SELECT CASE
          WHEN MOD(ROWNUM, 100) != 0 THEN
           object_id
          ELSE
           NULL
       END object_id
  FROM all_objects;

CREATE INDEX idx_null ON test(object_id, 1);

SET AUTOTRACE ON EXPLAIN

SELECT COUNT(*) FROM TEST WHERE object_id IS NULL;

وأود أن أقول أن هناك حاجة إلى اختبار ولكن من الجميل أن نعرف تجارب الشعوب الأخرى. في تجربتي على ماجستير خادم SQL، بلا قيم يمكن ولا يسبب مشكلات في الأداء الضخمة (الخلافات). في اختبار بسيط للغاية الآن لقد رأيت عودة الاستعلام في 45 ثانية عندما تم تعيين غير فارغة على المجالات ذات الصلة في الجدول خلق بيان وأكثر من 25 دقيقة حيث لم يتم تعيين (فاكتفيت انتظار وأخذ مجرد الذروة في خطة الاستعلام يقدر).

وبيانات الاختبار هو 1 مليون صف × 20 الأعمدة التي يتم بناؤها من 62 حرفا ألفا صغيرة عشوائية على HD العادي i5-3320 و 8GB RAM (SQL Server باستخدام 2GB) / SQL خادم 2012 Enterprise Edition على ويندوز 8.1. من المهم أن تستخدم / البيانات بيانات عشوائية غير منتظمة لجعل اختبار واقعية "أسوأ" القضية. في كل الحالات الجدول تم صوغه وإعادة تحميل مع البيانات العشوائية التي استغرقت نحو 30 ثانية على ملفات قاعدة البيانات التي لديها بالفعل كمية مناسبة من المساحة الحرة.

select count(field0) from myTable where field0 
                     not in (select field1 from myTable) 1000000

CREATE TABLE [dbo].[myTable]([Field0] [nvarchar](64) , ...

 vs

CREATE TABLE [dbo].[myTable]([Field0] [nvarchar](64) not null,

ولأسباب تتعلق بالأداء على حد سواء قد تم تعثر الجدول الخيار data_compression = مجموعة صفحات وكل شيء آخر. لم فهارس.

alter table myTable rebuild partition = all with (data_compression = page);

وعدم وجود القيم الخالية هو شرط لفي الجداول الذاكرة الأمثل لوأنا لست على وجه التحديد باستخدام ومع ذلك مزود خدمة ستفعل الواضح ما هو أسرع وهو في هذه الحالة المحددة يبدو أن نطاق واسع لصالح عدم وجود القيم الخالية في البيانات واستخدام ليس لاغية على خلق الجدول.

وأي الاستعلامات اللاحقة من نفس النموذج على هذه العودة الجدول في ثانيتين لذلك أود أن نفترض إحصاءات الافتراضي القياسية وربما وجود (1.3GB) الجدول صالح في الذاكرة تعمل بشكل جيد. أي بمعنى.

select count(field19) from myTable where field19 
                       not in (select field18 from myTable) 1000000

في جانبا عدم وجود القيم الخالية وعدم الاضطرار إلى التعامل مع الحالات فارغة أيضا يجعل الاستفسارات الكثير من أبسط، وأقصر، وأقل عرضة للخطأ وعادة جدا بشكل أسرع. إذا كان ذلك ممكنا، وأفضل لتجنب بلا قيم عموما على السيدة مزود خدمة على الأقل ما لم يطلب صراحة هم وليس من المعقول أن عملت بها من الحل.

وبدءا من الجدول الجديد والتحجيم هذا ما يصل إلى 10M الصفوف / 13GB يأخذ نفس الاستعلام 12 دقيقة وهو محترم جدا بالنظر إلى الأجهزة ولم فهارس في الاستخدام. لمزيد من المعلومات الاستعلام كان تماما IO ملزمة مع IO تتراوح ما بين 20MB / s إلى 60MB / ثانية. ووقع تكرار نفس الاستعلام 9 دقائق.

وحقول Nullable ويمكن أن يكون لها تأثير كبير على الأداء عند القيام "NOT IN" استفسار. بسبب خلافات مع جميع الحقول المفهرسة لتعيين لاغية وغير مفهرسة في الفهارس B-شجرة، يجب أوراكل القيام مسح الجدول الكامل للتحقق من entires فارغة، حتى عند وجود مؤشر.

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

create table t1 as select rownum rn from all_objects;

create table t2 as select rownum rn from all_objects;

create unique index t1_idx on t1(rn);

create unique index t2_idx on t2(rn);

delete from t2 where rn = 3;

explain plan for
select *
  from t1
 where rn not in ( select rn
                     from t2 );

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      | 50173 |   636K|  3162   (1)| 00:00:38 |
|*  1 |  FILTER            |      |       |       |            |          |
|   2 |   TABLE ACCESS FULL| T1   | 50205 |   637K|    24   (5)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| T2   | 45404 |   576K|     2   (0)| 00:00:01 |
---------------------------------------------------------------------------

والاستعلام يجب أن تحقق لقيم فارغة لذلك له علاقة تفحص الجدول الكامل من T2 لكل صف في T1.

والآن، إذا يمكننا أن نجعل من الحقول غير قيم الفارغة، فإنه يمكن استخدام الفهرس.

alter table t1 modify rn not null;

alter table t2 modify rn not null;

explain plan for
select *
  from t1
 where rn not in ( select rn
                     from t2 );

-----------------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |  2412 | 62712 |    24   (9)| 00:00:01 |
|   1 |  NESTED LOOPS ANTI |        |  2412 | 62712 |    24   (9)| 00:00:01 |
|   2 |   INDEX FULL SCAN  | T1_IDX | 50205 |   637K|    21   (0)| 00:00:01 |
|*  3 |   INDEX UNIQUE SCAN| T2_IDX | 45498 |   577K|     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------

ومسألة ما إذا كان استخدام بالقيم الخالية لأنها تؤثر على أداء واحدة من تلك الموازنة بين أعمال تصميم قاعدة البيانات. لديك لتحقيق التوازن بين احتياجات العمل ضد الأداء.

وينبغي أن تستخدم

وبلا قيم إذا ما لزم الأمر. على سبيل المثال، قد يكون لديك بدء التاريخ وتاريخ انتهاء في جدول. كنت في كثير من الأحيان لا يعرف تاريخ انتهاء وقت إنشاء السجل. لذلك يجب السماح بلا قيم ما إذا كانت تؤثر على الأداء أم لا كما يتضح من البيانات هي ببساطة ليست هناك لوضعها في. ومع ذلك، إذا كان لا بد من البيانات، وفقا لقواعد العمل، أن يكون هناك وقت إنشاء السجل، ثم لا ينبغي أن يسمح بلا قيم. وهذا من شأنه تحسين الأداء، وجعل الترميز أبسط قليلا وتأكد من الحفاظ على سلامة البيانات.

إذا كان لديك البيانات الموجودة التي ترغب في تغيير للم تعد تسمح بلا قيم، ثم عليك أن تنظر في تأثير هذا التغيير. أولا، هل تعرف ما هي القيمة التي تحتاج إليها لوضعها في السجلات التي تكون فارغة حاليا؟ ثانيا، هل لديك الكثير من التعليمات البرمجية التي تستخدم isnull أو coalesce التي تحتاج إلى تحديث (هذه الأشياء بطء الأداء، حتى إذا كنت لم تعد بحاجة للتحقق من هذه المواقع، فيجب تغيير رمز)؟ هل تحتاج إلى القيمة الافتراضية؟ يمكنك حقا تعيين واحد؟ إذا لن بعض من نهاية الشوط الاول إدراج أو تحديث كود إذا لم يتم النظر في هذا الميدان لم يعد لاغيا. في بعض الأحيان سوف يضع الناس في المعلومات السيئة للسماح لهم للتخلص من بالقيم الخالية. وحتى الآن يحتاج حقل السعر لاحتواء القيم العشرية واشياء من هذا القبيل "غير معروف"، وبالتالي لا يمكن أن يكون صحيح نوع بيانات عشري ثم عليك أن تذهب إلى كل أنواع من أطوال من أجل القيام بعمليات حسابية. هذا غالبا ما يخلق مشاكل الأداء بأنها سيئة أو أسوأ من لاغية بإنشائه. بالإضافة إلى أنك بحاجة للذهاب من خلال كل ما تبذلونه من رمز وأي وقت مضى حيث كنت تستخدم REFERNCE لرفعها كونها خالية أو لا يتم فارغة، تحتاج إلى إعادة كتابة لاستبعاد أو تضمين على أساس من الممكن القيم السيئة شخص سوف يضع في becasue البيانات غير مسموح لاغيا.

وأفعل الكثير من واردات البيانات من بيانات العملاء، وفي كل مرة نحصل على الملف حيث بعض الحقول التي يجب أن تسمح بلا قيم لا نحصل على بيانات القمامة التي تحتاج إلى تنظيف قبل أن استيراد لنظامنا. البريد الإلكتروني هو واحد من هؤلاء. غالبا ما تكون البيانات مدخلات لا يعرفون هذه القيمة وانها عموما نوع من سلسلة البيانات، بحيث يمكن للمستخدم كتابة أي شيء هنا. نذهب لاستيراد رسائل البريد الإلكتروني والعثور على أشياء "لا أعرف". صعبة في محاولة لارسال الواقع بريد الكتروني الى "لا أعرف". إذا كان النظام requres عنوان بريد إلكتروني صالح ويتحقق شيء من هذا القبيل الى وجود علامة @، سوف نحصل على "I@dont.know" كيف البيانات القمامة مثل هذه مفيدة لمستخدمي البيانات؟

وبعض مشكلات الأداء مع القيم الخالية هي نتيجة كتابة الاستفسارات nonsargable. في بعض الأحيان مجرد إعادة ترتيب شرط حيث بدلا من القضاء فارغة من الضروري يمكن تحسين الأداء.

في تجربتي NULL هي قيمة صالحة، وعادة ما يعني "لا أعرف". إذا كنت لا تعرف ثم هو حقا لا طائل لتعويض بعض القيمة الافتراضية للعمود أو في محاولة لفرض بعض القيود NOT NULL. NULL يحدث لمجرد أن يكون حالة معينة.

والتحدي الحقيقي لبالقيم الفارغة هل هو تعقيد استرجاع بعض الشيء. على سبيل المثال لا يمكنك أن تقول أين COLUMN_NAME IN (NULL، "VALUE1 '،' و value2 ').

وشخصيا إذا وجدت الكثير من الأعمدة الخاصة بك، أو بعض الأعمدة تحتوي على الكثير من القيم الخالية أعتقد أنك قد ترغب في إعادة النظر في نموذج البيانات الخاصة بك. ربما هذه الأعمدة فارغة يمكن وضعها في الجدول التابع؟ على سبيل المثال: جدول مع أرقام الهاتف حيث أنها اسم، homephone، والهواتف المحمولة، faxno، worknumber، emergencynumber الخ ... يمكنك تعبئة واحد فقط أو اثنين من هؤلاء وسيكون تطبيع بطريقة أفضل

.

ما عليك القيام به هو خطوة الى الوراء ونرى كيف سيتم الوصول إلى البيانات. هل هذا العمود الذي ينبغي أن يكون لها قيمة؟ هل هذا العمود الذي ليس لديها سوى قيمة لبعض الحالات؟ هل هذا العمود الذي سيتم الاستعلام كثيرا؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top