Можно ли выполнить этот SQL-запрос coldfusion9 быстрее? - PullRequest
0 голосов
/ 11 октября 2011

Ситуация:
У меня есть база данных 6000 студентов на реальном сайте, а на тестовом сайте есть база данных 400 студентов. Поиск студентов с использованием функции поиска (ниже) работает нормально на тестовом сайте, но на реальном сайте функция поиска занимает 1-2 полных минуты для возврата ( Даже необходимо увеличить время ожидания сценария, выполнив RequestTimeout = 180 ). Оба сайта используют одну и ту же функцию поиска (ниже).

Вопрос:
Мой вопрос: есть ли у кого-нибудь из вас советы о том, как ускорить этот поиск? Это так медленно.

Функция поиска:

<cffunction name="getStudentsByKeyword" access="public" output="no" returntype="struct">
    <cfargument name="keyword" type="string" required="yes">
    <cfargument name="pageNum" type="numeric" default="1">
    <cfargument name="startIndex" type="numeric" default="1">
    <cfargument name="numItemsPerPage" type="numeric" default="20">

    <cfset var resultStruct = StructNew()>
    <cfset resultStruct.numAllItems=0>
    <cfset resultStruct.numDisplayedItems=0>
    <cfset resultStruct.courses=QueryNew("studentID")>  

    <cfif Arguments.pageNum GT 1>
      <cfset Arguments.startIndex=(Arguments.pageNum - 1) * Arguments.numItemsPerPage + 1>
    </cfif>

    <cfquery name="qNumStudents" datasource="#this.datasource#">
      SELECT DISTINCT COUNT(cl_student.studentID) AS numItems
      FROM   cl_student LEFT JOIN cl_ordersummary ON cl_student.studentID=cl_ordersummary.studentID
      WHERE  cl_student.email LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%"> OR
             cl_ordersummary.contactFirstName LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%"> OR
             cl_ordersummary.contactLastName LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%">
    </cfquery>
    <cfset resultStruct.numAllItems = qNumStudents.numItems>

    <cfquery name="qStudents" datasource="#this.datasource#">
      SELECT DISTINCT cl_student.studentID, cl_student.email, cl_student.password, cl_student.studentType,
             cl_ordersummary.contactFirstName, cl_ordersummary.contactLastName
      FROM   cl_student LEFT JOIN cl_ordersummary ON cl_student.studentID=cl_ordersummary.studentID
      WHERE  cl_student.email LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%"> OR
             cl_ordersummary.contactFirstName LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%"> OR
             cl_ordersummary.contactLastName LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%">
      ORDER  BY cl_student.email, cl_ordersummary.contactFirstName, cl_ordersummary.contactLastName
      LIMIT  #Arguments.startIndex-1#, #Arguments.numItemsPerPage#
    </cfquery>

    <cfset resultStruct.numDisplayedItems=qStudents.recordcount>    
    <cfset resultStruct.students = qStudents>

    <cfreturn resultStruct>   
  </cffunction>

Описание таблиц:
( Простые представления каждой таблицы, используемой в поиске )

Table cl_student
================
studentID, email, password, studentType, sendReminderEmail, firstName, middleName, lastName, address, city, state, zip, daytimePhone, dateCreated, dateLastModified
----------------
studentID   INT UNSIGNED(10) (PRIMARY) (AI)
email   VARCHAR(100)
password    VARCHAR(20)
studentType ENUM('A','B','C','D','F')
sendRemiderEmail    TINYINT(4)
firstName   VARCHAR(30)
middleName  VARCHAR(30)
lastName    VARCHAR(30)
address VARCHAR(100)
city    VARCHAR(30)
state   VARCHAR(30)
zip VARCHAR(10)
daytimePhone    VARCHAR(20)
dateCreated DATETIME
dateLastModified    DATETIME


