@@ -9166,153 +9166,163 @@ void JOIN::finalize_derived_keys() {
91669166 assert (query_block->materialized_derived_table_count );
91679167 ASSERT_BEST_REF_IN_JOIN_ORDER (this );
91689168
9169- bool adjust_key_count = false ;
91709169 table_map processed_tables = 0 ;
91719170
91729171 for (uint i = 0 ; i < tables; i++) {
9173- JOIN_TAB *tab = best_ref[i];
9174- TABLE *table = tab->table ();
9175- Table_ref *table_ref = tab->table_ref ;
9172+ TABLE *const table = best_ref[i]->table ();
9173+ Table_ref *const tr = best_ref[i]->table_ref ;
91769174 /*
9177- Save chosen key description if:
9178- 1) it's a materialized derived table
9179- 2) it's not yet instantiated
9180- 3) some keys are defined for it
9175+ Process the table's key definitions if:
9176+ 1) it is a materialized derived table, and
9177+ 2) it is not yet instantiated, and
9178+ 3) it has some keys defined, and
9179+ 4) it has not yet been processed (may happen if there are more than one
9180+ local references to the same CTE, which are processed on seeing the
9181+ first reference).
91819182 */
9182- if (table && table_ref->uses_materialization () && // (1)
9183- !table->is_created () && // (2)
9184- table->s ->keys > 0 ) // (3)
9185- {
9186- /*
9187- If there are two local references to the same CTE, and they use
9188- the same key, the iteration for the second reference is unnecessary.
9189- */
9190- if (processed_tables & table_ref->map ()) continue ;
9191-
9192- adjust_key_count = true ;
9183+ if (table == nullptr || !tr->uses_materialization () || // (1)
9184+ table->is_created () || // (2)
9185+ table->s ->keys == 0 || // (3)
9186+ (processed_tables & tr->map ())) { // (4)
9187+ continue ;
9188+ }
9189+ /*
9190+ Collect all used keys before starting to shuffle them:
9191+ First create a map from key number to the table using the key:
9192+ */
9193+ assert (table->s ->keys <= MAX_INDEXES);
9194+ TABLE *table_map[MAX_INDEXES];
9195+ for (uint j = 0 ; j < table->s ->keys ; j++) {
9196+ table_map[j] = nullptr ;
9197+ }
91939198
9194- Key_map used_keys;
9199+ Key_map used_keys;
91959200
9196- // Mark all unique indexes as in use, since they have an effect
9197- // (deduplication) whether any expression refers to them or not.
9198- // In particular, they are used if we want to materialize a UNION DISTINCT
9199- // directly into the derived table.
9200- for (uint key_idx = 0 ; key_idx < table->s ->keys ; ++key_idx) {
9201- if (table->key_info [key_idx].flags & HA_NOSAME) {
9202- used_keys.set_bit (key_idx);
9203- }
9201+ // Mark all unique indexes as in use, since they have an effect
9202+ // (deduplication) whether any expression refers to them or not.
9203+ // In particular, they are used if we want to materialize a UNION DISTINCT
9204+ // directly into the derived table.
9205+ for (uint key_idx = 0 ; key_idx < table->s ->keys ; ++key_idx) {
9206+ if (table->key_info [key_idx].flags & HA_NOSAME) {
9207+ used_keys.set_bit (key_idx);
92049208 }
9209+ }
9210+ // Same for the hash key used for manual deduplication, if any.
9211+ // (It always has index 0 if it exists.)
9212+ if (table->hash_field ) {
9213+ used_keys.set_bit (0 );
9214+ }
92059215
9206- // Same for the hash key used for manual deduplication, if any. (It always
9207- // has index 0 if it exists.)
9208- if (table->hash_field ) {
9209- used_keys.set_bit (0 );
9210- }
9216+ Derived_refs_iterator it (tr);
92119217
9212- Key_use *const keyuse = tab->position ()->key ;
9213- if (keyuse == nullptr && used_keys.is_clear_all ()) {
9214- // Nothing uses any keys.
9215- tab->keys ().clear_all ();
9216- tab->const_keys .clear_all ();
9218+ while (TABLE *t = it.get_next ()) {
9219+ if (t->pos_in_table_list ->query_block != query_block) {
92179220 continue ;
92189221 }
9222+ JOIN_TAB *jtab = t->reginfo .join_tab ;
9223+ Key_use *const keyuse = jtab->position ()->key ;
9224+ if (keyuse != nullptr ) {
9225+ used_keys.set_bit (keyuse->key );
9226+ table_map[keyuse->key ] = t;
9227+ } else {
9228+ jtab->keys ().clear_all ();
9229+ jtab->const_keys .clear_all ();
9230+ processed_tables |= t->pos_in_table_list ->map ();
9231+ }
9232+ }
9233+ /*
9234+ This call is required to establish the initial value for
9235+ TABLE_SHARE::first_unused_tmp_key.
9236+ */
9237+ (void )table->s ->find_first_unused_tmp_key (used_keys);
92199238
9220- Derived_refs_iterator it (table_ref);
9221- while (TABLE *t = it.get_next ()) {
9222- /*
9223- Eliminate possible keys created by this JOIN and which it
9224- doesn't use.
9225- Collect all keys of this table which are used by any reference in
9226- this query block. Any other query block doesn't matter as:
9227- - either it was optimized before, so it's not using a key we may
9239+ // Process keys in increasing key order
9240+ for (uint j = 0 ; j < table->s ->keys ; j++) {
9241+ TABLE *const t = table_map[j];
9242+ if (t == nullptr ) continue ;
9243+
9244+ /*
9245+ Eliminate possible keys created by this JOIN and which it doesn't use.
9246+ Collect all keys of this table which are used by any reference in
9247+ this query block. Any other query block doesn't matter as:
9248+ - either it was optimized before, so it's not using a key we may
92289249 want to drop.
9229- - or it was optimized in this same window, so:
9230- * either we own the window, then any key we may want to
9250+ - or it was optimized in this same window, so:
9251+ * either we own the window, then any key we may want to
92319252 drop is not visible to it.
9232- * or it owns the window, then we are using only existing
9233- keys.
9234- - or it will be optimized after, so it's not using any key yet.
9235-
9236- used_keys is a mix of possible used keys and existing used keys.
9237- */
9238- if (t->pos_in_table_list ->query_block == query_block) {
9239- JOIN_TAB *jtab = t->reginfo .join_tab ;
9240- Key_use *keyuse_1 = jtab->position ()->key ;
9241- if (keyuse_1) used_keys.set_bit (keyuse_1->key );
9242- }
9243- }
9253+ * or it owns the window, then we are using only existing keys.
9254+ - or it will be optimized after, so it's not using any key yet.
92449255
9245- uint new_idx = table-> s -> find_first_unused_tmp_key (
9246- used_keys); // Also updates table->s->first_unused_tmp_key.
9247- if (keyuse == nullptr ) {
9256+ used_keys is a mix of possible used keys and existing used keys.
9257+ */
9258+ if (t-> pos_in_table_list -> query_block != query_block ) {
92489259 continue ;
92499260 }
92509261
9262+ JOIN_TAB *jtab = t->reginfo .join_tab ;
9263+ Key_use *const keyuse = jtab->position ()->key ;
9264+ assert (keyuse != nullptr );
9265+
9266+ // Also updates table->s->first_unused_tmp_key.
9267+ uint new_idx = t->s ->find_first_unused_tmp_key (used_keys);
9268+
92519269 const uint old_idx = keyuse->key ;
92529270 assert (old_idx != new_idx);
92539271
92549272 if (old_idx > new_idx) {
9255- assert (table ->s ->owner_of_possible_tmp_keys == query_block);
9256- it. rewind ( );
9257- while (TABLE *t = it .get_next ()) {
9273+ assert (t ->s ->owner_of_possible_tmp_keys == query_block);
9274+ Derived_refs_iterator it1 (tr );
9275+ while (TABLE *t1 = it1 .get_next ()) {
92589276 /*
92599277 Unlike the collection of used_keys, references from other query
92609278 blocks must be considered here, as they need a key_info array
92619279 consistent with the to-be-changed table->s->keys.
92629280 */
9263- t ->move_tmp_key (old_idx, it .is_first ());
9281+ t1 ->move_tmp_key (old_idx, it1 .is_first ());
92649282 }
9265- } else
9283+ used_keys.clear_bit (old_idx);
9284+ used_keys.set_bit (new_idx);
9285+ } else {
92669286 new_idx = old_idx; // Index stays at same slot
9287+ }
92679288
92689289 /*
92699290 If the key was created by earlier-optimized query blocks, and is
92709291 already used by nonlocal references, those don't need any further
9271- update: they are already setup to use it and we're not moving the
9272- key.
9292+ update: they are already setup to use it and we're not moving the key.
92739293 If the key was created by this query block, nonlocal references cannot
92749294 possibly be referencing it.
92759295 In both cases, only local references need to update their Key_use.
92769296 */
9277- it. rewind ( );
9278- while (TABLE *t = it .get_next ()) {
9279- if (t ->pos_in_table_list ->query_block != query_block) continue ;
9280- JOIN_TAB *jtab = t ->reginfo .join_tab ;
9281- Key_use *keyuse_1 = jtab ->position ()->key ;
9282- if (keyuse_1 && keyuse_1 ->key == old_idx) {
9283- processed_tables |= t ->pos_in_table_list ->map ();
9284- const bool key_is_const = jtab ->const_keys .is_set (old_idx);
9297+ Derived_refs_iterator it2 (tr );
9298+ while (TABLE *t2 = it2 .get_next ()) {
9299+ if (t2 ->pos_in_table_list ->query_block != query_block) continue ;
9300+ JOIN_TAB *jt2 = t2 ->reginfo .join_tab ;
9301+ Key_use *ku2 = jt2 ->position ()->key ;
9302+ if (ku2 != nullptr && ku2 ->key == old_idx) {
9303+ processed_tables |= t2 ->pos_in_table_list ->map ();
9304+ const bool key_is_const = jt2 ->const_keys .is_set (old_idx);
92859305 // tab->keys() was never set, so must be set
9286- jtab ->keys ().clear_all ();
9287- jtab ->keys ().set_bit (new_idx);
9288- jtab ->const_keys .clear_all ();
9289- if (key_is_const) tab ->const_keys .set_bit (new_idx);
9290- for (Key_use *kit = keyuse_1 ;
9291- kit->table_ref == jtab ->table_ref && kit->key == old_idx; kit++)
9306+ jt2 ->keys ().clear_all ();
9307+ jt2 ->keys ().set_bit (new_idx);
9308+ jt2 ->const_keys .clear_all ();
9309+ if (key_is_const) jt2 ->const_keys .set_bit (new_idx);
9310+ for (Key_use *kit = ku2 ;
9311+ kit->table_ref == jt2 ->table_ref && kit->key == old_idx; kit++) {
92929312 kit->key = new_idx;
9313+ }
92939314 }
92949315 }
92959316 }
9296- }
92979317
9298- if (!adjust_key_count) return ;
9318+ // Finally, we know how many keys remain in the table.
9319+ if (table->s ->owner_of_possible_tmp_keys != query_block) continue ;
92999320
9300- // Finally we know how many keys remain in the table.
9301- for (uint i = 0 ; i < tables; i++) {
9302- JOIN_TAB *tab = best_ref[i];
9303- TABLE *table = tab->table ();
9304- Table_ref *table_ref = tab->table_ref ;
9305- if (table && table_ref->uses_materialization () && !table->is_created () &&
9306- table->s ->keys > 0 ) {
9307- if (table->s ->owner_of_possible_tmp_keys != query_block) continue ;
9308- /*
9309- Release lock. As a bonus, avoid double work when this loop
9310- later processes another local reference to the same table (similar to
9311- the processed_tables map in the first loop).
9312- */
9313- table->s ->owner_of_possible_tmp_keys = nullptr ;
9314- Derived_refs_iterator it (table_ref);
9315- while (TABLE *t = it.get_next ()) t->drop_unused_tmp_keys (it.is_first ());
9321+ // Release lock:
9322+ table->s ->owner_of_possible_tmp_keys = nullptr ;
9323+ it.rewind ();
9324+ while (TABLE *t = it.get_next ()) {
9325+ t->drop_unused_tmp_keys (it.is_first ());
93169326 }
93179327 }
93189328}
0 commit comments