PrG_Indexing_Superfiles.xml 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
  3. "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
  4. <sect1 id="Indexing_into_SuperFiles">
  5. <title><emphasis role="bold">Indexing into SuperFiles</emphasis></title>
  6. <sect2 id="SuperFiles_vs_SuperKeys">
  7. <title>SuperFiles vs. SuperKeys</title>
  8. <para>A SuperFile may contain INDEX files instead of DATASET files, making
  9. it a SuperKey. All the same creation and maintenance processes and
  10. principles apply as described previously in the <emphasis>Creating and
  11. Maintaining SuperFiles</emphasis> article.</para>
  12. <para>However, <emphasis role="bold">a SuperKey may not contain INDEX
  13. sub-files that directly reference the sub-files of a SuperFile using the
  14. {virtual(fileposition)} “record pointer” mechanism </emphasis>(used by
  15. FETCH and full-keyed JOIN operations). This is because the
  16. {virtual(fileposition)} field is a virtual (exists only when the file is
  17. read from disk) field containing the relative byte position of each record
  18. within the single logical entity.</para>
  19. <para>The following attribute definitions used by the code examples in
  20. this article are declared in the DeclareData MODULE structure
  21. attribute:</para>
  22. <programlisting>EXPORT i1name := '~PROGGUIDE::SUPERKEY::IDX1';
  23. EXPORT i2name := '~PROGGUIDE::SUPERKEY::IDX2';
  24. EXPORT i3name := '~PROGGUIDE::SUPERKEY::IDX3';
  25. EXPORT SFname := '~PROGGUIDE::SUPERKEY::SF1';
  26. EXPORT SKname := '~PROGGUIDE::SUPERKEY::SK1';
  27. EXPORT ds1 := DATASET(SubFile1,{Layout_Person,UNSIGNED8 RecPos {VIRTUAL(fileposition)}},THOR);
  28. EXPORT ds2 := DATASET(SubFile2,{Layout_Person,UNSIGNED8 RecPos {VIRTUAL(fileposition)}},THOR);
  29. EXPORT i1 := INDEX(ds1,{personid,RecPos},i1name);
  30. EXPORT i2 := INDEX(ds2,{personid,RecPos},i2name);
  31. EXPORT sf1 := DATASET(SFname,{Layout_Person,UNSIGNED8 RecPos {VIRTUAL(fileposition)}},THOR);
  32. EXPORT sk1 := INDEX(sf1,{personid,RecPos},SKname);
  33. EXPORT sk2 := INDEX(sf1,{personid,RecPos},i3name );
  34. </programlisting>
  35. </sect2>
  36. <sect2 id="There_is_a_Problem">
  37. <title>There is a Problem</title>
  38. <para>The easiest way to illustrate the problem is to run the following
  39. code (this code is contained in IndexSuperFile1.ECL) that uses two of the
  40. sub-files from the <emphasis>Creating and Maintaining
  41. SuperFiles</emphasis> article.</para>
  42. <programlisting>IMPORT $;
  43. OUTPUT($.DeclareData.ds1);
  44. OUTPUT($.DeclareData.ds2);
  45. </programlisting>
  46. <para>You will notice that the RecPos values returned for both of these
  47. datasets are exactly the same (0, 89, 178 ... ), which is to be expected
  48. since they both have the same fixed-length RECORD structure. The problem
  49. lies in using that field when building separate INDEXes for the two
  50. datasets. It works perfectly as separate INDEXes into separate
  51. DATASETs.</para>
  52. <para>For example, you can use this code to build and test the separate
  53. INDEXes (contained in IndexSuperFile2.ECL):</para>
  54. <programlisting>IMPORT $;
  55. Bld := PARALLEL(BUILDINDEX($.DeclareData.i1,OVERWRITE),BUILDINDEX($.DeclareData.i2,OVERWRITE));
  56. F1 := FETCH($.DeclareData.ds1,
  57. $.DeclareData.i1(personid=$.DeclareData.ds1[1].personid),
  58. RIGHT.RecPos);
  59. F2 := FETCH($.DeclareData.ds2,
  60. $.DeclareData.i2(personid=$.DeclareData.ds2[1].personid),
  61. RIGHT.RecPos);
  62. Get := PARALLEL(OUTPUT(F1),OUTPUT(F2));
  63. SEQUENTIAL(Bld,Get);
  64. </programlisting>
  65. <para>As you can see, two different records are returned by the two FETCH
  66. operations. However, when you create a SuperFile and a SuperKey and then
  67. try using them to do the same two FETCHes again, they both return the same
  68. record, as shown by this code (contained in IndexSuperFile3.ECL):</para>
  69. <programlisting>IMPORT $;
  70. IMPORT Std;
  71. BldSF := SEQUENTIAL(
  72. Std.File.CreateSuperFile($.DeclareData.SFname),
  73. Std.File.CreateSuperFile($.DeclareData.SKname),
  74. Std.File.StartSuperFileTransaction(),
  75. Std.File.AddSuperFile($.DeclareData.SFname,$.DeclareData.SubFile1),
  76. Std.File.AddSuperFile($.DeclareData.SFname,$.DeclareData.SubFile2),
  77. Std.File.AddSuperFile($.DeclareData.SKname,$.DeclareData.i1name),
  78. Std.File.AddSuperFile($.DeclareData.SKname,$.DeclareData.i2name),
  79. Std.File.FinishSuperFileTransaction());
  80. F1 := FETCH($.DeclareData.sf1,
  81. $.DeclareData.sk1(personid=$.DeclareData.ds1[1].personid),
  82. RIGHT.RecPos);
  83. F2 := FETCH($.DeclareData.sf1,
  84. $.DeclareData.sk1(personid=$.DeclareData.ds2[1].personid),
  85. RIGHT.RecPos);
  86. Get := PARALLEL(OUTPUT(F1),OUTPUT(F2));
  87. SEQUENTIAL(BldSF,Get);
  88. </programlisting>
  89. <para>Once you combine the DATASETS into a SuperFile and combine the
  90. INDEXes into a SuperKey, you then have multiple entries in the SuperKey,
  91. with different key field values, that all point to the same physical
  92. record in the SuperFile, because the record pointer values are the
  93. same.</para>
  94. </sect2>
  95. <sect2 id="And_the_Solution_Is">
  96. <title>And the Solution Is ...</title>
  97. <para>The way around this problem is to create a single INDEX into the
  98. SuperFile, as shown by this code (contained in
  99. IndexSuperFile4.ECL):</para>
  100. <programlisting>IMPORT $;
  101. F1 := FETCH($.DeclareData.sf1,
  102. $.DeclareData.sk2(personid=$.DeclareData.ds1[1].personid),
  103. RIGHT.RecPos);
  104. F2 := FETCH($.DeclareData.sf1,
  105. $.DeclareData.sk2(personid=$.DeclareData.ds2[1].personid),
  106. RIGHT.RecPos);
  107. Get := PARALLEL(OUTPUT(F1),OUTPUT(F2));
  108. SEQUENTIAL(BUILDINDEX($.DeclareData.sk2,OVERWRITE),Get);
  109. </programlisting>
  110. <para>When you use a single INDEX instead of a SuperKey, the FETCH
  111. operations once again retrieve the correct records.</para>
  112. </sect2>
  113. </sect1>