Table cl_ordersummary
=====================
orderID, studentID, orderDate, status, donationAmount, total, contactFirstName, contactLastName, contactAddress1, contactAddress2, contactCity, contactState, contactZIP, daytimePhone, cellPhone, billingFirstName, billingLastName, billingAddress1, billingAddress2, billingCity, billingState, billingZIP, payWithCash, authCode, remark, dateLastModified
---------------------
orderID VARCHAR(20) (PRIMARY)
studentID   INT(11)
orderDate   DATETIME
status  CHAR(1)
donationAmount  FLOAT
total   FLOAT
contactFirstName    VARCHAR(50)
contactLastName VARCHAR(50)
contactAddress1 VARCHAR(100)
contactAddress2 VARCHAR(100)
contactCity VARCHAR(50)
contactState    VARCHAR(50)
contactZIP  VARCHAR(10)
daytimePhone    VARCHAR(30)
cellPhone   VARCHAR(30)
billingFirstName    VARCHAR(50)
billingLastName VARCHAR(50)
billingAddress1 VARCHAR(100)
billingAddress2 VARCHAR(100)
billingCity VARCHAR(50)
billingState    VARCHAR(50)
billingZIP  VARCHAR(10)
payWithCash TINYINT(4)
authCode    VARCHAR(20)
remark  TEXT
dateLastModified    DATETIME

Ответы [ 4 ]

2 голосов
/ 11 октября 2011

Ожидается ли и что вы хотите иметь несколько имен контактов в наборе записей для каждого учащегося? Такая настройка, в которой у вас есть имена контактов в таблице заказов, а не в таблице учеников, создает необходимость в запросе, который не является оптимальным. Я понимаю, что для этого может быть, конечно, веская причина, но стоит проверить. Итак, вы хотите / ожидаете этого?

studentId|email|password|studentType|contactFirstName|contactLastName
999       b@b.b|p455w0rd|slacker    |billy           |bob
999       b@b.b|p455w0rd|slacker    |bill            |bob
...

Если это так, не уверен, как второй запрос может быть быстрее. Тем не менее, первый запрос может выиграть от перехода на следующий, который всегда будет возвращать только одну строку и не требует left join или select distinct:

SELECT    count(s.*) as nAllResults
FROM      cl_student s
WHERE     s.email LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%"> 
OR EXISTS (
         SELECT 1 
         FROM   cl_ordersummary o
         WHERE  o.studentId = s.studentId
         AND  ( o.contactFirstName LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%"> 
         OR     o.contactLastName LIKE <cfqueryparam cfsqltype="cf_sql_char" value="%#Arguments.keyword#%"> )
)             

Еще одна вещь, которую нужно посмотреть, это индексы. Индексы не будут использоваться в ваших предложениях LIKE, но будут в ваших предложениях JOINS и ORDER BY. Убедитесь, что у вас есть соответствующие индексы в таблицах и что определены ваши ключи Pimary и Foreign.

1 голос
/ 11 октября 2011
  1. Попробуйте CREATE INDEX cl_ordersummary_studentID ON cl_ordersummary (studentID)

  2. Могут помочь и другие индексы, но вам придется использовать поиск префиксов для этой оптимизации, базы данных SQL обычнопреобразовать поиск префикса в индекс сканирования диапазона.Например, вы можете индексировать электронную почту и использовать префикс в качестве параметра:

  1. Полнотекстовый индекс поиска - лучший вариант для оптимизации, см. Документы для ваших возможностей РСУБДБольшинство баз данных поддерживают полнотекстовый поиск через специальные функции или синтаксис.Вы найдете другие полезные функции в полнотекстовом поиске, например, для сортировки по наилучшему соответствию.Вам не понадобится вариант 2, если вы измените свои запросы для использования полнотекстового поиска.

MySQL http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html (Все основные базы данных имеют схожие возможности поиска)

1 голос
/ 11 октября 2011

Coldfusion не выполняет ваш запрос. Он передается на сервер базы данных для выполнения, а набор результатов передается обратно.

Вы можете взять свой запрос и использовать анализатор запросов, чтобы сгенерировать план выполнения, чтобы увидеть, где ваш запрос занимает больше всего времени. Скорее всего, вам нужно добавить некоторые индексы для столбцов, используемых в ваших критериях WHERE. Я считаю, что в MySQL вы можете использовать EXPLAIN, чтобы показать, где отсутствуют индексы http://dev.mysql.com/doc/refman/5.5/en/using-explain.html

1 голос
/ 11 октября 2011

Может ли этот поисковый запрос SQL Coldfusion9 быть выполнен быстрее?

Да.Вы хотите настроить индексы для затронутых столбцов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...