1 21 22 package org.apache.derby.impl.sql.compile; 23 24 import org.apache.derby.iapi.services.sanity.SanityManager; 25 26 import org.apache.derby.iapi.error.StandardException; 27 28 import org.apache.derby.iapi.sql.compile.JoinStrategy; 29 import org.apache.derby.iapi.sql.compile.Optimizable; 30 import org.apache.derby.iapi.sql.compile.OptimizableList; 31 import org.apache.derby.iapi.sql.compile.OptimizablePredicate; 32 import org.apache.derby.iapi.sql.compile.OptimizablePredicateList; 33 import org.apache.derby.iapi.sql.compile.Optimizer; 34 import org.apache.derby.iapi.sql.compile.CostEstimate; 35 import org.apache.derby.iapi.sql.compile.RequiredRowOrdering; 36 import org.apache.derby.iapi.sql.compile.RowOrdering; 37 import org.apache.derby.iapi.sql.compile.AccessPath; 38 39 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; 40 41 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor; 42 import org.apache.derby.iapi.sql.dictionary.DataDictionary; 43 import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator; 44 import org.apache.derby.iapi.sql.dictionary.TableDescriptor; 45 46 import org.apache.derby.iapi.reference.SQLState; 47 48 import org.apache.derby.iapi.util.JBitSet; 49 50 import org.apache.derby.impl.sql.compile.OptimizerImpl; 51 import org.apache.derby.impl.sql.compile.CostEstimateImpl; 52 53 import java.util.Properties ; 54 55 58 59 public class Level2OptimizerImpl extends OptimizerImpl 60 { 61 private LanguageConnectionContext lcc; 62 63 Level2OptimizerImpl(OptimizableList optimizableList, 64 OptimizablePredicateList predicateList, 65 DataDictionary dDictionary, 66 boolean ruleBasedOptimization, 67 boolean noTimeout, 68 boolean useStatistics, 69 int maxMemoryPerTable, 70 JoinStrategy[] joinStrategies, 71 int tableLockThreshold, 72 RequiredRowOrdering requiredRowOrdering, 73 int numTablesInQuery, 74 LanguageConnectionContext lcc) 75 throws StandardException 76 { 77 super(optimizableList, predicateList, dDictionary, 78 ruleBasedOptimization, noTimeout, useStatistics, maxMemoryPerTable, 79 joinStrategies, tableLockThreshold, requiredRowOrdering, 80 numTablesInQuery); 81 82 optimizerTrace = lcc.getOptimizerTrace(); 84 optimizerTraceHtml = lcc.getOptimizerTraceHtml(); 85 this.lcc = lcc; 86 87 if (optimizerTrace) 89 { 90 trace(STARTED, 0, 0, 0.0, null); 91 } 92 } 93 94 95 public int getLevel() 96 { 97 return 2; 98 } 99 100 101 public CostEstimate newCostEstimate() 102 { 103 return new Level2CostEstimateImpl(); 104 } 105 106 public CostEstimateImpl getNewCostEstimate(double theCost, 107 double theRowCount, 108 double theSingleScanRowCount) 109 { 110 return new Level2CostEstimateImpl(theCost, theRowCount, theSingleScanRowCount); 111 } 112 113 public void trace(int traceFlag, int intParam1, int intParam2, 115 double doubleParam, Object objectParam1) 116 { 117 ConglomerateDescriptor cd; 118 String cdString; 119 String traceString = null; 120 121 if (!optimizerTrace) 123 { 124 return; 125 } 126 127 switch (traceFlag) 128 { 129 case STARTED: 130 traceString = 131 "Optimization started at time " + 132 timeOptimizationStarted + 133 " using optimizer " + this.hashCode(); 134 break; 135 136 case TIME_EXCEEDED: 137 traceString = 138 "Optimization time exceeded at time " + 139 currentTime + "\n" + bestCost(); 140 break; 141 142 case NO_TABLES: 143 traceString = "No tables to optimize."; 144 break; 145 146 case COMPLETE_JOIN_ORDER: 147 traceString = "We have a complete join order."; 148 break; 149 150 case COST_OF_SORTING: 151 traceString = 152 "Cost of sorting is " + sortCost; 153 break; 154 155 case NO_BEST_PLAN: 156 traceString = 157 "No best plan found."; 158 break; 159 160 case MODIFYING_ACCESS_PATHS: 161 traceString = 162 "Modifying access paths using optimizer " + this.hashCode(); 163 break; 164 165 case SHORT_CIRCUITING: 166 String basis = (timeExceeded) ? "time exceeded" : "cost"; 167 Optimizable thisOpt = 168 optimizableList.getOptimizable( 169 proposedJoinOrder[joinPosition]); 170 if (thisOpt.getBestAccessPath().getCostEstimate() == null) 171 basis = "no best plan found"; 172 traceString = 173 "Short circuiting based on " + basis + 174 " at join position " + joinPosition; 175 break; 176 177 case SKIPPING_JOIN_ORDER: 178 traceString = buildJoinOrder("\n\nSkipping join order: ", true, intParam1, 179 proposedJoinOrder); 180 break; 181 182 case ILLEGAL_USER_JOIN_ORDER: 183 traceString = 184 "User specified join order is not legal."; 185 break; 186 187 case USER_JOIN_ORDER_OPTIMIZED: 188 traceString = 189 "User-specified join order has now been optimized."; 190 break; 191 192 case CONSIDERING_JOIN_ORDER: 193 traceString = buildJoinOrder("\n\nConsidering join order: ", false, intParam1, 194 proposedJoinOrder); 195 break; 196 197 case TOTAL_COST_NON_SA_PLAN: 198 traceString = 199 "Total cost of non-sort-avoidance plan is " + 200 currentCost; 201 break; 202 203 case TOTAL_COST_SA_PLAN: 204 traceString = 205 "Total cost of sort avoidance plan is " + 206 currentSortAvoidanceCost; 207 break; 208 209 case TOTAL_COST_WITH_SORTING: 210 traceString = 211 "Total cost of non-sort-avoidance plan with sort cost added is " + currentCost; 212 break; 213 214 case CURRENT_PLAN_IS_SA_PLAN: 215 traceString = 216 "Current plan is a sort avoidance plan." + 217 "\n\tBest cost is : " + bestCost + 218 "\n\tThis cost is : " + currentSortAvoidanceCost; 219 break; 220 221 case CHEAPEST_PLAN_SO_FAR: 222 traceString = 223 "This is the cheapest plan so far."; 224 break; 225 226 case PLAN_TYPE: 227 traceString = 228 "Plan is a " + 229 (intParam1 == Optimizer.NORMAL_PLAN ? 230 "normal" : "sort avoidance") + 231 " plan."; 232 break; 233 234 case COST_OF_CHEAPEST_PLAN_SO_FAR: 235 traceString = 236 "Cost of cheapest plan is " + currentCost; 237 break; 238 239 case SORT_NEEDED_FOR_ORDERING: 240 traceString = 241 "Sort needed for ordering: " + 242 (intParam1 != Optimizer.SORT_AVOIDANCE_PLAN) + 243 "\n\tRow ordering: " + 244 requiredRowOrdering; 245 break; 246 247 case REMEMBERING_BEST_JOIN_ORDER: 248 traceString = buildJoinOrder("\n\nRemembering join order as best: ", false, intParam1, 249 bestJoinOrder); 250 break; 251 252 case SKIPPING_DUE_TO_EXCESS_MEMORY: 253 traceString = 254 "Skipping access path due to excess memory usage, maximum is " + 255 maxMemoryPerTable; 256 break; 257 258 case COST_OF_N_SCANS: 259 traceString = 260 "Cost of " + doubleParam + 261 " scans is: " + 262 objectParam1 + 263 " for table " + 264 intParam1; 265 break; 266 267 case HJ_SKIP_NOT_MATERIALIZABLE: 268 traceString = "Skipping HASH JOIN because optimizable is not materializable"; 269 break; 270 271 case HJ_SKIP_NO_JOIN_COLUMNS: 272 traceString = "Skipping HASH JOIN because there are no hash key columns"; 273 break; 274 275 case HJ_HASH_KEY_COLUMNS: 276 int[] hashKeyColumns = (int []) objectParam1; 277 traceString = "# hash key columns = " + hashKeyColumns.length; 278 for (int index = 0; index < hashKeyColumns.length; index++) 279 { 280 traceString = 281 "\n" + traceString + "hashKeyColumns[" + index + 282 "] = " + hashKeyColumns[index]; 283 } 284 break; 285 286 case CALLING_ON_JOIN_NODE: 287 traceString = "Calling optimizeIt() for join node"; 288 break; 289 290 case CONSIDERING_JOIN_STRATEGY: 291 JoinStrategy js = (JoinStrategy) objectParam1; 292 traceString = 293 "\nConsidering join strategy " + 294 js + " for table " + intParam1; 295 break; 296 297 case REMEMBERING_BEST_ACCESS_PATH: 298 traceString = 299 "Remembering access path " + 300 objectParam1 + 301 " as truly the best for table " + 302 intParam1 + 303 " for plan type " + 304 (intParam2 == Optimizer.NORMAL_PLAN ? 305 " normal " : "sort avoidance") + 306 "\n"; 307 break; 308 309 case NO_MORE_CONGLOMERATES: 310 traceString = 311 "No more conglomerates to consider for table " + 312 intParam1; 313 break; 314 315 case CONSIDERING_CONGLOMERATE: 316 cd = (ConglomerateDescriptor) objectParam1; 317 cdString = dumpConglomerateDescriptor(cd); 318 traceString = 319 "\nConsidering conglomerate " + 320 cdString + 321 " for table " + 322 intParam1; 323 break; 324 325 case SCANNING_HEAP_FULL_MATCH_ON_UNIQUE_KEY: 326 traceString = "Scanning heap, but we have a full match on a unique key."; 327 break; 328 329 case ADDING_UNORDERED_OPTIMIZABLE: 330 traceString = "Adding unordered optimizable, # of predicates = " + intParam1; 331 break; 332 333 case CHANGING_ACCESS_PATH_FOR_TABLE: 334 traceString = "Changing access path for table " + intParam1; 335 break; 336 337 case TABLE_LOCK_NO_START_STOP: 338 traceString = "Lock mode set to MODE_TABLE because no start or stop position"; 339 break; 340 341 case NON_COVERING_INDEX_COST: 342 traceString = 343 "Index does not cover query - cost including base row fetch is: " + 344 doubleParam + 345 " for table " + intParam1; 346 break; 347 348 case ROW_LOCK_ALL_CONSTANT_START_STOP: 349 traceString = 350 "Lock mode set to MODE_RECORD because all start and stop positions are constant"; 351 break; 352 353 case ESTIMATING_COST_OF_CONGLOMERATE: 354 cd = (ConglomerateDescriptor) objectParam1; 355 cdString = dumpConglomerateDescriptor(cd); 356 traceString = 357 "Estimating cost of conglomerate: " + 358 costForTable(cdString, intParam1); 359 break; 360 361 case LOOKING_FOR_SPECIFIED_INDEX: 362 traceString = 363 "Looking for user-specified index: " + 364 objectParam1 + " for table " + 365 intParam1; 366 break; 367 368 case MATCH_SINGLE_ROW_COST: 369 traceString = 370 "Guaranteed to match a single row - cost is: " + 371 doubleParam + " for table " + intParam1; 372 break; 373 374 case COST_INCLUDING_EXTRA_1ST_COL_SELECTIVITY: 375 traceString = costIncluding( 376 "1st column", objectParam1, intParam1); 377 traceString = 378 "Cost including extra first column selectivity is : " + 379 objectParam1 + " for table " + intParam1; 380 break; 381 382 case CALLING_NEXT_ACCESS_PATH: 383 traceString = 384 "Calling nextAccessPath() for base table " + 385 objectParam1 + " with " + intParam1 + " predicates."; 386 break; 387 388 case TABLE_LOCK_OVER_THRESHOLD: 389 traceString = lockModeThreshold("MODE_TABLE", "greater", 390 doubleParam, intParam1); 391 break; 392 393 case ROW_LOCK_UNDER_THRESHOLD: 394 traceString = lockModeThreshold("MODE_RECORD", "less", 395 doubleParam, intParam1); 396 break; 397 398 case COST_INCLUDING_EXTRA_START_STOP: 399 traceString = costIncluding( 400 "start/stop", objectParam1, intParam1); 401 break; 402 403 case COST_INCLUDING_EXTRA_QUALIFIER_SELECTIVITY: 404 traceString = costIncluding( 405 "qualifier", objectParam1, intParam1); 406 break; 407 408 case COST_INCLUDING_EXTRA_NONQUALIFIER_SELECTIVITY: 409 traceString = costIncluding( 410 "non-qualifier", objectParam1, intParam1); 411 break; 412 413 case COST_INCLUDING_COMPOSITE_SEL_FROM_STATS: 414 traceString = costIncluding("selectivity from statistics", 415 objectParam1, intParam1); 416 break; 417 418 case COST_INCLUDING_STATS_FOR_INDEX: 419 traceString = costIncluding("statistics for index being considered", 420 objectParam1, intParam1); 421 break; 422 case COMPOSITE_SEL_FROM_STATS: 423 traceString = "Selectivity from statistics found. It is " + 424 doubleParam; 425 break; 426 427 case COST_OF_NONCOVERING_INDEX: 428 traceString = 429 "Index does not cover query: cost including row fetch is: " + 430 costForTable(objectParam1, intParam1); 431 break; 432 433 case REMEMBERING_JOIN_STRATEGY: 434 traceString = 435 "\nRemembering join strategy " + objectParam1 + 436 " as best for table " + intParam1; 437 break; 438 439 case REMEMBERING_BEST_ACCESS_PATH_SUBSTRING: 440 traceString = 441 "in best access path"; 442 break; 443 444 case REMEMBERING_BEST_SORT_AVOIDANCE_ACCESS_PATH_SUBSTRING: 445 traceString = 446 "in best sort avoidance access path"; 447 break; 448 449 case REMEMBERING_BEST_UNKNOWN_ACCESS_PATH_SUBSTRING: 450 traceString = 451 "in best unknown access path"; 452 break; 453 454 case COST_OF_CONGLOMERATE_SCAN1: 455 cd = (ConglomerateDescriptor) objectParam1; 456 cdString = dumpConglomerateDescriptor(cd); 457 traceString = 458 "Cost of conglomerate " + 459 cdString + 460 " scan for table number " + 461 intParam1 + " is : "; 462 break; 463 464 case COST_OF_CONGLOMERATE_SCAN2: 465 traceString = 466 objectParam1.toString(); 467 break; 468 469 case COST_OF_CONGLOMERATE_SCAN3: 470 traceString = 471 "\tNumber of extra first column predicates is : " + 472 intParam1 + 473 ", extra first column selectivity is : " + 474 doubleParam; 475 break; 476 477 case COST_OF_CONGLOMERATE_SCAN4: 478 traceString = 479 "\tNumber of extra start/stop predicates is : " + 480 intParam1 + 481 ", extra start/stop selectivity is : " + 482 doubleParam; 483 break; 484 485 case COST_OF_CONGLOMERATE_SCAN5: 486 traceString = 487 "\tNumber of extra qualifiers is : " + 488 intParam1 + 489 ", extra qualifier selectivity is : " + 490 doubleParam; 491 break; 492 493 case COST_OF_CONGLOMERATE_SCAN6: 494 traceString = 495 "\tNumber of extra non-qualifiers is : " + 496 intParam1 + 497 ", extra non-qualifier selectivity is : " + 498 doubleParam; 499 break; 500 501 case COST_OF_CONGLOMERATE_SCAN7: 502 traceString = 503 "\tNumber of start/stop statistics predicates is : " + 504 intParam1 + 505 ", statistics start/stop selectivity is : " + 506 doubleParam; 507 break; 508 } 509 if (SanityManager.DEBUG) 510 { 511 if (traceString == null) 512 { 513 SanityManager.THROWASSERT( 514 "traceString expected to be non-null"); 515 } 516 } 517 lcc.appendOptimizerTraceOutput(traceString + "\n"); 518 } 519 520 private String costForTable(Object cost, int tableNumber) 521 { 522 return cost + " for table " + tableNumber; 523 } 524 525 private String bestCost() 526 { 527 return "Best cost = " + bestCost + "\n"; 528 } 529 530 private String buildJoinOrder(String prefix, boolean addJoinOrderNumber, 531 int joinOrderNumber, int[] joinOrder) 532 { 533 String joinOrderString = prefix; 534 535 for (int i = 0; i <= joinPosition; i++) 536 { 537 joinOrderString = joinOrderString + " " + joinOrder[i]; 538 } 539 if (addJoinOrderNumber) 540 { 541 joinOrderString = joinOrderString + " " + joinOrderNumber; 542 } 543 544 return joinOrderString + " with assignedTableMap = " + assignedTableMap + "\n\n"; 545 } 546 547 private String lockModeThreshold( 548 String lockMode, String relop, 549 double rowCount, int threshold) 550 { 551 return 552 "Lock mode set to " + lockMode + 553 " because estimated row count of " + rowCount + 554 " " + relop + " than threshold of " + threshold; 555 } 556 557 private String costIncluding( 558 String selectivityType, Object objectParam1, int intParam1) 559 { 560 return 561 "Cost including extra " + selectivityType + 562 " start/stop selectivity is : " + 563 costForTable(objectParam1, intParam1); 564 } 565 566 private String dumpConglomerateDescriptor(ConglomerateDescriptor cd) 567 { 568 if (SanityManager.DEBUG) 569 { 570 return cd.toString(); 571 } 572 573 String keyString = ""; 574 String [] columnNames = cd.getColumnNames(); 575 576 if (cd.isIndex() && columnNames != null ) 577 { 578 IndexRowGenerator irg = cd.getIndexDescriptor(); 579 580 int[] keyColumns = irg.baseColumnPositions(); 581 582 keyString = ", key columns = {" + columnNames[keyColumns[0] - 1]; 583 for (int index = 1; index < keyColumns.length; index++) 584 { 585 keyString = keyString + ", " + columnNames[keyColumns[index] - 1]; 586 } 587 keyString = keyString + "}"; 588 } 589 590 return "CD: conglomerateNumber = " + cd.getConglomerateNumber() + 591 " name = " + cd.getConglomerateName() + 592 " uuid = " + cd.getUUID() + 593 " indexable = " + cd.isIndex() + 594 keyString; 595 } 596 } 597 | Popular Tags |